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