Skip to content

Instantly share code, notes, and snippets.

@stulentsev
Created September 26, 2015 10:15
Show Gist options
  • Save stulentsev/b270bce4be67bc1a96ae to your computer and use it in GitHub Desktop.
Save stulentsev/b270bce4be67bc1a96ae to your computer and use it in GitHub Desktop.
Recursive Excel-like evaluator
require 'awesome_print'
require_relative 'table_evaluator.rb'
def print_test(label, expectation)
evaluator = TableEvaluator.new
actual = yield(evaluator)
if actual == expectation
puts "#{label}: PASS"
else
puts "#{label}: FAIL (actual value was #{actual.inspect})"
end
end
print_test('testing [1]cost = 180', 180) { |te| te.cost_of(1) }
# console output
# expanding [2]quantity + [3]value
# expanding 3
# expanding 7
# => 3 + 7
# expanding [2]cost
# expanding 3
# expanding 6
# => 18
# testing [1]cost = 180: PASS
class TableEvaluator
def initialize
end
def cost_of(row_id)
quantity_of(row_id) * value_of(row_id)
end
def quantity_of(row_id)
eval(expand_references((rows[row_id][:quantity])))
end
def value_of(row_id)
eval(expand_references(rows[row_id][:value]))
end
def rows
@rows ||= ROWS.each_with_object({}) do |row, memo|
memo[row[:id]] = row
end
end
private
def eval(expr)
::Kernel.eval(expr.to_s)
end
def expand_references(expr)
puts "expanding #{expr}"
return expr unless expr.is_a?(String)
res = expr.gsub(REFERENCE_REGEX) do |reference|
match = reference.match(REFERENCE_REGEX)
get_value(match[:row_id].to_i, match[:column].to_sym)
end
puts "=> #{res}"
res
end
def get_value(row_id, column)
case column
when :quantity
quantity_of(row_id)
when :value
value_of(row_id)
when :cost
cost_of(row_id)
else
fail "unknown column: #{column.inspect}"
end
end
REFERENCE_REGEX = /\[(?<row_id>\d+)\](?<column>quantity|value|cost)/
ROWS = [
{
id: 1,
name: 'Regulating',
quantity: '[2]quantity + [3]value',
value: '[2]cost',
},
{
id: 2,
name: 'Kerbs',
quantity: 3,
value: 6,
},
{
id: 3,
name: 'Bricks',
quantity: 9,
value: 7,
},
{
id: 4,
name: 'Sausages',
quantity: '[3]cost',
value: '3',
},
{
id: 5,
name: 'Bamboo',
quantity: '[4]quantity',
value: '[7]cost',
},
{
id: 6,
name: 'Clams',
quantity: '[4]quantity',
value: nil,
},
{
id: 7,
name: 'Hardcore',
quantity: '[3]quantity * 0.5',
value: 12,
},
{
id: 8,
name: 'Beetles',
quantity: '[6]quantity * [4]value',
value: '[2]value',
},
]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment