# bad use of metaprogramming module MetaTimeDSL {: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 "m_#{meth}" do amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount self * amount end alias_method "m_#{meth}s".intern, "m_#{meth}" end end Numeric.send :include, MetaTimeDSL # Rewrite 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 * 18144000 end alias_method :months, :month def year self * 31471200 end alias_method :years, :year end Numeric.send :include, TimeDSL module RefaMetaTimeDSL {:second => 1, :minute => 60, :hour => 3600, :day => [24,:hours], :week => [7,:days], :month => [30,:days], :year => [364.25, :days]}.each do |meth, amount| self.class_eval <<-RUBY def r_#{meth} #{amount.is_a?(Array) ? "#{amount[0]}.#{amount[1]}" : "#{amount}"} end alias_method :r_#{meth}s, :r_#{meth} RUBY end end Numeric.send :include, RefaMetaTimeDSL module EvalMetaTimeDSL def self.included(base) base.class_eval do [ [:e_second, 1], [:e_minute, 60], [:e_hour, 3600], [:e_day, [24,:e_hours]], [:e_week, [7,:e_days]], [:e_month, [30,:e_days]], [:e_year, [365.25, :e_days]]].each do |meth, amount| amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount eval "def #{meth}; self*#{amount}; end" alias_method "#{meth}s", meth end end end end Numeric.send :include, EvalMetaTimeDSL 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 ############################### # # # Benchmarks require "rubygems" require "rbench" TIMES = 100_000 RBench.run(TIMES) do format :width => 65 column :times column :bad_meta, :title => "Bad Neta" column :no_meta, :title => "No Meta" column :refa, :title => "Refactored" column :eval_meta, :title => 'Refactor 2' column :good_meta, :title => "Better Meta" group("MetaTimeDSL") do report "with 360.seconds" do bad_meta { 360.m_seconds } no_meta { 360.seconds } refa { 360.r_seconds } eval_meta { 360.e_seconds} good_meta { 360.g_seconds } end report "with 360.minutes" do bad_meta { 360.m_minutes } no_meta { 360.minutes } refa { 360.r_minutes } eval_meta { 360.e_minutes } good_meta { 360.g_minutes } end report "with 360.hours" do bad_meta { 360.m_hours } no_meta { 360.hours } refa { 360.r_hours } eval_meta { 360.e_hours } good_meta { 360.g_hours } end report "with 360.days" do bad_meta { 360.m_days } no_meta { 360.days } refa { 360.r_days } eval_meta { 360.e_days } good_meta { 360.g_days } end report "with 360.weeks" do bad_meta { 360.m_weeks } no_meta { 360.weeks } refa { 360.r_weeks } eval_meta { 360.e_weeks } good_meta { 360.g_weeks } end report "with 18.months" do bad_meta { 18.m_months } no_meta { 18.months } refa { 18.r_months } eval_meta { 18.e_months } good_meta { 18.g_months } end report "with 7.years" do bad_meta { 7.m_years } no_meta { 7.years } refa { 7.r_years } eval_meta { 7.e_years } good_meta { 7.g_years } end end end ##### # #                                  | Bad Neta | No Meta | Refactored | Refactor 2 | Better Meta | # --MetaTimeDSL---------------------------------------------------------------------------------- # with 360.seconds         x100000 |    0.143 |   0.046 |      0.033 |      0.047 |       0.048 | # with 360.minutes         x100000 |    0.152 |   0.045 |      0.033 |      0.046 |       0.046 | # with 360.hours           x100000 |    0.127 |   0.044 |      0.032 |      0.045 |       0.048 | # with 360.days            x100000 |    0.144 |   0.047 |      0.070 |      0.045 |       0.048 | # with 360.weeks           x100000 |    0.129 |   0.044 |      0.070 |      0.046 |       0.047 | # with 18.months           x100000 |    0.143 |   0.045 |      0.071 |      0.045 |       0.048 | # with 7.years             x100000 |    0.143 |   0.046 |      0.089 |      0.054 |       0.050 | # ####