From: The Higgs bozo Date: 2010-01-24T23:36:46+09:00 Subject: Re: Writing proper getter in a Ruby way I assume the usual thing is to assign @value = nil in initialize() and call it a day. But I think you are asking a higher-level question: How do we abstract away this detail? The attr_* methods define methods which create instance variables upon first being called. But what if we want those instance variables to be initialized beforehand? We would need to override the attr_* methods. But those methods belong to the class object--how are they going to initialize variables in the instances? By inserting code into the initialize() ancestor chain. module InitializeAttr [:attr_reader, :attr_writer, :attr_accessor].each do |method| define_method method do |*syms| super(*syms).tap do mod = Module.new do define_method :initialize do |*args, &block| super(*args, &block).tap do syms.each do |sym| instance_variable_set("@#{sym}", nil) end end end end include mod end end end end class Control attr_writer :a, :b def bar @a.to_i + 5 end end control = Control.new p control.instance_variables #=> [] p control.bar #=> warning: instance variable @a not initialized #=> 5 class Experiment extend InitializeAttr attr_writer :a, :b def bar @a.to_i + 5 end end exp = Experiment.new p exp.instance_variables #=> [:@a, :@b] p exp.bar #=> 5 # yay no warnings Therein lies either an abstraction technique or an overkill technique. A few things about define_method blocks, + The &block argument is unsupported in Ruby 1.8.6. Sell your soul to eval() for a workaround. + Implicit super arguments are broken in 1.8.7. It passes the regular arguments but forgets about the &block argument. + In Ruby 1.9 super *must* take explicit arguments. Don't know why. -- Posted via http://www.ruby-forum.com/.