As I explained in my recent post about metaprogramming, implementing a JavaBean is a task that would greatly benefit from metaprogramming. Here, I illustrate how this would be done in Ruby. Note that the resulting code has little interest for Ruby as JavaBeans are a Java idiom. I hope however that it demonstrates my purpose. Let’s dive straight into the code:
class RubyBean
def initialize
@listeners = []
end
def register_listener(l)
@listeners.push(l) unless @listeners.include?(l)
end
def unregister_listener(l)
@listeners.delete(l)
end
These methods implement the management of the property change listeners on the bean. It is a subset of what java.beans.PropertyChangeSupport provides. Now comes the most interesting part:
def RubyBean.property(*properties)
properties.each { |property|
class_eval(%Q[
def #{property}
@#{property}
end
def #{property}=(value)
old_value = @#{property}
return if (value == old_value)
@listeners.each { |listener|
listener.property_changed(:#{property},
old_value,
value)
}
@#{property} = value
end
])
}
end
end
I define property as a class method that takes a variable number of arguments. For each of its arguments, property dynamically creates and adds to the RubyBean class, a getter and a setter to the bean. This follows the Ruby conventions for accessors: the getter is simply the property name, the setter is the property name followed by the equal sign. The setter also notifies the registered property change listeners. Note that in Ruby, you would use the attr_accessor method to create these accessors.
Now, writing a bean is as simple as:
class TestBean < RubyBean property :name, :firstname end
Simple, no? Finally, here is how this code could be used:
class LoggingPropertyChangeListener
def property_changed(property, old_value, new_value)
print property, " changed from ",
old_value, " to ",
new_value, "\n"
end
end
test = TestBean.new
listener = LoggingPropertyChangeListener.new
test.register_listener(listener)
test.name = "Parker"
test.firstname = "Charlie"
test.firstname = "Maceo"
test.unregister_listener(listener)
and the output it generates:
name changed from nil to Parker firstname changed from nil to Charlie firstname changed from Charlie to Maceo
Do not hesitate to comment if you have any query, suggestion, critic or simply if you want to say Hi!
- Update 06/03/2006: see RubyBeans revisited for a better implementation.
- Update 01/05/2007: see RubyBeans revisited (again) – Closures in Ruby for a more elegant solution.

Saturday, March 4th, 2006 at 2:57
Nice Example… how would you create static methods using metaprogramming? For example a class method that gives the number of properties that have been assigned.
test = TestBean.new
test.name = “parker”
test2 = TestBean.new
test2.name = “lewis”
TestBean.name_count # => 2
TestBean.firstname_count # => 0
You can use another example if you want. It was the most trivially one that I could come up with.
Saturday, March 4th, 2006 at 3:12
Nithin,
you could do it this way:
def RubyBean.property(*properties) properties.each { |property| class_eval(%Q[ @@#{property}_count = 0 def #{property} @#{property} end def #{property}=(value) oldValue = @#{property} return if (value == oldValue) @listeners.each { |listener| listener.propertyChanged(:#{property}, oldValue, value) } @#{property} = value @@#{property}_count += 1 end def self.#{property}_count @@#{property}_count end ]) } endNote that there are more elegant ways than using
class_evalto do metaprogramming (see this post).Have a look at this article from Why-the-lucky-stiff. He is a Ruby Legend!
Monday, March 6th, 2006 at 0:52
[...] Today, I refactored the Rubybeans code to illustrate more metaprogramming methods in Ruby. Since the original article is mainly intended for Java developers, I have decided to explain the code with more details (you probably won’t need to have a look at a Ruby book). [...]
Thursday, June 1st, 2006 at 8:42
[...] Ruby is a highly mutable language. Objects and methods are first-class types that can be manipulated as easily as a string or an integer. Objects can examine themselves (called “reflection”) or modify themselves by adding or changing methods. This capability is what makes Rails so kick-ass. It’s also why everyone’s talking about Ruby for domain specific languages (DSLs). [...]
Wednesday, October 18th, 2006 at 17:33
[...] Metaprogramming [...]
Thursday, March 15th, 2007 at 7:20
Nice example of meta-programming. Don’t your class variables in your answer to Nithin’s question actually count the number of times a property is assigned a different value, not the number of properties that have that property assigned?
I’d like to see more real-world examples like this. For example, a meta-class that can become a ADT where even the operators are meta-defined.
Thursday, March 15th, 2007 at 20:41
Hi Milburn,
you are quite right!
Moving the
@@#{property}_count += 1line up to the beginning of the method, just afterdef #{property}=(value)solves the problem.Thanks for spotting this and for your comments!
Friday, April 27th, 2007 at 14:04
I think the property should sit in a proxy-object, that does inform the listeners of its change. In your example, one could directly change the properties value from within the class without a call to the property_changed method.
This would be a concern for me. Isn’t it a concern for you?
Tuesday, May 1st, 2007 at 12:52
[...] comment by Thomas Geis on my first RubyBeans post lead me to another rework of the RubyBeans metaprogramming [...]