rpn_party 0.0.1
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 +7 -0
- data/bin/rpn_party +11 -0
- data/lib/rpn_party/calculator.rb +90 -0
- data/lib/rpn_party/cli.rb +40 -0
- data/lib/rpn_party/errors.rb +7 -0
- metadata +48 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d32325fb22bab5f4a740c85edf8209a0356975ff
|
4
|
+
data.tar.gz: 9995eb11a6c13ed816b470b80aa9e096351c7550
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1e73c6c03d61a4b606cfc3411cbe920e9759ca9ec0b599a53499c6fd5d9248817891c3e7392de2ae78ba74790609bbd9b51316340bc8154a8ad82db4cb6cc63c
|
7
|
+
data.tar.gz: 2d8465d85f678ffa20e7446880ce1a3c606a7f040418765650dd9e80f3026082beeaf50f92ac38aef5bb9b389a39889c0948e7b6bde49b6c4ffc6092b1666e02
|
data/bin/rpn_party
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Adds this gem's lib path the the Ruby load path. This allows
|
4
|
+
# us to test RPNParty::CLI without the gem being installed.
|
5
|
+
# Borrowed from https://stackoverflow.com/a/5294358/918507
|
6
|
+
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
7
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
8
|
+
|
9
|
+
require 'rpn_party/cli'
|
10
|
+
|
11
|
+
RPNParty::CLI.new
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'rpn_party/errors'
|
2
|
+
|
3
|
+
module RPNParty
|
4
|
+
class Calculator
|
5
|
+
def initialize(calculation = '')
|
6
|
+
@stack = []
|
7
|
+
evaluate(calculation)
|
8
|
+
end
|
9
|
+
|
10
|
+
def result
|
11
|
+
if @stack.empty?
|
12
|
+
nil
|
13
|
+
elsif @stack.length == 1
|
14
|
+
@stack[0]
|
15
|
+
else
|
16
|
+
@stack
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def evaluate(calculation)
|
21
|
+
calculation.split.map do |token|
|
22
|
+
case token
|
23
|
+
when /\A(?:\-)?\d+(?:\.\d+)?\z/
|
24
|
+
@stack.push token.to_f
|
25
|
+
when /\A\+\z/
|
26
|
+
add
|
27
|
+
when /\A\-\z/
|
28
|
+
subtract
|
29
|
+
when /\A\*\z/
|
30
|
+
multiply
|
31
|
+
when /\A\/\z/
|
32
|
+
divide
|
33
|
+
else
|
34
|
+
raise UnrecognizedInputError,
|
35
|
+
"Unrecognized value/operator: '#{token}'. Valid inputs are numbers (0, 1, 2.5, -3, etc.), or '+', '-', '*', '/'."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def add
|
43
|
+
raise_if_insufficient_operands :addition
|
44
|
+
|
45
|
+
first_value, second_value = @stack.pop(2)
|
46
|
+
@stack.push(first_value + second_value)
|
47
|
+
end
|
48
|
+
|
49
|
+
def subtract
|
50
|
+
raise_if_insufficient_operands :subtraction
|
51
|
+
|
52
|
+
first_value, second_value = @stack.pop(2)
|
53
|
+
@stack.push(first_value - second_value)
|
54
|
+
end
|
55
|
+
|
56
|
+
def multiply
|
57
|
+
raise_if_insufficient_operands :multiplication
|
58
|
+
|
59
|
+
first_value, second_value = @stack.pop(2)
|
60
|
+
@stack.push(first_value * second_value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def divide
|
64
|
+
raise_if_insufficient_operands :division
|
65
|
+
raise_if_second_value_is_zero
|
66
|
+
|
67
|
+
first_value, second_value = @stack.pop(2)
|
68
|
+
@stack.push(first_value / second_value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def raise_if_second_value_is_zero
|
72
|
+
return unless @stack.last.zero?
|
73
|
+
|
74
|
+
raise ZeroDivisionError,
|
75
|
+
"Cannot divide #{@stack[-2]} by 0."
|
76
|
+
end
|
77
|
+
|
78
|
+
def raise_if_insufficient_operands(operation)
|
79
|
+
return if @stack.length >= 2
|
80
|
+
|
81
|
+
message = if @stack.empty?
|
82
|
+
"Could not perform #{operation}. At least two values are required, but there are none."
|
83
|
+
else
|
84
|
+
"Could not perform #{operation}. At least two values are required, but there is only one: '#{@stack.first}'."
|
85
|
+
end
|
86
|
+
raise InsufficientOperandsError,
|
87
|
+
message
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rpn_party/calculator'
|
2
|
+
|
3
|
+
module RPNParty
|
4
|
+
class CLI
|
5
|
+
def initialize
|
6
|
+
@calc = RPNParty::Calculator.new
|
7
|
+
|
8
|
+
puts 'Welcome to RPNParty!'
|
9
|
+
print '> '
|
10
|
+
|
11
|
+
loop do
|
12
|
+
input = gets
|
13
|
+
|
14
|
+
if input.nil? || input.chomp == 'q'
|
15
|
+
puts 'Goodbye!'
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
|
19
|
+
begin
|
20
|
+
@calc.evaluate(input.chomp)
|
21
|
+
rescue RPNParty::UnrecognizedInputError => error
|
22
|
+
puts error.message
|
23
|
+
rescue ZeroDivisionError => error
|
24
|
+
puts error.message
|
25
|
+
rescue RPNParty::InsufficientOperandsError => error
|
26
|
+
puts error.message
|
27
|
+
end
|
28
|
+
|
29
|
+
if @calc.result.nil?
|
30
|
+
puts 'nil'
|
31
|
+
elsif @calc.result.is_a? Array
|
32
|
+
puts @calc.result.join(', ')
|
33
|
+
else
|
34
|
+
puts @calc.result
|
35
|
+
end
|
36
|
+
print '> '
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rpn_party
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Richard Jones
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-24 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: An interactive Reverse Polish Notation calculator for the command line
|
14
|
+
email: rico@toasterlovin.com
|
15
|
+
executables:
|
16
|
+
- rpn_party
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/rpn_party
|
21
|
+
- lib/rpn_party/calculator.rb
|
22
|
+
- lib/rpn_party/cli.rb
|
23
|
+
- lib/rpn_party/errors.rb
|
24
|
+
homepage: https://github.com/toasterlovin/rpn_party
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
metadata: {}
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 2.6.12
|
45
|
+
signing_key:
|
46
|
+
specification_version: 4
|
47
|
+
summary: RPN Party
|
48
|
+
test_files: []
|