π Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io π

# lujanfernaud's solution

## to Wordy in the Ruby Track

Published at Mar 10 2019 · 0 comments
Instructions
Test suite
Solution

Parse and evaluate simple math word problems returning the answer as an integer.

What is 5 plus 13?

Evaluates to 18.

Handle large numbers and negative numbers.

## Iteration 2 β Subtraction, Multiplication and Division

Now, perform the other three operations.

What is 7 minus 5?

2

What is 6 multiplied by 4?

24

What is 25 divided by 5?

5

## Iteration 3 β Multiple Operations

Handle a set of operations, in sequence.

Since these are verbal word problems, evaluate the expression from left-to-right, ignoring the typical order of operations.

What is 5 plus 13 plus 6?

24

What is 3 plus 2 multiplied by 3?

15 (i.e. not 9)

## Bonus β Exponentials

If you'd like, handle exponentials.

What is 2 raised to the 5th power?

32

For installation and learning resources, refer to the Ruby resources page.

For running the tests provided, you will need the Minitest gem. Open a terminal window and run the following command to install minitest:

gem install minitest

If you would like color output, you can require 'minitest/pride' in the test file, or note the alternative instruction, below, for running the test file.

Run the tests from the exercise directory using the following command:

ruby wordy_test.rb

To include color from the command line:

ruby -r minitest/pride wordy_test.rb

## Source

Inspired by one of the generated questions in the Extreme Startup game. https://github.com/rchatley/extreme_startup

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### wordy_test.rb

require 'minitest/autorun'
require_relative 'wordy'

# Common test data version: 1.2.0 86d0069
class WordyTest < Minitest::Test
# skip
problem = WordProblem.new("What is 1 plus 1?")
end

skip
problem = WordProblem.new("What is 53 plus 2?")
end

skip
problem = WordProblem.new("What is -1 plus -10?")
end

skip
problem = WordProblem.new("What is 123 plus 45678?")
end

def test_subtraction
skip
problem = WordProblem.new("What is 4 minus -12?")
end

def test_multiplication
skip
problem = WordProblem.new("What is -3 multiplied by 25?")
end

def test_division
skip
problem = WordProblem.new("What is 33 divided by -3?")
end

skip
problem = WordProblem.new("What is 1 plus 1 plus 1?")
end

skip
problem = WordProblem.new("What is 1 plus 5 minus -2?")
end

def test_multiple_subtraction
skip
problem = WordProblem.new("What is 20 minus 4 minus 13?")
end

skip
problem = WordProblem.new("What is 17 minus 6 plus 3?")
end

def test_multiple_multiplication
skip
problem = WordProblem.new("What is 2 multiplied by -2 multiplied by 3?")
end

skip
problem = WordProblem.new("What is -3 plus 7 multiplied by -2?")
message = "You should ignore order of precedence. -3 + 7 * -2 = -8, not #{problem.answer}"
end

def test_multiple_division
skip
problem = WordProblem.new("What is -12 divided by 2 divided by -3?")
end

def test_unknown_operation
skip
problem = WordProblem.new("What is 52 cubed?")
assert_raises(ArgumentError) do
end
end

def test_non_math_question
skip
problem = WordProblem.new("Who is the President of the United States?")
assert_raises(ArgumentError) do
end
end
end

### wordy.rb

require "./question_parser"
require "./operation_evaluator"

class WordProblem
OPERATION = /\d.+?\d/

def initialize(question)
@question = question
end

raise ArgumentError, "Unknown operation" unless question.match(OPERATION)

evaluate_problem
end

private

def evaluate_problem
values = QuestionParser.run(question)

OperationEvaluator.run(values)
end

end

### question_parser.rb

class QuestionParser
OPERATORS = {
"plus"       => "+",
"minus"      => "-",
"multiplied" => "*",
"divided"    => "/"
}.freeze

def self.run(question)
new(question).parse
end

def initialize(question)
@question = question
end

def parse
prepare_question
parse_values
end

private

def prepare_question
@question = question.sub("What is ", "").gsub("by", "").chop.split(" ")
end

def parse_values
question.map do |value|
if OPERATORS.include?(value)
OPERATORS[value].to_sym
else
value.to_i
end
end
end

end

### operation_evaluator.rb

class OperationEvaluator
def self.run(values)
new(values).evaluate
end

def initialize(values)
@values = values
@result = 0
end

def evaluate
until values.empty?
first_item, second_item, third_item = values.slice!(0..2)

result = if third_item
first_item.send(second_item, third_item)
else
result.send(first_item, second_item)
end
end

result
end

private

attr_accessor :values, :result
end