0

私はこれらの2つのような多くの方法を持っています:

def create_machine(name, os_type_id, settings_file='', groups=[], flags={})
  soap_method = "#{self.class.name.split('::').last.to_underscore}_#{__method__}".to_sym
  args = method(__method__).parameters.map { |arg| arg[1] }
  soap_message = Hash[args.map { |arg| [arg, eval(arg.to_s)] }]
  VirtualBoxAPI.send_request(@cl.conn, soap_method, @this.merge(soap_message))
end

def register_machine(machine)
  soap_method = "#{self.class.name.split('::').last.to_underscore}_#{__method__}".to_sym
  args = method(__method__).parameters.map { |arg| arg[1] }
  soap_message = Hash[args.map { |arg| [arg, eval(arg.to_s)] }]
  VirtualBoxAPI.send_request(@cl.conn, soap_method, @this.merge(soap_message))
end

実装は同じですが、引数の数が異なります。数十のクラスのそれぞれに、そのようなメソッドが数十あります。そこで、メタプログラミングを使用してコードの繰り返しを最小限に抑えることにしました。私はこれを介してこれをやろうとしていdefine_methodて、次のようなものになりたいと思っていました:

vb_method :create_machine, :args => [:name, :os_type_id], :optional_args => [:settings_file, :groups, :flags]

しかし、任意の数の名前付き (非スプラット) 引数を渡す方法を見つけることができませんdefine_method(splat 引数は、メソッドの文書化を困難または不可能にし、結果の API を不便にすると思いました)。

これに対処する最善の方法は何ですか (Ruby 2.0 を使用)?

UPD これを行う別の方法は、メソッド vb_method を定義することです。

def vb_method(*vb_meths)
  vb_meths.each do |meth|
    define_method(meth) do |message={}|
      soap_method = "#{self.class.name.split('::').last.to_underscore}_#{meth}".to_sym
      VirtualBoxAPI.send_request(@cl.conn, soap_method, @this.merge(message))
    end
  end
end

そして、クラスには次のような呼び出しがあります。

vb_method :create_machine, :register_machine

しかし、この場合、常に引数としてハッシュを使用してメソッドを呼び出す必要があります。

machine = vb.create_machine(name: 'my_vm', os_type_id: 'Windows95')

この場合、結果として得られる API は文書化できず、使いにくいと思うので、それはまさに私が避けようとしているものです。

4

1 に答える 1

3

オプション ハッシュを回避しようとするのをやめます。それが「Ruby 流」のやり方です。それらを文書化することは不可能ではなく、いくつかの主流の Ruby ライブラリがこの方法で使用しています (最初に思い浮かぶのは ActiveRecord と Mysql2 です)。

オプション ハッシュにデフォルトの引数を指定できることに注意してください。これはドキュメントとして機能し、コードの繰り返しを減らすことができます。

また、(何らかの方法で) 任意の数の名前付き引数を に渡すことができた場合、コードがどのように機能するかを考えてみてくださいdefine_method。ユーザーは、どの引数がどれであるかをどのように覚えているでしょうか? このように定義されたすべての異なるメソッドに対するすべての異なる位置引数の順序と意味を記憶する必要があります。さまざまな意味の引数を持つ類似のメソッドが多数ある場合、すべてを正確に保つことは非常に困難です。キーワード引数 (基本的に Ruby のオプション ハッシュと同じ) は、この状況を回避するために特別に作成されました。

エラー チェックが心配な場合は、オプション ハッシュの欠落/認識されないキーをチェックし、有益な例外を発生させるヘルパー メソッドを定義します。

def validate_options(known, opts)
  opts.each_key { |opt| raise "Unknown option: #{opt}" unless known.include?(opt) }
  known.each { |opt, required| raise "Missing required option: #{opt}" if required and not opts.include?(opt) }
end
于 2013-09-29T16:16:23.330 に答える