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
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
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
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.
Top comments (2)
Just to add approach that I wrote before reading your answers (your is better, but, well, it was just for fun :)
That's why I love Ruby! It allows you to solve a problem in a large number of ways.