On my current project I found we often duplicated the pattern:
def method_nameI saw this often enough that I decided to create a module to reduce the duplication. The module allows you to specify an attribute that will be initialized on the first execution. Additionally, it allows you to specify what type of class you want initialized and it allows you to provide constructor arguments if necessary.
@method_name ||= Klass.new
end
# module definition*Note: adding the constructor arguments is completely optional and the above code will also work if you change
module AttributeInitializer
def attr_init(name, klass, *ctor_args)
eval "define_method(name) { @#{name} ||= klass.new(*ctor_args) }"
end
def self.append_features(mod)
mod.extend(self)
end
end
# example of usage
class Foo
include AttributeInitializer
attr_init :bar, Array, 1, "some_val"
end
# tests to ensure it works as expected
require 'test/unit'
class AttributeInitTest < Test::Unit::TestCase
def test_same_instance_is_returned
f = Foo.new
assert_equal f.bar, f.bar
end
def test_ctor_args_are_correctly_passed
f = Foo.new
assert_equal ["some_val"], f.bar
end
end
attr_init :bar, Array, 1, "some_val"to
attr_init :bar, Arrayand
assert_equal ["some_val"], f.barto
assert_equal [], f.bar