元编程的意思是:对程序进行编程。
由于 Ruby 是一门动态编程语言,因此,在 Ruby 中可以很方便的实现元编程。
而在编程中灵活的使用元编程,将会非常有用和高效。
下面列举几个实用的、常见的例子。PS:使用 ruby-1.9.3-p194,Rails 3.0.11
1. Ruby 元编程中典型的例子:attr_accessor,attr_reader,attr_writer。
以 attr_accessor 为例,attr_accessor 是一个 Ruby 类中内嵌的方法,可以用来动态的生成访问实例变量的(set/get)方法。
    class User
      attr_accessor :name
    end
    puts User.instance_methods
  
输出结果中将包含:name 和 name= 。因此下面的程序将输出:'admin'
admin = User.new admin.name = 'admin' puts admin.name # admin
2. Rails 中典型的例子:belongs_to,has_one,has_many 等。
以 belongs_to 为例:
  class Book < ActiveRecord::Base
    belongs_to :user
  end
  book = Book.new
  
由于有 belongs_to :user 这句声明,book 这个实例,将拥有下面四个实例方法,实践中会经常用到。
user user= build_user create_user
3. 使用 send 方法,对例1的程序稍作改动,如下:
  class User
    attr_accessor :name
    def initialize(attrs = {})
      attrs.each do |k,v|
        self.send("#{k}=", v)
      end
    end
  end
  admin = User.new(:name => 'admin')
  puts admin.name
  # admin
  
输出结果同样为'admin'。
好处在于新建 user 时,可以传入一个 Hash。这一优点在 user 属性多的时候,比较明显。
4. 使用 class_eval 和 define_method 方法。
下面尝试初始一个类,并且在运行时,动态的为其增加一个方法。输出结果为注释的内容。
  class User
  end
  u = User.new
  puts u.respond_to?(:website_url)
  # false
  User.class_eval do
    define_method :website_url do
      "www.boohee.com"
    end
  end
  puts u.respond_to?(:website_url)
  # true
  puts u.website_url
  # www.boohee.com
  
5. 使用 method_missing 方法:Ruby 中非常强大的特性,灵活的运用可以简化代码。
Rails 源代码中有非常多的应用。例如,ActiveRecord::Base 类中,有下面这样一个方法定义:
  def method_missing(method_id, *arguments, &block)
    if match = DynamicFinderMatch.match(method_id)
      attribute_names = match.attribute_names
      super unless all_attributes_exists?(attribute_names)
      if match.finder?
        ...
        relation.send :find_by_attributes, match, attribute_names, *arguments
      elsif match.instantiator?
        scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
      end
    elsif match = DynamicScopeMatch.match(method_id)
      ...
    else
      super
    end
  end
  
该方法即实现了所有 find_by_* 的方法。当我们调用 User.find_by_name('admin') 的时候,
实现原理是:User 类中没有该方法,Base中也没有,但是 Base 类中定义了 method_missing 方法。
因此执行该方法。大概浏览一下 DynamicFinderMatch 的 match 方法,他会使用正则解析,判断查找的方式是
find_all 还是 find_last,并且解析将要查找的条件,最后,构造一个 find 语句。
还有很多可以实现动态编程的方法。例如:eval, instance_eval, remove_method, undef_method。
理解 Ruby 元编程,需要清楚 Ruby 的 Classes 是一个对象(Object)。
而且,任意一个 Classes 都不是关闭的,在运行时可以被打开,重新定义程序信息。
在运用元编程实现动态编程的时候,需要清楚的知道它的 self 以及作用域,
否则,会遇到一些奇怪的问题,但是,思考一下(self 和 scope)就可以找到问题了。
2012-12-02