Created
May 26, 2011 22:22
-
-
Save justinko/994238 to your computer and use it in GitHub Desktop.
Reverse Polish Calculator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module RPN | |
def self.start | |
loop { stack.add(Line.new) } | |
end | |
def self.stack | |
@stack ||= Stack.new | |
end | |
class Stack | |
Error = Class.new(StandardError) | |
OperandOneIndex = -3 | |
OperandTwoIndex = -2 | |
def initialize | |
@lines, @aggregate = [], nil | |
end | |
def add(line) | |
if line.valid? | |
@lines << line | |
output | |
end | |
end | |
def output | |
validate | |
if can_calculate? | |
calculate | |
puts @aggregate | |
end | |
rescue Error => exception | |
puts exception.message | |
end | |
def calculate | |
@aggregate = 0 unless @aggregate | |
if operand_one_in_stack | |
@aggregate += calculated_result | |
else | |
@aggregate = calculated_result | |
end | |
clear_invoked | |
end | |
def can_calculate? | |
not current_line.operand? | |
end | |
def calculated_result | |
current_line.invoke(operand_one, operand_two) | |
end | |
def validate | |
if not operand_one or | |
not operand_two and | |
not current_line.operand? and | |
not full? | |
clear_current_line | |
raise Error.new('Sorry, need another operand.') | |
end | |
end | |
def full? | |
@lines.size > 2 | |
end | |
def current_line | |
@lines.last | |
end | |
def operand_one | |
operand_one_in_stack || @aggregate | |
end | |
def operand_one_in_stack | |
@lines.at(OperandOneIndex) | |
end | |
def operand_two_in_stack | |
@lines.at(OperandTwoIndex) | |
end | |
alias :operand_two :operand_two_in_stack | |
def clear_invoked | |
@lines.delete_at(OperandOneIndex) | |
@lines.delete_at(OperandTwoIndex) | |
clear_current_line | |
end | |
def clear_current_line | |
@lines.pop | |
end | |
end | |
class Line | |
attr_reader :character | |
def initialize | |
@character = gets.chomp | |
__exit if exited? | |
validate | |
end | |
def __exit | |
puts 'goodbye' | |
exit | |
end | |
def exited? | |
character == 'q' | |
end | |
def validate | |
if character[/\s/] | |
puts 'One character at a time, please.' | |
else | |
@valid = true | |
end | |
end | |
def valid? | |
!!@valid | |
end | |
def operand? | |
!!character[/\d/] | |
end | |
def invoke(line1, line2) | |
line1.to_f.send(character, line2.to_f) | |
end | |
def to_f | |
character.to_f | |
end | |
end | |
end | |
RPN.start |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment