First off, I'm not talking about bad breath. Rather, I'm talking about scope in ruby.
The previous entry, attributes with default values (on steroids), had an issue with it, due to the way in which ruby defines scope (as of 1.8, scope is supposed to change in 1.9). Here's the "broken" code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Object def self.attribute(*arg,&block) (name,value) = arg self.send(:define_method, name) { if instance_variables.include? "@#{name}" self.instance_eval "@#{name}" else if block_given? instance_eval &block else value end end } self.send(:define_method, "#{name}="){ |value| self.instance_eval "@#{name} = value" } end end |
The problem is with the value variable. Because it is set within the Object#attribute method, the reference to value is the same throughout the entire method. So, when we change value, by setting it in the "setter" method, we are changing it for every instance of the variable. In addition, since we're setting it at the class level, any object which belongs to the class for which we are setting it has the same value. The solution is pretty simple:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def self.attribute(*arg,&block) (name, default) = arg self.send(:define_method, name) { if instance_variables.include? "@#{name}" self.instance_eval "@#{name}" else if block_given? instance_eval &block else default end end } self.send(:define_method, "#{name}="){ |value| self.instance_eval "@#{name} = value" } end end |
Notice that I'm using default now within the accessor method. This removes the issue with value, and it now works properly.
