# Fluid Interface Calculator

Hey all. So I managed to solve this fluid calculator problem but I’m not especially happy with the solution. I saw other solutions using `method_missing` (e.g. the Calc2 class I include below) but I’m uneasy about `method_missing`. Any suggestions for improvements here? Thanks in advance…

``````
class Calc
attr_accessor :str
def initialize
self.str = ''
self
end

def plus
self.str << '+'
self
end

def minus
self.str << '-'
self
end

def times
self.str << '*'
self
end

def divided_by
self.str << '/'
self
end

%w(zero one two three four five six seven eight nine).each_with_index do |num, index|
define_method "#{num}" do
if self.str == ''
self.str << index.to_s
self
else
eval(self.str << index.to_s)
end
end
end
end

# nice n compact, but method_missing blech
class Calc2

def method_missing(method_name, *args)
@numbers ||= []
@numbers << { one: 1, two: 2, three: 3, four: 4, five: 5, six: 6, seven: 7, eight: 8, nine: 9, plus: "+", minus: "-", times: "*", divided_by: "/" }[method_name]
@numbers.size == 3 ? eval(@numbers.join) : self
end
end

require 'minitest/autorun'

class TestCalc < MiniTest::Unit::TestCase

def setup
@calc1 = Calc.new.four.plus.five
@calc2 = Calc.new.five.plus.four
@calc3 = Calc.new.six.divided_by.two
end

def test_1
assert_equal(9, @calc1)
end

def test_2
assert_equal(9, @calc2)
end

def test_3
assert_equal(3, @calc3)
end
end

``````

Why do you use `self.str` and not `@str`? Or add a private `attr_reader` and use `str`. Also, `str` is not a very good name, I believe.

I know this is not exactly the help you were looking for, but it’s a start.

Thanks for the feedback, I appreciate it. What do you suggest would be a good name for the variable here? I could’t think of anything particularly descriptive.

I 100% agree that the method_missing version is not the way. I prefer the define_method version if for anything, because you don’t have to remember to add in a `respond_to?(method)`.

Please accept this slight revision, bringing the code at least to a more idiomatic ruby form, and while I am at it, I’ll name your state variable something. It IS a string, but what does it represent? A running ticker for a calculation, thus it’s new name: `:calculation_ticker`

``````class Calc
PRIMARY_INTEGERS = %w(zero one two three four five six seven eight nine)

def initialize
@calculation_ticker = String.new
# you cannot override the return of initialize
end

def plus
@calculation_ticker << '+'
self
end

def minus
@calculation_ticker << '-'
self
end

def times
@calculation_ticker << '*'
self
end

def divided_by
@calculation_ticker << '/'
self
end

PRIMARY_INTEGERS.each_with_index do |num, index|
define_method "#{num}" do
if @calculation_ticker == ''
@calculation_ticker << index.to_s
self
else
eval(@calculation_ticker << index.to_s)
end
end
end
end

require 'minitest/autorun'

class TestCalc < MiniTest::Unit::TestCase

def setup
@calc1 = Calc.new.four.plus.five
@calc2 = Calc.new.five.plus.four
@calc3 = Calc.new.six.divided_by.two
end

def test_1
assert_equal(9, @calc1)
end

def test_2
assert_equal(9, @calc2)
end

def test_3
assert_equal(3, @calc3)
end
end
``````

Now that the code is cleaned up a bit I would like to address what I see as a fundamental problem here. Why are you chaining these number string as methods in the first place?

``````calc = Calculator.new
calc.calculate("1 + 1 - 3 +")  #=> -1.0
calc.calculate("5 + 10")       #=> 14.0
calc.clear                     #=> 0.0
calc.calculate("5 + 10")       #=> 15.0
calc.calculate("2")            #=> 17.0 (assumes + when not given)
``````

If was was coding something that was more than a play toy to learn I would code to an interface more like that. What do you think?

What about something like `operation` or `statement`?

@zamith, that is better, thanks. @Dreamr, this was just a problem on Code Wars. I hadn’t heard of fluid interfaces, just thought it might be of general interest here.