From: "Aaron D. Gifford" Date: 2011-04-15T08:45:30+09:00 Subject: Re: What do you do when you need to attach data to an object instance? > On Thu, Apr 14, 2011 at 3:11 PM, Kevin Mahler wrote: >> You probably wouldn't want OpenStructModule even if it did exist because >> you wouldn't want NoMethodError to be suppressed. Perhaps you're looking >> for Object#extend. So using Kevin's suggestion: def extend_accessor(obj, name) mod = Module.new mod.send(:public).send(:attr_accessor, name.to_sym) obj.extend(mod) obj end That's a cleaner way to attach data: irb(main):001:0> def extend_accessor(obj, name) irb(main):002:1> mod = Module.new irb(main):003:1> mod.send(:public).send(:attr_accessor, name.to_sym) irb(main):004:1> obj.extend(mod) irb(main):005:1> obj irb(main):006:1> end => nil irb(main):007:0> a = "this is a string" => "this is a string" irb(main):008:0> extend_accessor(a, :bar) => "this is a string" irb(main):009:0> a.bar => nil irb(main):010:0> a.bar = "hi there" => "hi there" Now another question. I noticed that if I don't include the send(:public) bit up there, that the send(:attr_accessor) message delivered to the anonymous module ends up creating private accessor methods, not public. I find that puzzling: irb(main):001:0> def extend_accessor(obj, name) irb(main):002:1> mod = Module.new irb(main):003:1> mod.send(:attr_accessor, name.to_sym) irb(main):004:1> obj.extend(mod) irb(main):005:1> obj irb(main):006:1> end => nil irb(main):007:0> a = "this is a string" => "this is a string" irb(main):008:0> extend_accessor(a, :bar) => "this is a string" irb(main):009:0> a.bar = "hi there" NoMethodError: private method `bar=' called for "this is a string":String from (irb):9 from /opt/local/bin/irb:12:in `
' irb(main):010:0> Any ideas why sending :attr_accessor to a module would create accessors as private? I would think that attr_accessor implies public, but I guess if by default an anonymous module is in "private" mode, that might explain it. However, if that's the case, why does this work to create public methods: def extend_method(obj, name, &block) mod = Module.new mod.send(:define_method, name, &block) obj.extend(mod) obj end Sending define_method (at least for me) to an anonymous Module seems to default to "public" mode. This seems a tad inconsistent. All this was on Ruby 1.9.2 on a FreeBSD box. Aaron out.