闭包的例子一般是在说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"