metaid.rb学习笔记

当需要动态扩展一个类定义的类方法时候,我们可以利用metaid.rb,一个为元编程创建的极小的库来实现,代码如下:
# metaid
# ------
# a few simple metaclass helpers
#
# http://github.com/dannytatom/metaid

class Object
  # The hidden singleton lurks behind everyone
  def metaclass; class << self; self; end; end
  def meta_eval &blk; metaclass.instance_eval &blk; end

  # Adds methods to a metaclass
  def meta_def name, &blk
    meta_eval { define_method name, &blk }
  end
end

这里需要理清下面几个概念

类对象:Ruby中,所有的类名对应与一个常量,也就是一个Class类的一个对象,而Class这个常量也是Class类的一个对象实例。

类方法:即为Class类的对象的实例方法。类方法是如同普通的实例方法一样,它的接收对象必须是一个Class类的实例,而普通的实例方法没有这个限制条件。

对象在内存中的数据集合:在Ruby中,每个对象在内存中都将维护着klass,iv_tbl,m_tbl,flags,super这几个数据集合,其中,m_tbl指向一个类或者模块所包函的“方法表”。

self:Ruby中的self不同于Java中的this,在不同的上下文中有其不同的解释,例如,在类定义中,self指向的是类名对应的类对象常量;而在类的方法定义中,指向消息接收对象,和Java中的this有点类似。

对象方法的查询基本链路:当发送一个方法调用消息到一个对象,将通过该接收消息的对象的klass找到一个类对象,从它的m_tbl中查询,而不是直接从消息接收对象的m_tbl中查询。如果klass所指的类对象的m_tbl未找到该方法,Ruby将遵循super指针链路查询回溯至Object这个类对象。

本征类:当需要一个(仅仅需要一个)对象区别它的同类对象,但是利用继承生成该类的子类,实例化出一个对象这个代价过大时候,这里可以使用本征类,如同继承,让对象klass指向一个虚类,而这个虚类super指向原类(虚类不能实例化,即不能调用new方法)。ps:在Java中可以着到一个词“单例”带对应这个本征类吧,“某个对象自己的类”。

metaclass: 该方法调用的时候,返回消息的接收对象的本征类。

class A
end
a = A.new #=>#<A:0x00000002bba5b0> 
#这里可以看出a是一个A的对象实例
a.metaclass #=>#<Class:#<A:0x00000002bba5b0>>
#这里看出metaclass返回一个Class的对象实例,但有别于普通的类,这是一个虚类
#我们常用的定义类方法技巧原理也是如是:
class A
  class << self #创建一个本征类
    #添加一个实例方法到本征类中
    def method_1
      'hello'
    end
  end
end

metaclass.instance_eval: 向本征类注入类方法,即为向本征类这个Class类的对象注入实例方法:

class A
  def self.method_1
    'hello'
  end
end
#下面是生成的等价于上述代码
Object.const_get("A").meta_def(:method_1){'hello'}

你可能感兴趣的:(metaid.rb学习笔记)