Hook Methods 一般译为钩子方法,可以理解为当触发了某个条件执行的方法。例如我们常见的 method_missing。
Method 相关
示例代码:
# respond_to_missing?
class Base
def respond_to_missing?(sym, *args)
true
end
end
Base.new.respond_to?(:missing_method)
# 这个跟重写respond_to?的区别主要在于使用下面这个方法
Base.new.method(:missing_method)
# => #<Method: Base#missing_method>
# method_missing
class Base
def method_missing(method_name)
puts method_name
end
end
Base.new.missing_method
# => missing_method
# method_added
class Base
def self.method_added(method_name)
puts method_name
end
def missing_method
end
end
# => missing_method
Base.class_eval { def missing_method2;end }
# => missing_method2
# method_removed
class Base
def self.method_removed(method_name)
puts method_name
end
end
Base.class_eval { remove_method :missing_method }
# => missing_method
# method_undefined
class Base
def self.method_undefined(method_name)
puts method_name
end
end
Base.class_eval { undef_method :missing_method }
# => missing_method
# singleton_method_added/removed/undefined
class Base
def self.singleton_method_added(method_name)
puts method_name
end
def self.missing_method
end
def Base.missing_method1
end
end
def Base.missing_method2
end
# => singleton_method_added
# => missing_method
# => missing_method1
# => missing_method2
Class/Object相关
介绍这几个方法之前我们先要了解一下 dup 和 clone 的区别,主要有以下两点:
# inherited
class Base
def self.inherited(sub)
puts sub.name
end
end
class Sub < Base
end
# => Sub
# initialize_*
class Base
def initialize_copy(other)
puts 'initialize_copy'
super
end
def initialize_dup(other)
puts 'initialize_dup'
super
end
def initialize_clone(other)
puts 'initialize_clone'
super
end
end
Base.new.dup
# => initialize_dup
# => initialize_copy
Base.new.clone
# => initialize_copy
# => initialize_clone
Modules 相关
首先来说,对于 include,prepend 这两者和 extend 的关系很容易区分。include 和 prepend 的区别在于对祖先链的修改方式,进一步影响方法的查找流程。
参考下面的例子:
module M
def hello
puts 'Hello from M'
super
end
end
module N
def hello
puts 'Hello from N'
end
end
class C
include N
prepend M
def hello
puts 'hello from C'
super
end
end
C.new.hello
#=> Hello from M
#=> hello from C
#=> Hello from N
其中 included 和 append_features 是一组,prepended 和 prepend_features 是一组,extended 和 extend_object 是一组。
以 included 和 append_features 来说,append_features 这个方法是真正把 module 里的代码混入到 include 此 module 的地方,而 included 仅仅是在完成混入之后执行的一个回调,下面是一个伪示例:
module M
def self.append_features(mod)
mod.class_eval {def new_method;puts 'say hi!';end}
end
def self.included(mod)
puts 'included'
mod.new.new_method
end
def self.const_missing(const_name) # 当常量丢失时执行
puts const_name
end
MissingConst # 访问不存在常量
end
# => MissingConst
M::MissingPerson
# => MissingPerson # 访问不存在常量
对于 prepend 和 extend 两组来说也是如此。
Marshal 相关
class C
attr_accessor :arrs, :d_arrs
def marshal_dump
Marshal.dump(arrs)
end
def marshal_load(data)
self.d_attrs = Marshal.load(data)
end
end
k = C.new
k.arrs = [1,2,3,4,5]
k2 = Marshal.load(Marshal.dump(k))
k2.d_arrs
# => [1,2,3,4,5]
k2.arrs
# => nil
Coercion 相关
# coerce
class C
def coerce(n)
puts n
[n,5]
end
def to_s
"CCCC"
end
def to_int
3
end
def to_proc
Proc.new {|i| puts i}
end
end
3*C.new
#=> 3
#=> 15
"#{C.new}" #=> CCCC 会触发to_s
[1,2,3,4,5][C.new]
# => 4 触发to_int
[1,2,3,4,5].each(&C.new) # to_proc
# => 1
# => 2
# => 3
# => 4
# => 5