Ruby Meta Programming: define_method or class_eval


今日はMatt Aimonettiのblogでruby meta programmingの実行効率について議論しているのを見て、ついてみましたが、いろいろなことを学びました.大まかに言えば、まずMattは簡単な計算時間のDSLクラスを書きました.

module TimeDSL
    def second
      self * 1
    end
    alias_method :seconds, :second

    def minute
      self * 60
    end
    alias_method :minutes, :minute

    def hour
      self * 3600
    end
    alias_method :hours, :hour

    def day
      self * 86400
    end
    alias_method :days, :day

    def week
      self * 604800
    end
    alias_method :weeks, :week

    def month
      self * 2592000
    end
    alias_method :months, :month

    def year
      self * 31471200
    end
    alias_method :years, :year
end
Numeric.send :include, TimeDSL

このクラスは簡単です.Numericクラスに時間に関するいくつかの方法を追加します.これにより、類似のコードを使用して時間を計算できます.たとえば、次のようにします.

1.hours + 20.minutes # =>    20      
3.days + 5.hours # => 3  5  
2.years + 10.months # =>      

コードは簡単ですが、Mattの使用に注意してください.
Numeric.send :include, TimeDSL
法はNumericクラスにTimeDSLというモジュールを追加した.
そして彼はdefineを利用してmethod方式でTimeDSLを実現するクラス(説明の便宜上、省略しました)

module BadMetaTimeDSL

    {:second => 1, 
     :minute => 60, 
     :hour => 3600, 
     :day => [24,:hours], 
     :week => [7,:days], 
     :month => [30,:days], 
     :year => [364.25, :days]}.each do |meth, amount|
		define_method "b_#{meth}" do
			amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount
			self * amount
		end
		alias_method "b_#{meth}s".intern, "b_#{meth}"
    end
  end
Numeric.send :include, BadMetaTimeDSL

彼はこの2つのbenchmarkのテストデータを発表し、rubyのmeta programmingは基本的に正常な方法より3倍ほど遅いと結論した(私自身のテストデータは2倍ぐらいだ)
この結論はすぐに多くの人の議論を引き起こし,最後にWycatsは改善案を提出した.

module GoodMetaTimeDSL
  SECOND  = 1
  MINUTE  = SECOND * 60
  HOUR    = MINUTE * 60
  DAY     = HOUR * 24
  WEEK    = DAY * 7
  MONTH   = DAY * 30
  YEAR    = DAY * 364.25

  %w[SECOND MINUTE HOUR DAY WEEK MONTH YEAR].each do |const_name|
      meth = const_name.downcase
      class_eval <<-RUBY
        def g_#{meth}
          self * #{const_name}
        end
        alias g_#{meth}s g_#{meth}
      RUBY
  end
end
Numeric.send :include, GoodMetaTimeDSL

新しいクラスの実行効率が通常の方法で定義されたクラスに迫るのは,ほとんど差がないと言える.その原因を究明するmethodは実行するためにProcを作成する必要がありますがclass_evalとruby自身の実行方式には何の違いもなく,実行を直接解釈している.
最後の結論は、できればclassを使うことです.义齿
添付ファイルの図面をどのように貼るか分かりませんが、添付ファイルを見てください.ソースコードも含まれています.
テスト全体がjruby 1.1.3で合格しました
参考になる
http://railsontherun.com/2008/6/18/about-metaprogramming-speed