Friday, May 23, 2008

Dynamically adding methods to objects

Let's say you have a class named Color, which defines instance methods red, green and blue, which return the corresponding color component (0 to 255). You have an instance of Color called santorin, among other instances. You just calculated a transparency component for this color and want to add that in. Problem is, the Color class doesn't have a transparency attribute. We don't want transparency in any other instance of this class anyway. The proper way to do this would probably be to subclass Color as TransparentColor and add a transparency attribute there. But that's more code than we want for this simple task. You could just define an extra method for the santorin instance:
def santorin.transparency
  5
end
This works, and will return 5 when you call it. But our calculated transparency is in a variable called trans, so we need to do this:
def santorin.transparency
  trans
end
Now that doesn't work, because when you try to call this method, you'll get this:
NameError: undefined local variable or method `trans' for ...
  ...
The problem is that trans is evaluated when you call the method, not when you define it. The quickest solution here is to use eval to force evaluation of the variable at definition time:
eval "def santorin.transparency() #{trans}; end"