==回调方法和钩子方法
回调和钩子是相当常见的元编程技术。在Ruby程序运行过程中,当特定的事件发生时,将调用这些回调和钩子方法。特定事件是指:
* 调用一个不存的对象方法
* 类混含一个模块
* 定义类的子类
* 给类添加一个实例方法
* 给对象添加一个单例方法
* 引用一个不存在的常量
以上的每个事件,都可以编写一个回调方法,在该事件发生时,该回调方法被执行。这些回调方法是针对某个对象或某个类的,而不是全局的。
===method_missing
给对象调用一个方法,对象没有这个方法时,则会抛出NoMethodError异常,这时就可以使用method_missing来拦截。
class C
def method_missing(m)
puts "There's no method called #{m} here -- please try again."
end
end
C.new.anything
这里就会调用method_missing方法。
method_missing是一个有用的工具,在所有Ruby标准的钩子方法和回调方法中,它可能是使用最广泛的了。
===Module#included
当一个模块混入到类时,如果该模的included方法已经定义,那么该方法被调用。该方法的唯一参数就是接受混含的类的名字。
module M
def self.included(c)
puts "I have justbeen mixed into #{c}."
end
end
class C
include M
end
混含模块到类中使得在模块中的所有实例方法可以被作为类的实例的方法。如果在混含模块时,不仅要给类添加实例方法,还要添加类方法,该如何做呢?
用included可以捕获混含操作,并以此给混含模块的类添加类方法:
module M
def self.included(cl)
def cl.a_class_method
puts "Now the class has a new class method."
end
end
def an_inst_method
puts "This module supplines this instance method."
end
end
class C
include M
end
c = C.new
c.an_inst_method
C.a_class_method
输出结果:
This module supplines this instance method.
Now the class has a new class method.
其实这里很好理解,由于C做为included的唯一参数传入到cl,接着定义了cl.a_class_method就相当于是给类C定义了类方法。
===Class#inherited
如果为给定的类定义了inherited方法,那么在为它生成子类时,inherited会被调用,唯一的调用参数是新的子类的名字:
class C
def self.inherited(subclass)
puts "#{self} just got subclassed by #{subclass}"
end
end
class D < C
end
D继承C,触发了inherited方法,输出结果:
C just got subclassed by D
===Module#const_missing
在给定的模块或类中引用一个不可识别的常量时,该方法被调用:
class C
def self.const_missing(const)
puts "#{const} is undefined-setting it to 1."
const_set(const, 1)
end
end
puts C::A
puts C::A
输出结果:
A is undefined-setting it to 1.
1
1