【发布时间】:2009-09-28 01:49:56
【问题描述】:
假设我有一个 XML::Element...我想做类似的事情:
my_xml_element.send("parent.next_sibling.next_sibling")
【问题讨论】:
标签: ruby metaprogramming
假设我有一个 XML::Element...我想做类似的事情:
my_xml_element.send("parent.next_sibling.next_sibling")
【问题讨论】:
标签: ruby metaprogramming
在你的情况下,最好使用instance_eval
"Test".instance_eval{chop!.chop!} #=> "Te"
对于您的代码:
my_xml_element.instance_eval{parent.next_sibling.next_sibling}
【讨论】:
实际上,Khelll 几乎是对的。 使用这个:
methods_chain = "parent.next_sibling.next_sibling"
result = my_xml_element.instance_eval( eval methods_chain )
此代码比使用 split() 快 20 倍,并允许您通过 args 传递链式方法,如下所示:
methods = "power!(2).div(57).+(12).to_f"
42.instance_eval { eval methods }
【讨论】:
呃,如果我正确理解他的问题,那并不是他真正想要的。我的意思是 send 将字符串或符号作为参数,而您的解决方案没有。我认为没有内置方法可以满足您的需求,但我通过测试创建了一种方法。
require 'test/unit'
class Example
def multi_send(str)
str.split('.').inject(self){|klass, method| klass.send(method) }
end
end
class MyTest < Test::Unit::TestCase
def test_multi_send
a = Example.new
methods = "class.to_s.downcase.chop!"
assert a.multi_send(methods) == 'exampl'
end
end
【讨论】:
我认为问题是您专门将一系列方法定义为字符串,并且您想在某个对象上调用它,对吗?
class Object
def call_method_chain(method_chain)
return self if method_chain.empty?
method_chain.split('.').inject(self){|o,m| o.send(m.intern)}
end
end
>> User.first.profile.address.state.name
=> "Virginia"
>> User.first.call_method_chain("profile.address.state.name")
=> "Virginia"
【讨论】:
Alfuken基于eval的答案的问题是
A) eval 虽然速度很快,但相当不安全
B) 如果你有一个额外的(连续的)点用于这样的方法调用
"example".instance_eval{eval "chop!..chop!"}.class
=> "examp".."examp"
"example".instance_eval {eval "chop!..chop!"}.class
=> Range # this is not what is desired
【讨论】:
instance_val 和 { 括号之间的额外空格?我很困惑。