attr++, yet another replacement for attr_accessor

There have been many attempts to rewrite attr_accessor to support default values; the best attempt so far (in my opinion) is schmidt’s ‘attr_accessor on steroids’. attr++ is an extension of schmidt’s work to support the initialization of multiple attributes on a single line. The syntax is as follows:

attr_plus_plus {x 20; y "hello"; z 1, 2, 3}

The code above defines getters and setters for the x, y and z attributes and initializes them to the values 20, “hello” and [1, 2, 3] respectively.

attr++ also suppots the old attr_accessor syntax, and you may mix it along with the new attr++ syntax on the same line:

attr_plus_plus :a, :b, :c {a 10; b "goodbye"; z}

In the above, attributes ‘a’ and ‘b’ are initialized to 10 and “goodbye” respectively, and attributes ‘c’ and ‘z’ are unitialized.

The sourcecode for attr++ is given below:

module Attr_plus_plus
    def attr_plus_plus(*argv, &block)

        defaults = {}

        proxy = Object.new        

        eigen = class << proxy; self; end

        eigen.send(:define_method,:method_missing) { |name, *argvt|
            defaults[name] = argvt.size > 1 ? argvt : argvt.first
        }                    

        proxy.instance_eval &block

        defaults.each_pair { |name, default_val|
            attr_writer(name)

            define_method(name) do
                class << self; self; end.class_eval do
                    attr_reader( name )
                end
                if instance_variable_defined? "@#{name}"
                    instance_variable_get( "@#{name}" )
                else
                    instance_variable_set( "@#{name}", default_val )
                end
            end

        }

        (argv-defaults.keys).each { |name|
            raise ArgumentError if !(Symbol === name)

            attr_accessor name
        }

    end

end

UPDATE: I no longer consider attr++ a good solution.

Leave a Reply