I'm a newcomer to dynamic languages and have found quite an incredible
world among Ruby's .call, .method_missing and so on. I've been
playing a bit to learn these features and I'd like comments from more
experienced folks on this bit of code.
#!/bin/ruby
class Triangle
attr_accessor :base, :height, :area
def initialize
@base = 4.0
@height = 5.0
@area = 10.0
@formulas = {
"area" => Proc.new { @base * @height / 2.0 },
"base" => Proc.new { @area * 2 / @height.to_f },
"height" => Proc.new { @area * 2 / @base.to_f }
}
@solve_prefix = "solve_for_"
end
def method_missing(method_id, *args)
method_name = method_id.to_s
if method_name =~ /^#{@solve_prefix}/
variable_name = method_name.gsub(@solve_prefix, "")
solve_for(variable_name)
else
super
end
end
def to_s
"Base: #{@base}\nHeight: #{@height}\nArea: #{@area}\n"
end
private
def solve_for(variable_name)
writer = method( variable_name + "=" ) # look for `xxx=' method
formula = @formulas[variable_name] # get the right formula
value = formula.call # execute it
writer.call( value ) # write its value
end
end
if $0 == __FILE__
t = Triangle.new
puts t
puts "Now changing base and solving for area..."
t.base = 5
t.solve_for_area
puts t
puts "Now changing area and solving for height..."
t.area = 50
t.solve_for_height
puts t
end
The one thing I would have liked to do but have not been able to, was
of using :symbol's instead of strings as keys for the @formulas hash.
The difficulty arose in method_missing when trying to get the :symbol
from the variable (didn't find anything that looks like
"a".to_symbol). I don't know whether it would have made any
difference in performance, though. I don't even know if in terms of
performance it is any good, for that matter. But, as I said, I was
mostly playing. :-)
Massimiliano