ruby強力なdefine_method、閉める能力がある!

2368 ワード

閉パッケージの例は一般的にrubyのブロックについて話しています.スライスは、ローカル変数にアクセスし、実行コンテキストをバインドすることです(強力な2点).
 
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"# "embeds_one""ss_bus"# "ref_one"