środa, 18 sierpnia 2010

Module#attr_accessor_with_default by Rails3 (and its speed measured by benchmark)

Did you know that every time you change the value it will recreate reader method?

class Module
# Declare an attribute accessor with an initial default return value.
#
# To give attribute :age the initial value 25:
#
# class Person
# attr_accessor_with_default :age, 25
# end
#
# some_person.age
# => 25
# some_person.age = 26
# some_person.age
# => 26
#
# To give attribute :element_name a dynamic default value, evaluated
# in scope of self:
#
# attr_accessor_with_default(:element_name) { name.underscore }
#
def attr_accessor_with_default(sym, default = nil, &block)
raise 'Default value or block required' unless !default.nil? || block
define_method(sym, block_given? ? block : Proc.new { default })
module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
def #{sym}=(value) # def age=(value)
class << self; attr_reader :#{sym} end # class << self; attr_reader :age end
@#{sym} = value # @age = value
end # end
EVAL
end
end



The effect is like that:


BigNumber = 1_000_000

def test
BigNumber.times do
yield
end
end

Benchmark.bmbm do |x|

x.report("normal") do
klass = Class.new
klass.class_eval {attr_accessor :age}
k = klass.new
test do
k.age = 12
end
end

x.report("default") do
klass = Class.new
klass.class_eval { attr_accessor_with_default :age, 25 }
k = klass.new
test do
k.age = 12
end
end
end


Rehearsal -------------------------------------------
normal 0.230000 0.000000 0.230000 ( 0.230735)
default 5.500000 0.000000 5.500000 ( 5.503365)
---------------------------------- total: 5.730000sec

user system total real
normal 0.220000 0.000000 0.220000 ( 0.220314)
default 5.440000 0.000000 5.440000 ( 5.439583)