Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
# dohzya's comment is on target - the overhead here is in restoring # the context (stack frame) that was captured by # define_method, and handling the amount.is_a?(Array) case. # # Just lifting the Array case above define_method fails pretty badly, # as the methods don't get defined on Numeric until the end. (Also # note: the meta-programming code relies on the TimeDsl code in # this example - m_days calls TimeDsl's version of hours) # # What's really needed (if you want to go meta) is something closer # to ActiveRecord's method: module Meta2TimeDSL def self.included(base) base.class_eval do [ [:m2_second, 1], [:m2_minute, 60], [:m2_hour, 3600], [:m2_day, [24,:m2_hours]], [:m2_week, [7,:m2_days]], [:m2_month, [30,:m2_days]], [:m2_year, [365.25, :m2_days]]].each do |meth, amount| amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount define_method meth do self * amount end alias_method "#{meth}s".intern, meth end end end end Numeric.send :include, Meta2TimeDSL #A couple notes: # - The hash has been changed to an array; this is needed because # Hash.each does not return elements in the order they were defined # (it's not specified what order they appear in, by design). # - This gives some speedup, (0.09s vs 0.13s, see below), but still has overhead due to the closure environment. # A version using eval fixes the performance problems: module Meta3TimeDSL def self.included(base) base.class_eval do [ [:m3_second, 1], [:m3_minute, 60], [:m3_hour, 3600], [:m3_day, [24,:m3_hours]], [:m3_week, [7,:m3_days]], [:m3_month, [30,:m3_days]], [:m3_year, [365.25, :m3_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".intern, meth end end end end Numeric.send :include, Meta3TimeDSL # Yielding the benchmarks shown below: # Rehearsal ------------------------------------------------------------------ # metaprogramming 360.seconds 0.140000 0.000000 0.140000 ( 0.141081) # metaprogramming(2) 360.seconds 0.090000 0.000000 0.090000 ( 0.093958) # metaprogramming(3) 360.seconds 0.040000 0.000000 0.040000 ( 0.046542) # no metaprogramming 360.hours 0.050000 0.000000 0.050000 ( 0.048048) # metaprogramming 360.minutes 0.130000 0.010000 0.140000 ( 0.130627) # metaprogramming(2) 360.minutes 0.090000 0.000000 0.090000 ( 0.092048) # metaprogramming(3) 360.minutes 0.050000 0.000000 0.050000 ( 0.046882) # no metaprogramming 360.minutes 0.040000 0.000000 0.040000 ( 0.047463) # metaprogramming 360.hours 0.130000 0.000000 0.130000 ( 0.131119) # metaprogramming(2) 360.hours 0.090000 0.000000 0.090000 ( 0.092674) # metaprogramming(3) 360.hours 0.050000 0.000000 0.050000 ( 0.047141) # no metaprogramming 360.hours 0.040000 0.000000 0.040000 ( 0.045937) # metaprogramming 360.days 0.140000 0.000000 0.140000 ( 0.137041) # metaprogramming(2) 360.days 0.090000 0.000000 0.090000 ( 0.093388) # metaprogramming(3) 360.days 0.040000 0.000000 0.040000 ( 0.049240) # no metaprogramming 360.days 0.050000 0.000000 0.050000 ( 0.050279) # metaprogramming 360.weeks 0.130000 0.000000 0.130000 ( 0.136106) # metaprogramming(2) 360.weeks 0.090000 0.000000 0.090000 ( 0.099243) # metaprogramming(3) 360.weeks 0.040000 0.000000 0.040000 ( 0.051029) # no metaprogramming 360.weeks 0.050000 0.000000 0.050000 ( 0.050768) # metaprogramming 18.months 0.130000 0.000000 0.130000 ( 0.158195) # metaprogramming(2) 18.months 0.090000 0.000000 0.090000 ( 0.099450) # metaprogramming(3) 18.months 0.050000 0.000000 0.050000 ( 0.055940) # no metaprogramming 18.months 0.050000 0.000000 0.050000 ( 0.051529) # metaprogramming 7.years 0.130000 0.000000 0.130000 ( 0.170961) # metaprogramming(2) 7.years 0.100000 0.000000 0.100000 ( 0.104808) # metaprogramming(3) 7.years 0.050000 0.000000 0.050000 ( 0.054334) # no metaprogramming 7.years 0.050000 0.000000 0.050000 ( 0.050485) # --------------------------------------------------------- total: 2.230000sec # # user system total real # metaprogramming 360.seconds 0.130000 0.000000 0.130000 ( 0.141990) # metaprogramming(2) 360.seconds 0.090000 0.000000 0.090000 ( 0.098228) # metaprogramming(3) 360.seconds 0.050000 0.000000 0.050000 ( 0.049056) # no metaprogramming 360.hours 0.050000 0.000000 0.050000 ( 0.047961) # metaprogramming 360.minutes 0.130000 0.000000 0.130000 ( 0.130837) # metaprogramming(2) 360.minutes 0.090000 0.000000 0.090000 ( 0.093146) # metaprogramming(3) 360.minutes 0.050000 0.000000 0.050000 ( 0.048804) # no metaprogramming 360.minutes 0.040000 0.000000 0.040000 ( 0.053469) # metaprogramming 360.hours 0.130000 0.000000 0.130000 ( 0.131478) # metaprogramming(2) 360.hours 0.090000 0.000000 0.090000 ( 0.093532) # metaprogramming(3) 360.hours 0.040000 0.000000 0.040000 ( 0.047129) # no metaprogramming 360.hours 0.040000 0.000000 0.040000 ( 0.046554) # metaprogramming 360.days 0.130000 0.000000 0.130000 ( 0.131920) # metaprogramming(2) 360.days 0.100000 0.000000 0.100000 ( 0.094566) # metaprogramming(3) 360.days 0.040000 0.000000 0.040000 ( 0.046710) # no metaprogramming 360.days 0.050000 0.000000 0.050000 ( 0.047298) # metaprogramming 360.weeks 0.130000 0.000000 0.130000 ( 0.131556) # metaprogramming(2) 360.weeks 0.090000 0.000000 0.090000 ( 0.093834) # metaprogramming(3) 360.weeks 0.050000 0.000000 0.050000 ( 0.047080) # no metaprogramming 360.weeks 0.050000 0.000000 0.050000 ( 0.047726) # metaprogramming 18.months 0.130000 0.000000 0.130000 ( 0.138385) # metaprogramming(2) 18.months 0.090000 0.000000 0.090000 ( 0.094485) # metaprogramming(3) 18.months 0.050000 0.000000 0.050000 ( 0.047307) # no metaprogramming 18.months 0.050000 0.000000 0.050000 ( 0.047689) # metaprogramming 7.years 0.130000 0.000000 0.130000 ( 0.132349) # metaprogramming(2) 7.years 0.100000 0.000000 0.100000 ( 0.098260) # metaprogramming(3) 7.years 0.050000 0.000000 0.050000 ( 0.051457) # no metaprogramming 7.years 0.050000 0.000000 0.050000 ( 0.048856) # Essentially, the eval version is identical to the handwritten version. # Whether it is more readable, however, is another thing entirely. I can't # see using this kind of structure for something like time which is naturally # fixed (it seems unlikely that a week will not be 7 days in the future...), but # it could be useful for more variable situations (constants defined in YAML, # or in a DB somewhere). # #--Matt
This paste will be private.
From the Design Piracy series on my blog: