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

# GunPenguin's solution

## to Wordy in the Ruby Track

Published at Nov 26 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``````
``````class WordProblem
def initialize(problem)
@problem = " #{problem} "
end

parse_phrase
end

private
def parse_phrase
raise ArgumentError if numbers.length != actions.length + 1 || numbers.empty? || actions.empty?
nmb = numbers.map(&:to_i)
(1...nmb.length).inject(nmb.first) do |sum, i|
sum = ACTIONS[actions[i - 1]].call(sum, nmb[i])
end
end

def numbers
@numbers ||= problem.scan(/\s(-?\d+)[\s|\?]/).to_a.flatten.map(&:strip)
end

def actions
@actions ||= problem.scan(/\d\s(.*?)\s(?=-?\d)/).flatten.to_a
end

ACTIONS =
{
"plus" => ->(a, b){a + b},
"minus" => ->(a, b){a - b},
"multiplied by" => ->(a, b){a * b},
"divided by" => ->(a, b){a / b},
}
end``````