class Person
def method_missing(sym, *args)
"#{sym} not defined on #{self}"
end
def name
"My name is Person"
end
end
p = Person.new
puts p.name # => My name is Person
puts p.address # => address not defined on #<Person:0x007fb2bb022fe0>
method_missing 接收两个参数:被调用的方法名和传递给该方法的参数。 首先Ruby会寻找我们试图调用的方法,如果方法没找到则会寻找 method_missing 方法。 现在我们重载了 Person 中的 method_missing,因此Ruby将会调用它而不是抛出异常。
让我们来看看 Rake 是如何使用 method_missing 的。
Rake中的 method_missing
Rake 是Ruby中使用最广泛的gem包之一。Rake 使用 method_missing 来提供访问传递给Rake任务的参数。 首先创建一个简单的rake任务:
task :hello do
puts "Hello"
end
如果你通过调用 rake hello 来执行这个任务,你会看到输出 Hello。 让我们扩展这个rake任务,以便接收一个参数(一个人名)并向他打招呼:
task :hello, :name do |t, args|
puts "Hello #{args.name}"
end
t 是任务名,args 保存了传递过来的参数。正如你所见,我们调用 args.name 来获取传递给 hello 任务的 name 参数。 运行该任务,并传递一个参数:
rake hello["Imran Latif"]
=> Hello Imran Latif
让我们来看看 Rake 是如何使用 method_missing 为我们提供了传递给任务的参数的。
在上面任务中的 args 对象是一个 Rake::TaskArguments 实例,它是在这里所定义。 这个类负责管理传递给Rake任务的参数。查看 Rake::TaskArguments 的代码,你会发现并没有定义相关的方法将参数传给任务。 那么 Rake 是如何将参数提供给任务的呢?答案是 Rake 是使用了 method_missing 巧妙地实现了这个功能。 看看第64行 method_missing 的定义:
def method_missing(sym, *args)
lookup(sym.to_sym)
end
在这个类中定义 method_missing 是为了保证能够访问到那些未定义的方法,而不是由Ruby抛出异常。 在 method_missing 中它调用了 lookup 方法:
def lookup(name)
if @hash.has_key?(name)
@hash[name]
elsif @parent
@parent.lookup(name)
end
end
method_missing 调用 lookup,并将方法名以 Symbol(符号) 的形式传递给它。 lookup 方法将会在 @hash 中进行查找,它是在 Rake::TaskArguments 的构造函数中创建的。 如果 @hash 中包含该参数则返回,如果在 @hash 中没有则 Rake 会尝试调用 @parent 的 lookup。 如果该参数没有找到,则什么都不返回。










