rpn-calculator 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/rpn-calculator +1 -1
- data/lib/rpn-calculator.rb +13 -9
- data/lib/rpn-calculator/{io_processor.rb → cli.rb} +6 -6
- data/lib/rpn-calculator/input/parser.rb +7 -7
- data/lib/rpn-calculator/input_processor.rb +32 -0
- data/lib/rpn-calculator/operation/addition.rb +1 -1
- data/lib/rpn-calculator/operation/base.rb +0 -4
- data/lib/rpn-calculator/operation/division.rb +1 -1
- data/lib/rpn-calculator/operation/multiplication.rb +1 -1
- data/lib/rpn-calculator/operation/subtraction.rb +1 -1
- data/lib/rpn-calculator/operation_processor.rb +13 -23
- data/lib/rpn-calculator/result/input.rb +21 -0
- data/lib/rpn-calculator/result/parser.rb +8 -2
- data/lib/rpn-calculator/result/processor.rb +3 -1
- data/lib/rpn-calculator/result/validator.rb +7 -1
- data/lib/rpn-calculator/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72f8ad5a6504d98bb59d0bfcbac6e918dee44743
|
4
|
+
data.tar.gz: e34bb42f596a78a62ee1c94e570c89bc9e3dbd64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f1355c0cd90e80345918f66771eb4311b8a983e1fee0bb09ffdbebfa75623cf337f24f4e410424d434f5d69daa2b5d17e300428c9908e611d5750689391acae
|
7
|
+
data.tar.gz: 55a42ddf85c9efbbf32b34e67acd1bc35d60d3abd4d1dab846e802512e44a0e006d0d35d061eebe85698d6260fe976c6d9a736f606096003b0c287f1bcd06890
|
data/bin/rpn-calculator
CHANGED
data/lib/rpn-calculator.rb
CHANGED
@@ -10,20 +10,24 @@ module RPNCalculator
|
|
10
10
|
'/' => Operation::Division
|
11
11
|
}.freeze
|
12
12
|
ALLOWED_OPERATORS = OPERATION_CLASSES.keys.freeze
|
13
|
-
INVALID_ARGUMENTS_REGEX = /[^\d\s
|
13
|
+
INVALID_ARGUMENTS_REGEX = /[^\d\s\.#{Regexp.quote(ALLOWED_OPERATORS.join)}]/
|
14
|
+
OPERATION_PROCESSOR = OperationProcessor.new(OPERATION_CLASSES).freeze
|
15
|
+
INPUT_PROCESSOR = InputProcessor.new(
|
16
|
+
OPERATION_PROCESSOR,
|
17
|
+
Input::Validator.new(INVALID_ARGUMENTS_REGEX),
|
18
|
+
Input::Parser.new(ALLOWED_OPERATORS)
|
19
|
+
).freeze
|
14
20
|
|
15
21
|
module_function
|
16
22
|
|
17
|
-
def
|
18
|
-
operation_processor = OperationProcessor.new(
|
19
|
-
OPERATION_CLASSES,
|
20
|
-
Input::Validator.new(INVALID_ARGUMENTS_REGEX),
|
21
|
-
Input::Parser.new(ALLOWED_OPERATORS)
|
22
|
-
)
|
23
|
-
|
23
|
+
def start_cli_tool
|
24
24
|
# Here is where we could read and write to another input
|
25
25
|
# using stdin and stdout by default
|
26
|
-
processor =
|
26
|
+
processor = CLI.new(IoInterface::Standard.new, INPUT_PROCESSOR)
|
27
27
|
processor.start
|
28
28
|
end
|
29
|
+
|
30
|
+
def calculate(expression)
|
31
|
+
INPUT_PROCESSOR.process(expression)
|
32
|
+
end
|
29
33
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module RPNCalculator
|
2
|
-
class
|
3
|
-
def initialize(io_interface,
|
2
|
+
class CLI
|
3
|
+
def initialize(io_interface, input_processor)
|
4
4
|
@io_interface = io_interface
|
5
5
|
@input_stack = []
|
6
|
-
@
|
6
|
+
@input_processor = input_processor
|
7
7
|
end
|
8
8
|
|
9
9
|
def start
|
10
|
-
while (
|
11
|
-
processor_result =
|
10
|
+
while (input_expression = io_interface.read_input)
|
11
|
+
processor_result = input_processor.process(input_expression, input_stack)
|
12
12
|
|
13
13
|
if processor_result.valid?
|
14
14
|
print_result_array(processor_result.result)
|
@@ -21,7 +21,7 @@ module RPNCalculator
|
|
21
21
|
|
22
22
|
private
|
23
23
|
|
24
|
-
attr_reader :io_interface, :
|
24
|
+
attr_reader :io_interface, :input_processor, :input_stack
|
25
25
|
|
26
26
|
def print_result_array(result)
|
27
27
|
io_interface.display_output(result.join(' '))
|
@@ -18,19 +18,19 @@ module RPNCalculator
|
|
18
18
|
attr_reader :allowed_operators
|
19
19
|
|
20
20
|
def input_without_whitespace(split_string)
|
21
|
-
split_string.
|
21
|
+
split_string.reject { |e| e == ' ' }
|
22
22
|
end
|
23
23
|
|
24
24
|
def parsed_input_errors(parsed_input)
|
25
25
|
parsed_input.inject([]) do |result, element|
|
26
|
-
result << element unless allowed_operators.include?(element) ||
|
26
|
+
result << element unless allowed_operators.include?(element) || number?(element)
|
27
27
|
result
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def join_consecutive_numbers(split_string)
|
32
32
|
split_string.each_with_index.inject([]) do |result, (element, index)|
|
33
|
-
if index
|
33
|
+
if index.zero? || any_operator?([split_string[index - 1], element])
|
34
34
|
result << element
|
35
35
|
else
|
36
36
|
result[-1] += element
|
@@ -40,14 +40,14 @@ module RPNCalculator
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def any_operator?(elements)
|
43
|
-
elements.any? { |e| !
|
43
|
+
elements.any? { |e| !number_or_period?(e) }
|
44
44
|
end
|
45
45
|
|
46
|
-
def
|
47
|
-
number_string == '.' ||
|
46
|
+
def number_or_period?(number_string)
|
47
|
+
number_string == '.' || number?(number_string)
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
50
|
+
def number?(number_string)
|
51
51
|
true if Float(number_string)
|
52
52
|
rescue ArgumentError
|
53
53
|
false
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RPNCalculator
|
2
|
+
class InputProcessor
|
3
|
+
def initialize(operation_processor, input_validator, input_parser)
|
4
|
+
@input_validator = input_validator
|
5
|
+
@input_parser = input_parser
|
6
|
+
@operation_processor = operation_processor
|
7
|
+
end
|
8
|
+
|
9
|
+
def process(input_expression, previous_operations = [])
|
10
|
+
validator_result = input_validator.validate(input_expression)
|
11
|
+
return invalid_processor_result(validator_result) unless validator_result.valid?
|
12
|
+
|
13
|
+
parser_result = input_parser.parse(input_expression)
|
14
|
+
return invalid_processor_result(parser_result) unless parser_result.valid?
|
15
|
+
|
16
|
+
operation_result = operation_processor.process(
|
17
|
+
previous_operations + parser_result.result
|
18
|
+
)
|
19
|
+
return invalid_processor_result(operation_result) unless operation_result.valid?
|
20
|
+
|
21
|
+
Result::Processor.new(operation_result.result)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :input_validator, :input_parser, :operation_processor
|
27
|
+
|
28
|
+
def invalid_processor_result(result)
|
29
|
+
Result::Processor.new([], result.error)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,44 +1,34 @@
|
|
1
1
|
module RPNCalculator
|
2
2
|
class OperationProcessor
|
3
|
-
def initialize(operation_classes
|
4
|
-
@input_validator = input_validator
|
5
|
-
@input_parser = input_parser
|
3
|
+
def initialize(operation_classes)
|
6
4
|
@operation_classes = operation_classes
|
7
5
|
@operation_symbols = @operation_classes.keys
|
8
6
|
end
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
validator_result = input_validator.validate(input)
|
13
|
-
return Result::Processor.new([], validator_result.error) unless validator_result.valid?
|
14
|
-
|
15
|
-
parser_result = input_parser.parse(input)
|
16
|
-
return Result::Processor.new([], parser_result.error) unless parser_result.valid?
|
17
|
-
|
18
|
-
process_operations(previous_operations + parser_result.parsed_elements)
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
attr_reader :input_validator, :input_parser, :operation_classes, :operation_symbols
|
24
|
-
|
25
|
-
def process_operations(operations)
|
26
|
-
result_stack = operations.inject([]) do |stack, element|
|
8
|
+
def process(parsed_expression)
|
9
|
+
result_stack = parsed_expression.inject([]) do |stack, element|
|
27
10
|
if operation_symbols.include?(element)
|
28
|
-
result = operation_classes.fetch(element)
|
29
|
-
.operate([stack.pop, stack.pop].reverse)
|
11
|
+
result = operation_classes.fetch(element).operate(stack.pop(2))
|
30
12
|
return invalid_processor_result(result) unless result.valid?
|
31
13
|
stack.push(result.result)
|
32
14
|
else
|
33
|
-
stack.push(element)
|
15
|
+
stack.push(as_float(element))
|
34
16
|
end
|
35
17
|
stack
|
36
18
|
end
|
37
19
|
Result::Processor.new(result_stack)
|
38
20
|
end
|
39
21
|
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :operation_classes, :operation_symbols
|
25
|
+
|
40
26
|
def invalid_processor_result(result)
|
41
27
|
Result::Processor.new([], result.error)
|
42
28
|
end
|
29
|
+
|
30
|
+
def as_float(num_string)
|
31
|
+
Float(num_string)
|
32
|
+
end
|
43
33
|
end
|
44
34
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RPNCalculator
|
2
|
+
module Result
|
3
|
+
class Input
|
4
|
+
def initialize
|
5
|
+
raise 'Can not instantiate abstract class'
|
6
|
+
end
|
7
|
+
|
8
|
+
def valid?
|
9
|
+
raise 'must implement in subclass'
|
10
|
+
end
|
11
|
+
|
12
|
+
def error
|
13
|
+
raise 'must implement in subclass'
|
14
|
+
end
|
15
|
+
|
16
|
+
def result
|
17
|
+
raise 'must implement in subclass'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'rpn-calculator/result/input'
|
2
|
+
|
1
3
|
module RPNCalculator
|
2
4
|
module Result
|
3
|
-
class Parser
|
5
|
+
class Parser < Input
|
4
6
|
def initialize(parsed_elements = [], invalid_elements = [])
|
5
7
|
@parsed_elements = parsed_elements
|
6
8
|
@invalid_elements = invalid_elements
|
@@ -14,10 +16,14 @@ module RPNCalculator
|
|
14
16
|
"Invalid operators or numbers: #{invalid_element_list}" unless valid?
|
15
17
|
end
|
16
18
|
|
17
|
-
|
19
|
+
def result
|
20
|
+
@parsed_elements
|
21
|
+
end
|
18
22
|
|
19
23
|
private
|
20
24
|
|
25
|
+
attr_reader :invalid_elements
|
26
|
+
|
21
27
|
def invalid_element_list
|
22
28
|
invalid_elements.join(', ')
|
23
29
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'rpn-calculator/result/input'
|
2
|
+
|
1
3
|
module RPNCalculator
|
2
4
|
module Result
|
3
|
-
class Validator
|
5
|
+
class Validator < Input
|
4
6
|
def initialize(invalid_characters = [])
|
5
7
|
@invalid_characters = invalid_characters
|
6
8
|
end
|
@@ -13,6 +15,10 @@ module RPNCalculator
|
|
13
15
|
"Invalid characters: #{invalid_character_list}" unless valid?
|
14
16
|
end
|
15
17
|
|
18
|
+
def result
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
|
16
22
|
private
|
17
23
|
|
18
24
|
attr_reader :invalid_characters
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rpn-calculator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mario Celi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -34,17 +34,19 @@ extra_rdoc_files: []
|
|
34
34
|
files:
|
35
35
|
- bin/rpn-calculator
|
36
36
|
- lib/rpn-calculator.rb
|
37
|
+
- lib/rpn-calculator/cli.rb
|
37
38
|
- lib/rpn-calculator/input/parser.rb
|
38
39
|
- lib/rpn-calculator/input/validator.rb
|
40
|
+
- lib/rpn-calculator/input_processor.rb
|
39
41
|
- lib/rpn-calculator/io_interface/abstract.rb
|
40
42
|
- lib/rpn-calculator/io_interface/standard.rb
|
41
|
-
- lib/rpn-calculator/io_processor.rb
|
42
43
|
- lib/rpn-calculator/operation/addition.rb
|
43
44
|
- lib/rpn-calculator/operation/base.rb
|
44
45
|
- lib/rpn-calculator/operation/division.rb
|
45
46
|
- lib/rpn-calculator/operation/multiplication.rb
|
46
47
|
- lib/rpn-calculator/operation/subtraction.rb
|
47
48
|
- lib/rpn-calculator/operation_processor.rb
|
49
|
+
- lib/rpn-calculator/result/input.rb
|
48
50
|
- lib/rpn-calculator/result/operation.rb
|
49
51
|
- lib/rpn-calculator/result/parser.rb
|
50
52
|
- lib/rpn-calculator/result/processor.rb
|
@@ -62,7 +64,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
62
64
|
requirements:
|
63
65
|
- - ">="
|
64
66
|
- !ruby/object:Gem::Version
|
65
|
-
version:
|
67
|
+
version: 1.9.3
|
66
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
69
|
requirements:
|
68
70
|
- - ">="
|