Lyn*_*ynn 14 ruby metaprogramming
假设我有一个访问对象的方法的对象:
def foo
@foo
end
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用send访问该方法:
obj.send("foo") # Returns @foo
Run Code Online (Sandbox Code Playgroud)
是否有一种直接的方法来执行递归发送以获取@foo对象的参数,例如:
obj.send("foo.bar") # Returns @foo.bar
Run Code Online (Sandbox Code Playgroud)
Mic*_*ant 19
你可以使用instance_eval
:
obj.instance_eval("foo.bar")
Run Code Online (Sandbox Code Playgroud)
您甚至可以直接访问实例变量:
obj.instance_eval("@foo.bar")
Run Code Online (Sandbox Code Playgroud)
dbe*_*hur 15
虽然OP已经接受了答案instance_eval(string)
,但我强烈建议OP避免使用字符串形式,eval
除非绝对必要.Eval调用ruby编译器 - 计算成本高,使用起来很危险,因为它打开了代码注入攻击的向量.
如上所述,根本不需要发送:
obj.foo.bar
Run Code Online (Sandbox Code Playgroud)
如果确实foo和bar的名字来自某些非静态计算,那么
obj.send(foo_method).send(bar_method)
Run Code Online (Sandbox Code Playgroud)
很简单,所有人都需要这个.
如果方法以点线形式出现,可以使用split和inject来链接方法:
'foo.bar'.split('.').inject(obj, :send)
Run Code Online (Sandbox Code Playgroud)
澄清以回应评论:从安全角度来看,字符串评估是最危险的事情之一.如果有任何方式字符串是由用户提供的输入构造的,而没有令人难以置信的仔细检查和验证该输入,您应该只考虑您的系统所有.
发送(方法)从用户输入获得方法也有风险,但有一个更有限的攻击向量.您的用户输入可能会导致您执行通过接收器可分派的任何0-arghument方法.这里的好习惯是在调度之前始终将方法列入白名单:
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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2822 次 |
最近记录: |