I came across an interesting problem today. Say you wanted to have an object where all the instance variables have an associated description. You also wanted to have a 'pretty_print' method, that would print out the description of the variable, along with the value. Here's how the ideal code would look:
class Coordinate < DescribedObject
attr_with_desc :x, "X Coordinate"
attr_with_desc :y, "Y Coordinate"
attr_with_desc :z, "Z Coordinate"
end
coord = Coordinate.new
coord.x = 1
coord.y = 2
coord.z = 3
coord.pretty_print
X Coordinate: 1
Y Coordinate: 2
Z Coordinate: 3
I managed to get that kind of behaviour with this code:
class Module
def attr_with_desc(sym, desc="Instance var")
attr_accessor sym
eval_str = "@@desc[\"@#{sym.id2name}\"] = \"#{desc.to_s}\""
puts(eval_str)
module_eval(eval_str)
end
end
class DescribedObject
@@desc = Hash.new
def pretty_print
instance_variables.each {
>var>
if @@desc.has_key?(var)
puts "#{@@desc[var]}: #{eval(var)}"
else
puts "Instance var #{var}: #{eval(var)}"
end
}
end
end
class Coordinate < DescribedObject
attr_with_desc :x, "X Coord"
attr_with_desc :y, "Y Coord"
attr_with_desc :z, "Z Coord"
end
But there are still a couple of things that I don't think are ideal about this, and wonder if it is possible to fix:
1) Is there a way to add the 'attr_with_desc' method without having to modify the Module class? I'd like to keep it pristine, if possible.
2) Both Module and DescribedObject have to know that the variable is named '@@desc', so if they get out of sync, then that could be bad. Is there a way of grouping all the code into one class/module?
Ben