DEV Community

Ivan Ilyukhin
Ivan Ilyukhin

Posted on • Originally published at evanilukhin.com

Ruby Interview Tasks - Simple word calculator

Recently during an interview live coding session, I got a pretty interesting task:

# Make this code working
one.plus.two.equal # =>> 3
one.minus.three.equal # => -2
Enter fullscreen mode Exit fullscreen mode

I was tired and tried to solve it by adding some method to a String instance methods like there:

one = '1'

def one.plus
  temp_plus = "#{self}+"

  def temp_plus.two
    temp_plus_two = "#{self}2"

    def temp_plus_two.equal
      eval(self)
    end

    temp_plus_two
  end

  temp_plus
end

def one.minus
  temp_minus = "#{self}-"

  def temp_minus.three
    temp_minus_three = "#{self}3"

    def temp_minus_three.equal
      eval(self)
    end

    temp_minus_three
  end

  temp_minus
end

# Yes, it works
pp one.plus.two.equal # => 3
pp one.minus.three.equal => -2
Enter fullscreen mode Exit fullscreen mode

Looks bulky and terrible. Yes, Ruby allows to do this, but it is natural monkey patching, and I would not be used similar construction in real projects.
Six hours later, when I woke up, I realized that there is exist a significantly more straightforward and elegant solution. It’s just a realization of the method chaining pattern:

class Evaluator
  class << self
    def operation(name, expression_part)
      define_method(name) do
        return_new_instance expression_part
      end
    end
  end

  operation :plus,  '+'
  operation :minus, '-'
  operation :two,   '2'
  operation :three, '3'

  def initialize(expression = '')
    @expression = expression
  end

  def equal
    eval(@expression)
  end

  private

  def return_new_instance(expression_part)
    @expression = "#{@expression}#{expression_part}"
    self.class.new(@expression)
  end
end

one = Evaluator.new('1')
pp one.plus.two.equal # => 3
pp one.minus.three.equal # => -2
Enter fullscreen mode Exit fullscreen mode

Pretty neat!
This task is well for estimating the level of a developer. Specifically, the knowledge of method chaining pattern(interviewee mentioned it or just used it), how to use metaprogramming and awareness about monkey patching and bad solutions.

Discussion (2)

Collapse
decentralizuj profile image
decentralizuj • Edited

Just to add approach that I wrote before reading your answers (your is better, but, well, it was just for fun :)

  class One
    def initialize
      @num = 1
    end

    def plus
      @opt = :add
      return self
    end

    def minus
      @opt = :rmw
      return self
    end

    def two
      case @opt
        when :add then @num += 2
        when :rmw then @num -= 2
      end
      return self
    end

    def three
      case @opt
        when :add then @num += 3
        when :rmw then @num -= 3
      end
      return self
    end

    def equal
      num  = @num
      @num = 1
      return num
    end
  end

  one = One.new
  one.plus.two.equal    =>  3
  one.minus.three.equal => -2
Enter fullscreen mode Exit fullscreen mode
Collapse
evanilukhin profile image
Ivan Ilyukhin Author

That's why I love Ruby! It allows you to solve a problem in a large number of ways.