From: Rick DeNatale Date: 2008-02-13T22:37:17+09:00 Subject: Re: How to add a instance variable through a mixin? On 2/12/08, Robert Klemme wrote: > You can do > > module Foo > attr_accessor :var > > def initialize(*a,&b) > @var = 10 > end > end > > And then > > irb(main):015:0> class Bar > irb(main):016:1> include Foo > irb(main):017:1> end > => Bar > irb(main):018:0> Bar.new.var > => 10 > > Or > > irb(main):026:0> class Oink > irb(main):027:1> include Foo > irb(main):028:1> def initialize > irb(main):029:2> super > irb(main):030:2> @x = 10 > irb(main):031:2> end > irb(main):032:1> end > => nil > irb(main):033:0> Oink.new.var > => 10 You have to be careful here, since it relies on invoking super in the initialize method, and since the initialize method in the module doesn't do this, it can break under the right conditions: class A attr_reader :a_var def initialize @a_var = :a_var end end module M attr_reader :m_var def initialize @m_var = :m_var end end class B < A include M end B.new.instance_variables # => ["@m_var"] Note that the A instance didn't get an @a_var instance variable. The solution here is to invoke the superclass' initialize, which also works for subclasses which don't have an initialize method themselves: class A attr_reader :a_var def initialize @a_var = :a_var end end module M attr_reader :m_var def initialize super @m_var = :m_var end end class B < A include M end class C include M end B.new.instance_variables # => ["@a_var", "@m_var"] C.new.instance_variables # => ["@m_var"] But this is hard to do in general when the initialize methods take different parameters. module M attr_reader :m_var def initialize(*a, &b) super @m_var = :m_var end end class D include M def initialize(d_val) @d_var = d_val super end end D.new(10).instance_variables # => # ~> -:13:in `initialize': wrong number of arguments (1 for 0) (ArgumentError) # ~> from -:13:in `initialize' # ~> from -:30:in `initialize' # ~> from -:35:in `new' # ~> from -:35 -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/