假设我有一个带有访问对象的方法的对象:
def foo
@foo
end
我知道我可以使用 send 来访问该方法:
obj.send("foo") # Returns @foo
是否有一种简单的方法可以进行递归发送以获取 @foo 对象上的参数,例如:
obj.send("foo.bar") # Returns @foo.bar
假设我有一个带有访问对象的方法的对象:
def foo
@foo
end
我知道我可以使用 send 来访问该方法:
obj.send("foo") # Returns @foo
是否有一种简单的方法可以进行递归发送以获取 @foo 对象上的参数,例如:
obj.send("foo.bar") # Returns @foo.bar
虽然 OP 已经接受了使用 的答案instance_eval(string)
,但我强烈敦促 OP 避免使用字符串形式,eval
除非绝对必要。Eval 调用 ruby 编译器——计算成本高,使用起来很危险,因为它打开了代码注入攻击的向量。
如前所述,根本不需要发送:
obj.foo.bar
如果确实 foo 和 bar 的名称来自一些非静态计算,那么
obj.send(foo_method).send(bar_method)
很简单,所有人都需要这个。
如果方法以点分字符串的形式出现,则可以使用 split 和 injection 链接方法:
'foo.bar'.split('.').inject(obj, :send)
澄清回应评论:从安全角度来看,字符串评估是最危险的事情之一。如果有任何方式从用户提供的输入构造字符串,而无需对该输入进行非常勤奋的检查和验证,那么您应该只考虑您的系统拥有。
从用户输入获取方法的 send(method) 也有风险,但攻击向量更有限。您的用户输入可能会导致您执行任何可通过接收器调度的 0 参数方法。这里的良好做法是在调度之前始终将方法列入白名单:
VALID_USER_METHODS = %w{foo bar baz}
def safe_send(method)
raise ArgumentError, "#{method} not allowed" unless VALID_USER_METHODS.include?(method.to_s)
send(method)
end
聚会有点晚了,但我不得不做一些类似的事情,必须在一次调用中结合“发送”和访问来自哈希/数组的数据。基本上,这允许您执行以下操作
value = obj.send_nested("data.foo['bar'].id")
在引擎盖下,这将做类似的事情
obj.send(data).send(foo)['bar'].send(id)
这也适用于属性字符串中的符号
value = obj.send_nested('data.foo[:bar][0].id')
这将做类似的事情
obj.send(data).send(foo)[:bar][0].send(id)
如果您想使用无关访问,您也可以将其添加为参数。例如
value = obj.send_nested('data.foo[:bar][0].id', with_indifferent_access: true)
由于涉及更多,这里是指向 gist 的链接,您可以使用该链接将该方法添加到基本 Ruby 对象。(它还包括测试,以便您了解它是如何工作的)