rpn-calculator 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
- - ">="
|