Ruby元编程读书笔记十四
Use Macros
可以使用类宏来声明一些已被弃用的旧方法名:
class Book
def title # ...
def subtitle # ...
def lend_to(user)
puts "Lending to #{user}"
# ...
def self.deprecate(old_method, new_method)
define_method(old_method) do |*args, &block|
warn "Warning: #{old_method}() is deprecated. Use #{new_method}()."
send(new_method, *args, &block)
end
end
deprecate :GetTitle, :title
deprecate :LEND_TO_USER, :lend_to
deprecate :title2, :subtitle
end
b = Book.new
b.LEND_TO_USER("Bill")
#=> Warning: LEND_TO_USER() is deprecated. Use lend_to().
#=> Lending to Bill
Eigenclass
在之前我们学习了 Ruby 是怎样查找方法的:
class MyClass
def my_method; end
end
obj = MyClass.new
obj.my_method
在调用 my_method() 方法时, Ruby 直接向右一步进入 MyClass 类,并在那里找到了这个方法。现在,如果在 obj 上定义一个 单件方法:
def obj.my_singleton_method; end
单件方法不能存在于 obj 中,因为 obj 不是一个类,但是它也不能存在于 MyClass 中,否则所有 MyClass 的实例都能共享这个方法。当然,它也不能存在于 MyClass 的超类 Object 中。那么,单件方法究竟在什么地方呢?
类方法是单件方法的特例—-而且同样令人困惑:
def MyClass.my_class_method; end
Eigenclasses Revealed
当向一个对象索要它的类时,Ruby 并没有告诉你全部的真相,而是还有一个对象特有的隐藏类,这个类称为该对象的 eigenclass。像 Object#class() 这样的方法虽然会把 eigenclass 隐藏起来,但是可以采用迂回战术解决这个问题。Ruby 有一种特殊的基于 class 关键字的语法,它可以让你进入该 eigenclass 的作用域:
class << an_object
# ...
end
如果想获得这个 eigenclass 的引用,则可以在离开该作用域时返回 self:
obj = Object.new
eigenclass = class << obj
self
end
eigenclass.class #=> Class
eigenclass 是一个类—-而且是很特殊的类。每个 eigenclass 只有一个实例(这就是它们也称为单件类的原因),并且不能被继承。更重要的是, eigenclass 是一个对象的单件方法的存活之所:
def obj.my_singleton_method; end
eigenclass.instance_methods.grep(/my/) #=> ["my_singleton_method"]
-
正常的方法查找过程是这样的,如果对象有 eigenclass,那么 Ruby 先从这个 eigenclass 类中开始查找方法,如果在 eigenclass 类中找不到这个方法,那么它会沿着祖先链向上来到 eigenclass 的超类—-这个对象所在的类。从这里开始,一切又跟过去所学的一样了。
-
eigenclass 的超类就是超类的 eigenclass。由于有了这种组织方式,你可以在子类中调用父类的类方法。
-
Ruby 对象模型7条规则:
- 只有一种对象—-要么是普通对象,要么是模块。
- 只有一种模块—-可以使普通模块、类、eigenclass、或代理类。
- 只有一个方法,它存在于一种模块中—-通常是类中。
- 每个对象(包括类)都有自己的“真正的类”—-要么是普通类,要么是 eigenclass。
- 除了 BasicObject 类无超类外,每个类有且只有一个超类,这意味着从任何类只有一条向上直到 BasicObject 的祖先链。
- 一个对象的 eigenclass 的超类是这个对象的类;一个类的 eigenclass 的超类是这个类的超类的 eigenclass。
- 当调用一个方法,Ruby 先向右迈一步进入接受者真正的类,然后向上进入祖先链。