class Rubulator
Constants
- MATH_CONSTANTS
- MATH_FUNCTIONS
- OPERATORS
- RESULT_VARIABLE
- VARIABLE_PREFIX
- VARIABLE_PREFIX_MATCH_RE
- VERSION
Attributes
variables[RW]
Public Class Methods
calculate(expression)
click to toggle source
# File lib/rubulator.rb, line 34 def self.calculate(expression) Rubulator.new.calculate(expression) end
new()
click to toggle source
# File lib/rubulator.rb, line 28 def initialize @variables = {} result.store(0.0) end
Public Instance Methods
calculate(expression)
click to toggle source
# File lib/rubulator.rb, line 42 def calculate(expression) return unless expression && expression != '' operands = expression.sub(/^\s+/, '').sub(/\s+$/, '').split(/\s+/) result.store(consume(nil, 'initial', operands).to_f) unless operands.empty? raise CalculationError, "Operands #{operands.inspect} left over in expression '#{expression}'" end result.to_f end
constants()
click to toggle source
# File lib/rubulator.rb, line 63 def constants MATH_CONSTANTS.keys.map(&:to_s) end
functions()
click to toggle source
# File lib/rubulator.rb, line 59 def functions MATH_FUNCTIONS end
operators()
click to toggle source
# File lib/rubulator.rb, line 55 def operators ['='] + OPERATORS end
result()
click to toggle source
# File lib/rubulator.rb, line 38 def result @variables[RESULT_VARIABLE] ||= Variable.new(RESULT_VARIABLE) end
variable_names()
click to toggle source
# File lib/rubulator.rb, line 67 def variable_names variables.keys.map { |v| VARIABLE_PREFIX + v } end
Private Instance Methods
consume(operator, name, operands)
click to toggle source
# File lib/rubulator.rb, line 87 def consume(operator, name, operands) raise CalculationError, "Missing #{name} operand for '#{operator || 'main expression'}'" if operands.empty? operand = operands.shift case # rubocop:disable Style/EmptyCaseCondition when operand == '=' variable = consume('=', 'assignment variable', operands) unless variable.is_a?(Variable) raise CalculationError, "Variable expected for 1st operand, found '#{variable}' instead" end value = consume('=', 'value', operands).to_f variable.store(value) when operand.start_with?(VARIABLE_PREFIX) name = operand.sub(VARIABLE_PREFIX_MATCH_RE, '') raise CalculationError, "No variable name provided for '$'" if name == '' @variables[name] ||= Variable.new(name) when operand == ',' consume(',', '1st', operands) consume(',', '2nd', operands) when OPERATORS.include?(operand) op1 = consume(operand, '1st', operands).to_f op2 = consume(operand, '2nd', operands).to_f op1.send(operand.to_sym, op2) when MATH_FUNCTIONS.include?(operand) op1 = consume(operand, 'input', operands).to_f Math.send(operand.to_sym, op1) when MATH_CONSTANTS.include?(operand.downcase.to_sym) MATH_CONSTANTS.fetch(operand.downcase.to_sym) when /[+-]?[0-9][0-9.]*/.match(operand) operand else raise CalculationError, "Unknown argument '#{operand}'" end end