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条规则

    1. 只有一种对象—-要么是普通对象,要么是模块。
    2. 只有一种模块—-可以使普通模块、类、eigenclass、或代理类。
    3. 只有一个方法,它存在于一种模块中—-通常是类中。
    4. 每个对象(包括类)都有自己的“真正的类”—-要么是普通类,要么是 eigenclass。
    5. 除了 BasicObject 类无超类外,每个类有且只有一个超类,这意味着从任何类只有一条向上直到 BasicObject 的祖先链。
    6. 一个对象的 eigenclass 的超类是这个对象的类;一个类的 eigenclass 的超类是这个类的超类的 eigenclass
    7. 当调用一个方法,Ruby 先向右迈一步进入接受者真正的类,然后向上进入祖先链。