【发布时间】:2013-09-29 13:41:01
【问题描述】:
我有很多这样的方法:
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]
但我找不到将任意数量的命名(非 splat)参数传递给 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 无法记录并且使用起来不方便。
【问题讨论】:
-
您是否研究过另一种名为
method_missing的魔术方法? :) -
@ArupRakshit 我猜 method_missing 基本相同,因为它不提供动态操作命名参数的可能性。
-
这看起来像是一个糟糕的 hack,因为您基本上是通过依赖特定的参数名称传递给 API 来使用参数列表作为 Hahes。只需对
create_machine和register_machine的参数使用普通哈希。然后使用元编程创建您的通用方法将很容易。 -
@Max 我不确定我明白你的意思。一个例子真的很有帮助。
标签: ruby