ruby强大的 define_method,有闭包的能力!

闭包的例子一般是在说ruby的块,特片是:访问本地变量和绑定运行上下文(很强大的两点)

 

nums = [10,3,22,34,17]
sum = 0
nums.each{|n| sum += n}
print sum

 

近来看mongoid的代码,发现define_method也能绑定运行上下文!

 

 def getter(name, metadata)
     tap do
       define_method(name) do |*args|
         reload, variable = args.first, "@#{name}"
         options = options(args)
         if instance_variable_defined?(variable) && !reload
           instance_variable_get(variable)
         else
           build(
             name,
             @attributes[metadata.key],
             metadata,
             options.merge(:binding => true, :eager => metadata.embedded?)
           )
         end
       end
     end
   end          

 

定义的getter方法中绑定了当时metadata类实例!这样应用不用再额外做映射表,来维护方法与其它对象的关系,正如有栈系统帮我们存函数出入参数。

 

写了一个简单示意方法:

 

class Metadata
  attr_accessor :relation_name
end

module Accessor           
  def build(name, metadata)
    p name, metadata, metadata.relation_name
  end

  module ClassMethods
    def getter(name, metadata)
      tap do
        define_method(name) do 
          build(
          name,
          metadata
          )
        end
      end
    end
  end        
end   

class Doc
  include Accessor
  extend Accessor::ClassMethods
end

meta = Metadata.new
meta.relation_name = 'embeds_one'

Doc.getter("ss_car", meta)
# p Doc.public_instance_methods
Doc.new.ss_car

meta2 = Metadata.new
meta2.relation_name = 'ref_one'
Doc.getter("ss_bus", meta2)
Doc.new.ss_bus                          

 

输出:

 

"ss_car"
#<Metadata:0x00000100846f38 @relation_name="embeds_one">
"embeds_one"
"ss_bus"
#<Metadata:0x00000100846128 @relation_name="ref_one">
"ref_one"

 

 

 

 

你可能感兴趣的:(Ruby)