私はこれらの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 は文書化できず、使いにくいと思うので、それはまさに私が避けようとしているものです。