在 Ruby 中通过符号名称调用私有方法
Calling private methods by symbol name in Ruby
我有一个方法的符号名称,我想用一些参数调用它。我真正想做的事情归结为这个代码片段:
method.to_proc.call(method)
在这种情况下,method
是对象上方法的符号名称。在我的例子中,我试图调用一个恰好在对象上是私有的方法。
这是我得到的错误输出:
>$ ruby symbol_methods.rb
symbol_methods.rb:33:in `call': private method `test_value_1' called for "value":String (NoMethodError)
from symbol_methods.rb:33:in `block (2 levels) in <main>'
from symbol_methods.rb:30:in `each'
from symbol_methods.rb:30:in `block in <main>'
from symbol_methods.rb:29:in `each'
from symbol_methods.rb:29:in `<main>'
这是一个演示此行为的独立示例:
data = [
["value", true],
["any value here", true],
["Value", true],
]
def matches_value(string)
string == "value"
end
def contains_value(string)
string.gsub(/.*?value.*?/, "\1")
end
def matches_value_ignore_case(string)
string.downcase == "value"
end
#tests
[:matches_value, :contains_value, :matches_value_ignore_case].each_with_index do |method, index|
test = data[index]
value = test[0]
expected_result = test[1]
result = method.to_proc.call(value) # <<== HERE
puts "#{method}: #{result == expected_result ? 'Pass' : 'Fail'}: '#{value}'"
end
重要的位在标记为 #tests
的块中。 data
变量是一组输入和预期结果。 test_value_*
方法是私有方法,是对 运行.
的测试
我试过 public_send(method, value)
和 method.to_proc.call(value)
,但两者都会导致 private method
错误。
在这种情况下调用名为符号的私有方法的正确方法是什么?我正在寻找解释和语法正确的答案。
改用send
。
puts "#{method}: #{send(method, value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'"
经过大量搜索,我找到了一个替代答案,而不是 Object#send
, that has an unanticipated feature benefit. The solution is to use the Object#method
to return a Method
符号名称的对象。
一个Method
对象是一个Proc
-like callable object, so it implements the #call
interface, which fits the bill nicely. Object
在其接口中定义了许多这样有用的助手。
在原始问题的上下文中,它是这样工作的:
#tests
[:test_value_1, :test_value_2, :test_value_3].each do |method|
data.each do |test|
value = test[0]
expected_result = test[1]
puts "#{method}: #{self.method(method).call(value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'"
end
end
重要的部分是:
self.method(method).call(value)
这会将符号名称转换为 Method
对象,然后使用 value
作为参数调用该方法。这在功能方面 与 大致等效 。但是,需要注意一些差异。
send
会更有效率,因为在转换为 Method
时没有开销。 Method#call
和 send
使用不同的内部调用机制,看起来 send
的调用开销也较小。
使用 Object#method
的 意想不到的功能 是 Method
对象很容易转换为 Proc
对象(使用 Method#to_proc
).因此,它可以作为 first-class 对象存储和传递。这意味着它可以代替块提供或作为回调提供,从而有助于实现灵活的调度解决方案。
我有一个方法的符号名称,我想用一些参数调用它。我真正想做的事情归结为这个代码片段:
method.to_proc.call(method)
在这种情况下,method
是对象上方法的符号名称。在我的例子中,我试图调用一个恰好在对象上是私有的方法。
这是我得到的错误输出:
>$ ruby symbol_methods.rb
symbol_methods.rb:33:in `call': private method `test_value_1' called for "value":String (NoMethodError)
from symbol_methods.rb:33:in `block (2 levels) in <main>'
from symbol_methods.rb:30:in `each'
from symbol_methods.rb:30:in `block in <main>'
from symbol_methods.rb:29:in `each'
from symbol_methods.rb:29:in `<main>'
这是一个演示此行为的独立示例:
data = [
["value", true],
["any value here", true],
["Value", true],
]
def matches_value(string)
string == "value"
end
def contains_value(string)
string.gsub(/.*?value.*?/, "\1")
end
def matches_value_ignore_case(string)
string.downcase == "value"
end
#tests
[:matches_value, :contains_value, :matches_value_ignore_case].each_with_index do |method, index|
test = data[index]
value = test[0]
expected_result = test[1]
result = method.to_proc.call(value) # <<== HERE
puts "#{method}: #{result == expected_result ? 'Pass' : 'Fail'}: '#{value}'"
end
重要的位在标记为 #tests
的块中。 data
变量是一组输入和预期结果。 test_value_*
方法是私有方法,是对 运行.
我试过 public_send(method, value)
和 method.to_proc.call(value)
,但两者都会导致 private method
错误。
在这种情况下调用名为符号的私有方法的正确方法是什么?我正在寻找解释和语法正确的答案。
改用send
。
puts "#{method}: #{send(method, value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'"
经过大量搜索,我找到了一个替代答案,而不是 Object#send
, that has an unanticipated feature benefit. The solution is to use the Object#method
to return a Method
符号名称的对象。
一个Method
对象是一个Proc
-like callable object, so it implements the #call
interface, which fits the bill nicely. Object
在其接口中定义了许多这样有用的助手。
在原始问题的上下文中,它是这样工作的:
#tests
[:test_value_1, :test_value_2, :test_value_3].each do |method|
data.each do |test|
value = test[0]
expected_result = test[1]
puts "#{method}: #{self.method(method).call(value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'"
end
end
重要的部分是:
self.method(method).call(value)
这会将符号名称转换为 Method
对象,然后使用 value
作为参数调用该方法。这在功能方面 与
send
会更有效率,因为在转换为 Method
时没有开销。 Method#call
和 send
使用不同的内部调用机制,看起来 send
的调用开销也较小。
使用 Object#method
的 意想不到的功能 是 Method
对象很容易转换为 Proc
对象(使用 Method#to_proc
).因此,它可以作为 first-class 对象存储和传递。这意味着它可以代替块提供或作为回调提供,从而有助于实现灵活的调度解决方案。