Ruby Weekly is a weekly newsletter covering the latest Ruby and Rails news.

Applying conditions to attribute setters

By Peter Cooper / May 26, 2006

An anonymous commenter contributed a cute Ruby example on this post talking about Java's verbosity. The original poster lamented on how much code you have to write to create some basic accessors on a Java class.

With Ruby you can simply use attr, attr_accessor, attr_reader and attr_writer to create various types of accessors with a single line of code. They lack logic though, and you need to write your own accessors from scratch if you want even basic logic included. Mr. Anonymous came up with a solution, which I've slightly changed to produce this:

class Class
        def attr(name, &conditions)
                varname = '@' + name.to_s
                conditions ||= lambda {true}
                define_method(name) do
                        instance_variable_get(varname)
                end

                define_method(name.to_s + '=') do |val|
                        raise ArgumentError, "#{name} can't be #{val}" unless conditions.call(val)
                        instance_variable_set(varname, val)
                end
        end
end

class AClass
        attr(:my_int) { |i| i >= 0 }
        attr(:my_string)
end

With this code, 'attr' has been extended to support accepting a code block as a parameter. When you try to set my_int on an AClass object, if i >= 0 is true, my_int is set. If it's under zero, Ruby throws an exception. This is great if you need to make sure the data is totally safe.

Comments

  1. Jonathan Conway says:

    Cool piece of code, though I think people should be warned about the dangers of accessors/mutators as far as encapsulation is concerned.

    When I left the land of Java and it was no longer expected of me to write code that needed to be a "bean" I found it a joyful day. Exposing the interals of an objects state via accessors and mutators leads to bad OO design and not to mention an extremely unhealthy amount of coupling. Its a dark path I tell thee!! *runs off jibbering like a mad man*

Other Posts to Enjoy

Twitter Mentions