attributes with default values (on steroids) 0

Posted by Matt Williams

EDITED to fix bug: See Scope Kills for details.

While ruby has attr_accessor there's no good way to specify a default value which comes as part of the stock language. Thank goodness for metaprogramming. Based off of Create getter and setter on a valorized variable, I have a solution which takes either a value or a block as the default. It's based, in part, upon my solution for Ruby Quiz #67 Metakoans.

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,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

Given the following class:

1
2
3
4
5
6

class Foo
  attribute :bar
  attribute(:fud) {instance_variables.include?("@bar") ? @bar : ' '}
  attribute :fi, 10
end

we can test as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

>>   t=Foo.new
=> #<Foo:0xb7b9cadc>
>> t.bar
=> nil
>> t.fud
=> " "
>> t.fi
=> 10
>> t.bar = 5
=> 5
>> t.fud
=> 5
>> t.fud = 20
=> 20
>> t.fud
=> 20
>> 

I imagine it can be simplified some more, but it works, and I think it's kinda nifty.....

Comments

Leave a response

Comment