I have three values (foo,bar,bad) and based on which one I pass into a function I want to use the other two.
For example calling self.method(foo)
would result in something like this with foo
being undefined.
def method
self.foo = 180 - self.bar - self.bad
end
I can do it with a simple if-elsif-else setup, but is there a better (more idiomatic) way?
Update for clarity:
Here's what one suggestion might look like in production:
def solve_angles(missing)
angles = 180 - [ A, B, C ].reject { |e| e == missing }.inject(:+)
end
called via @triangle.solve_angles(self.C)
or even '@triangle.solve_angles("C") would be possible.
You don't need to specify which angle you're solving for; it's implicit in the problem's definition. If you start with something like this (anything resembling error handling elided):
class Triangle
def initialize h
h.keys.each { |key| instance_variable_set "@#{key}".to_sym, h[key] }
end
def to_s
"a=#{@a}, b=#{@b}, c=#{@c}"
end
def solve
angle = instance_variables.inject(180) { |v, a| v -= instance_variable_get(a) }
[:@a, :@b, :@c].each {|s| instance_variable_set(s, angle) unless instance_variable_defined? s }
self
end
end
Then:
pry(main)> t = Triangle.new :a => 20, :c => 30
=> a=20, b=, c=30
pry(main)> t.solve
=> a=20, b=130, c=30
pry(main)>
You could also return/indicate which angle was actually solved for, if necessary.
This doesn't actually avoid an if
statement, which was your specific question. It eliminates the need to explicitly spell each one of them out, which I took as the intent of the question.
If you truly need to "solve for", you could do add:
def solve_for sym
solve
instance_variable_get("@#{sym}".to_sym)
end
Technically, you could solve only after determining the value isn't set, but meh.
> t = Triangle.new :a => 20, :c => 30
=> a=20, b=, c=30
> t.solve_for :b
=> 130
> t
=> a=20, b=130, c=30
> t = Triangle.new :a => 20, :c => 30
=> a=20, b=, c=30
> t.solve_for :a
=> 20
> t
=> a=20, b=130, c=30