On Wed, Feb 19, 2003 at 05:08:19PM +0900, Yukihiro Matsumoto wrote: > Hi, > > In message "Re: How to test for existence of instance variable?" > on 03/02/19, Paul Brannan <pbrannan / atdesk.com> writes: > > |Creating an attribute reader and not initializing the attribute (either > |with @foo= or with self.foo=) is a bug. The user should never see this > |warning except for buggy code. > > I thought it is needed just because > > @foo ||= [] > > trick cannot be done for attributes without causing warning. ??? batsman@tux-chan:/tmp$ irb --simple-prompt /usr/lib/ruby/1.6/irb/context.rb:112: warning: method redefined; discarding old irb_name /usr/lib/ruby/1.6/irb/context.rb:176: warning: method redefined; discarding old math_mode= /usr/lib/ruby/1.6/irb/context.rb:188: warning: method redefined; discarding old use_readline= /usr/lib/ruby/1.6/irb/context.rb:177: warning: instance variable @math_mode not initialized /usr/lib/ruby/1.6/irb/context.rb:151: warning: instance variable @use_tracer not initialized >> class A; def foo; @foo ||= []; end; end => nil >> A.new.foo => [] If you mean that attr_* won't work with default values, we can use something like the following: batsman@tux-chan:/tmp$ set | grep RUBYOPT RUBYOPT=-w batsman@tux-chan:/tmp$ expand -t 2 z.rb module AttrWithDefault def attr_reader_with_default(sym, val) instance_eval <<-EOF class << self attr_accessor "_#{sym.to_s}_".intern attr_reader :__symlist__ end @__symlist__ ||= [] @__symlist__.push( [self, "#{sym}"] ) EOF meth = self.method "_#{sym.to_s}_=".intern meth.call( val ) module_eval <<-EOF def #{sym.to_s} @#{sym.to_s} ||= self.class._#{sym.to_s}_ end EOF if self.singleton_methods.grep("inherited") == [] class << self def inherited sub ancestors.each do |klass| begin assoc = klass.__symlist__ assoc.each do |x| #puts "Redefining #{x[1]} from #{sub} using #{x[0]}._#{x[1]}_" sub.module_eval <<-EOF def #{x[1]} @#{x[1]} ||= #{x[0]}._#{x[1]}_ end EOF end rescue NameError end end end end end end end class A extend AttrWithDefault attr_reader_with_default :foo, [] attr_reader_with_default :bar, 'test' def inspect str = "#{self.class}:" instance_variables.each do |iv| str << " #{iv} => " str << instance_eval("#{iv}").inspect end str end end a = A.new p a a.foo p a class B < A attr_reader_with_default :bar2, 'bla' end class C < B end b = B.new p b b.foo b.bar p b c = C.new p c c.foo c.bar c.bar2 p c batsman@tux-chan:/tmp$ ruby z.rb A: A: @foo => [] B: B: @bar => "test" @foo => [] C: C: @bar => "test" @bar2 => "bla" @foo => [] I am not sure about what default value to take when several are specified at different points along the inheritance chain. -- _ _ | |__ __ _| |_ ___ _ __ ___ __ _ _ __ | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \ | |_) | (_| | |_\__ \ | | | | | (_| | | | | |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_| Running Debian GNU/Linux Sid (unstable) batsman dot geo at yahoo dot com Sigh. I like to think it's just the Linux people who want to be on the "leading edge" so bad they walk right off the precipice. -- Craig E. Groeschel