This post originated from an RSS feed registered with Ruby Buzz
by Jay Fields.
Original Post: Ruby: Assigning instance variables in a constructor
Feed Title: Jay Fields Thoughts
Feed URL: http://feeds.feedburner.com/jayfields/mjKQ
Feed Description: Blog about Ruby, Agile, Testing and other topics related to software development.
Every time I assign an instance variable in a constructor I remember that I've been meaning to write something that takes care of it for me.
class DomainObject attr_reader :arg1, :arg2
def initialize(arg1, arg2) @arg1, @arg2 = arg1, arg2 end end
So, without further ado.
class Module def initializer(*args, &block) define_method :initialize do |*ctor_args| ctor_named_args = (ctor_args.last.is_a?(Hash) ? ctor_args.pop : {}) (0..args.size).each do |index| instance_variable_set("@#{args[index]}", ctor_args[index]) end ctor_named_args.each_pair do |param_name, param_value| instance_variable_set("@#{param_name}", param_value) end initialize_behavior end
define_method :initialize_behavior, &block end end
The above code allows you to create a constructor that takes arguments in order or from a hash. Here's the tests that demonstrate the behavior of the initializer method.
class ModuleExtensionTest < Test::Unit::TestCase def test_1st_argument klass = Class.new do attr_reader :foo
initializer :foo end foo = klass.new('foo') assert_equal 'foo', foo.foo end
def test_block_executed klass = Class.new do attr_reader :bar
initializer do @bar = 1 end end foo = klass.new assert_equal 1, foo.bar end
def test_2nd_argument klass = Class.new do attr_reader :foo, :baz
initializer :foo, :baz end foo = klass.new('foo', 'baz') assert_equal 'baz', foo.baz end
def test_used_hash_to_initialize_attrs klass = Class.new do attr_reader :foo, :baz, :cat
initializer :foo, :baz, :cat end foo = klass.new(:cat => 'cat', :baz => 2, :foo => 'foo') assert_equal 'foo', foo.foo assert_equal 2, foo.baz assert_equal 'cat', foo.cat end end
There are limitations, such as not being able to use default values. But, for 80% of the time, this is exactly what I need.