答案 0 :(得分:7)
这个例子巧妙地将多个Ruby概念联系在一起。因此,我将尝试解释所有这些。
Ruby中的方法可以在优雅的事物中接受块(代码片段):
def run_code
yield
end
run_code { puts 42 } # => prints 42
deep_thought = proc { puts 42 }
deep_thought.call # => prints 42
&
运算符调用方法时,可以将proc转换为块:def run_code
yield
end
deep_thought = proc { puts 42 }
run_code(&deep_thought) # => prints 42
def reveal_answer
yield 5_000
end
deep_thought = proc do |years_elapsed|
years_elapsed >= 7_500_000 ? 42 : 'Still processing'
end
reveal_answer(&deep_thought) # => 'Still processing'
&
将块转换为proc:def inspector(&block)
puts block.is_a?(Proc)
puts block.call
end
inspector { puts 42 } # => prints true and 42
inspector(&proc { puts 42 }) # => the same
Symbol#to_proc
创建一个proc,它调用对象上具有相同名称的方法:class Dummy
def talk
'wooooot'
end
end
:talk.to_proc.call(Dummy.new) # => "wooooot"
换句话说,
:bar.to_proc.call(foo)
几乎相当于
foo.bar
BasicObject#method_missing
:当您尝试在对象上调用方法时,Ruby会遍历它的祖先链,搜索具有该名称的方法。如何构建链是一个不同的主题,对于另一天来说足够长,重要的是如果找不到方法直到最底部(BasicObject
),则在同一链上执行第二次搜索 - 这一个名为method_missing
的方法的时间。它作为参数传递原始方法的名称加上它收到的任何参数:
class MindlessParrot
def method_missing(method_name, *args)
"You caldt #{method_name} with #{args} on me, argh!"
end
end
MindlessParrot.new.foo # => "You caldt foo with [] on me, argh!"
MindlessParrot.new.bar :baz, 42 # => "You caldt bar with [:baz, 42] on me, argh!"
那么在我们的具体案例中,这一切意味着什么呢?让我们假设一秒钟没有protected
。
translator.speak(&:spanish)
调用方法Translator#speak
并将:spanish
转换为块。
Translator#speak
接受该块并将其转换为名为language
的proc,并调用它,并将self
作为参数传递。
self
是Translator
的一个实例,因此,它包含方法speak
,french
,spanish
,turkey
和method_missing
。
所以:
Translator.new.speak(&:spanish)
相当于:
:spanish.to_proc.call(Translator.new)
相当于:
Translator.new.spanish
给我们"hola"
。
现在,取回protected
,我们的translator
对象的所有语言方法仍然存在,但外人无法直接访问它们。
就像你不能打电话一样
Translator.new.spanish
并期待"hola"
回来,你不能打电话
Translator.new.speak(&:spanish)
由于该方法无法直接访问,因此系统会将其视为未找到并调用method_missing
,从而为我们提供"awkward silence"
。