From: dblack@... Date: 2002-08-13T01:17:52+09:00 Subject: Re: ambiguity between local variable assignment and writter method Hi -- On Mon, 12 Aug 2002, Tom Sawyer wrote: > i'm creating my own attribute module methods to replace attr_reader, > attr_writer, and attr_accessor. instead of having a seperate method for > assignment, i use the same method as the reader, but it checks to see if > there's an argument passed. if there is than it acts like a setter. > > not positive about the names of these yet, but: > > class Module > > def Module.attr_rw(name) > name = name.to_s > class_eval <<-EOS > if not method_defined?(:#{name}) > def #{name}(*args) > if args.length > 0 > return @#{name} = args[0] > else > if @#{name} > return @#{name} > else > return @#{name} = nil > end > end > end > end > EOS > end > > def Module.attr_ro(name) > name = name.to_s > class_eval <<-EOS > if not method_defined?(:#{name}) > def #{name} > if @#{name} > return @#{name} > else > return @#{name} = nil > end > end > end > EOS > end > > end > > is this the right way to go about this? can anyone improve on this code? > or see any flaws that need to be fixed? i don't have a write only > version, do i really need it? i don't think i've have used one before. I would recommend: 1. Don't check for method existence. Use -w, and let Ruby warn you if you're redefining and/or discarding methods. 2. Consolidate some of the logic; I don't think you need that many branches. (Or am I overlooking a scenario?) 3. Consider how you would do the equivalent of this: class X attr_reader :thing def thing=(x) @thing = "I am #{x}" end end I can't spot a way to do it very cleanly (i.e., without either using aliases and/or manually rewriting the method that was automatically written.) Here's a somewhat trimmed-down implementation (which I think behaves the same as yours). I've added multi-argument handling. class Module def attr_rw(*names) names.each do |name| class_eval <<-EOS def #{name}(*args) @#{name} = args[0] if args.size > 0 @#{name} end EOS end end def attr_ro(*names) names.each do |name| class_eval <<-EOS def #{name} @#{name} end EOS end end end class X attr_rw :thing, :other end x = X.new x.thing "Hello" puts x.thing x.other "Bye" puts x.other David -- David Alan Black home: dblack@candle.superlink.net work: blackdav@shu.edu Web: http://pirate.shu.edu/~blackdav