I have many methods like these two:
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
They have the same implementation but different number of different arguments. There will be tens of such methods in each of tens of classes. So I thought I'd use some meta-programming to minimize the code repetition.
I was trying to do this via define_method and wanted to end up in something like this:
vb_method :create_machine, :args => [:name, :os_type_id], :optional_args => [:settings_file, :groups, :flags]
But I can't find a way to pass arbitrary number of named (non-splat) arguments to define_method (I thought splat argument will make documenting the methods hard to impossible also will make the resulting API inconvenient).
What would be the best way to deal with this (using Ruby 2.0)?
UPD Another way to do this is defining a method 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
And then the class would have a call like this:
vb_method :create_machine, :register_machine
But is this case I will need to always call the methods with hash as an argument:
machine = vb.create_machine(name: 'my_vm', os_type_id: 'Windows95')
And that's exactly what I'm trying to avoid because I think in this case the resulting API can't be documented and is not convenient to use.
method_missing? :)create_machineandregister_machine. Then it will be easy to create your generic method using metaprogramming.