Решение на Осма задача от Веселин Стоянов

Обратно към всички решения

Към профила на Веселин Стоянов

Резултати

  • 3 точки от тестове
  • 0 бонус точки
  • 3 точки общо
  • 18 успешни тест(а)
  • 22 неуспешни тест(а)

Код

class Spreadsheet
attr_accessor :table
def initialize(data = nil)
@table = data.nil? ? [] : Spreadsheet::Helpers::parse_table_data(data)
end
def empty?
@table.empty?
end
def cell_at(cell_index)
row_string = /[A-Z]+/.match(cell_index)
column_string = /\d+/.match(cell_index)
if row_string.nil? or column_string.nil?
raise Error, "Invalid cell index '#{cell_index}'"
end
Spreadsheet::Helpers::cell(row_string[0], column_string[0], self)
end
def [](cell_index)
cell = Spreadsheet::Helpers::cell_evaluate(cell_at(cell_index))
case cell[:type]
when 0 then cell[:data].to_s
when 1 then self[cell[:data]]
when 2 then Spreadsheet::Functions::prepare_function(cell[:data], self)
end
end
private
def cell_direct(x, y)
cell = Spreadsheet::Helpers::cell_evaluate(@table[x][y])
case cell[:type]
when 0 then cell[:data].to_s
when 1 then self[cell[:data]]
when 2 then Spreadsheet::Functions::prepare_function(cell[:data], self)
end
end
public
def to_s
string = '' and @table.each_with_index do |row, x|
row.each_index do |y|
Spreadsheet::GeneratorHelpers::add_row_cell(string, cell_direct(x, y))
end and string.strip!
string << "\n"
end and string.strip
end
class Error < IndexError
end
class Helpers
class << self
def parse_table_data(data)
table, rows = [], data.strip.split("\n")
rows.each do |row|
prepare = row.strip.gsub(/,\s+/m, ",")
table << prepare.gsub(/\s+/m, "\t").split("\t")
end
table.delete_if(&:empty?)
end
def calculate_row_number(row_string)
chars = row_string.chars
count, last = 0, chars.pop
chars.each do |char|
count += ('A'..char).count * 26
end
count += ('A'..last).count
end
def cell(row_string, column_string, i)
x, y = calculate_row_number(row_string), column_string.to_i
x -= 1 unless x == 0
y -= 1 unless y == 0
index = row_string.concat(column_string)
raise Error, "Cell '#{index}' does not exist" unless exists?(x, y, i)
i.table[y][x]
end
def exists?(row, column, instance)
!(instance.table[row].nil? or instance.table[row][column].nil?)
end
def cell_evaluate(raw)
a, b, c = is_number?(raw), is_reference?(raw), is_function?(raw)
return {:type => 0, :data => a} if a
return {:type => 1, :data => b} if b
return {:type => 2, :data => c} if c
{:type => 0, :data => raw}
end
def is_number?(raw, equals = true)
expression = /[-+]?\d*\.?\d+/.match(raw) unless equals
expression = /\=[-+]?\d*\.?\d+/.match(raw) if equals
return false if expression.nil?
number = equals ? expression[0][1..-1] : expression[0]
/\./.match(number).nil? ? number.to_i : number.to_f
end
def is_reference?(raw, equals = true)
expression = /[A-Z]+\d+/.match(raw) unless equals
expression = /\=[A-Z]+\d+/.match(raw) if equals
return false if expression.nil?
equals ? expression[0][1..-1] : expression[0]
end
def is_function?(raw)
expression = /\=\w+\(.+\)/.match(raw)
return false if expression.nil?
expression[0][1..-1]
end
end
end
class Functions
class << self
def prepare_function(function, instance)
data = function.split('(')
function_name = data[0].downcase
function_arguments = data[1][0..-2].split(',').map! { |a| a.strip }
call_function(function_name, function_arguments, instance)
end
def call_function(name, arguments, instance)
arguments = prepare_arguments(arguments, instance)
check_function_name(name) and check_function_arguments(name, arguments)
Spreadsheet::SheetFunctions.new.send(name.to_sym, *arguments)
end
def prepare_arguments(arguments, instance)
arguments.map! do |a|
number = Spreadsheet::Helpers::is_number?(a, false)
reference = Spreadsheet::Helpers::is_reference?(a, false)
(instance[reference] if reference) or number
end
end
def check_function_name(name)
unless SheetFunctions.instance_methods(false).include?(name.to_sym)
raise Spreadsheet::Error, "Unknown function '#{name}'"
end
end
def check_function_arguments(name, arguments)
if ['add', 'multiply'].include?(name)
at_least_expected_error(name, 2, arguments.count)
else
expected_error(name, 2, arguments.count)
end
end
def at_least_expected_error(name, expected, got)
if got < expected
a = "Wrong number of arguments for '#{name}':"
a.concat("expected at least #{expected}, got #{got}")
raise Spreadsheet::Error, a
end
end
def expected_error(name, expected, got)
unless expected == got
a = "Wrong number of arguments for '#{name}':"
a.concat("expected #{expected}, got #{got}")
raise Spreadsheet::Error, a
end
end
end
end
class SheetFunctions
def add(*numbers)
result = 0
numbers.each { |number| result += number.to_f }
(result.to_i == result.to_f ? result.to_i : result.to_f).to_s
end
def multiply(*numbers)
result = 1
numbers.each { |number| result *= number.to_f }
(result.to_i == result.to_f ? result.to_i : result.to_f).to_s
end
def subtract(a, b)
result = a.to_f - b.to_f
(result.to_i == result.to_f ? result.to_i : result.to_f).to_s
end
def divide(a, b)
result = a.to_f / b.to_f
(result.to_i == result.to_f ? result.to_i : result.to_f).to_s
end
def mod(a, b)
result = a.to_f % b.to_f
(result.to_i == result.to_f ? result.to_i : result.to_f).to_s
end
end
class GeneratorHelpers
def self.add_row_cell(string, cell)
string << cell << "\t"
end
end
end

Лог от изпълнението

.........F.F..FF..FFFFF.FF.FF.FFFFFFFF.F

Failures:

  1) Spreadsheet#to_s returns the evaluated spreadsheet as a table
     Failure/Error: expect(sheet.to_s).to eq \
       
       expected: "foo\t10\t2.1\t15\nbar\t11\t2.2\t5\nbaz\t12\t2.3\t27.60"
            got: "foo\t10\t2.1\t15\nbar\t11\t2.2\t5\nbaz\t12\t2.3\t27.599999999999998"
       
       (compared using ==)
       
       Diff:
       @@ -1,4 +1,4 @@
        foo	10	2.1	15
        bar	11	2.2	5
       -baz	12	2.3	27.60
       +baz	12	2.3	27.599999999999998
     # /tmp/d20160121-5693-1bkon5b/spec.rb:50:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Spreadsheet#cell_at returns the raw value of existing cells
     Failure/Error: expect(sheet.cell_at('B1')).to eq '=ADD(2, 2)'
       
       expected: "=ADD(2, 2)"
            got: "=ADD(2,2)"
       
       (compared using ==)
     # /tmp/d20160121-5693-1bkon5b/spec.rb:69:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) Spreadsheet#[] returns the value of existing cells for complex cell indexes
     Failure/Error: expect(sheet['AD1']).to eq 'b'
     Spreadsheet::Error:
       Cell 'AD1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:93:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) Spreadsheet#[] returns the calculated value of formulae cells
     Failure/Error: expect(sheet['B1']).to eq 'ADD(2, 2)'
     Spreadsheet::Error:
       Cell 'B1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:102:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) Spreadsheet#[] raises an exception for less than two arguments passed to ADD
     Failure/Error: expect { Spreadsheet.new('=ADD(1)')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Wrong number of arguments for 'ADD': expected at least 2, got 1/ but nothing was raised
     # /tmp/d20160121-5693-1bkon5b/spec.rb:119:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  6) Spreadsheet#[] adds numbers from cell references and as immediate arguments with ADD
     Failure/Error: expect(sheet['B1']).to eq('55')
     Spreadsheet::Error:
       Cell 'B1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:131:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  7) Spreadsheet#[] adds numbers only from cell references with ADD
     Failure/Error: expect(sheet['D1']).to eq('10')
     Spreadsheet::Error:
       Cell 'D1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:137:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  8) Spreadsheet#[] multiplies numbers with MULTIPLY
     Failure/Error: expect(sheet2['E1']).to eq('120')
     Spreadsheet::Error:
       Cell 'E1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:145:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  9) Spreadsheet#[] raises an exception for less than two arguments to MULTIPLY
     Failure/Error: expect { Spreadsheet.new('=MULTIPLY(1)')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Wrong number of arguments for 'MULTIPLY': expected at least 2, got 1/ but nothing was raised
     # /tmp/d20160121-5693-1bkon5b/spec.rb:149:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  10) Spreadsheet#[] subtracts numbers via cell references
     Failure/Error: expect(sheet['D1']).to eq('4')
     Spreadsheet::Error:
       Cell 'D1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:167:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  11) Spreadsheet#[] raises an exception when SUBTRACT is called with a wrong number of arguments
     Failure/Error: expect { Spreadsheet.new('=SUBTRACT(1)')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Wrong number of arguments for 'SUBTRACT': expected 2, got 1/, got #<ArgumentError: wrong number of arguments (1 for 2)> with backtrace:
         # /tmp/d20160121-5693-1bkon5b/solution.rb:185:in `subtract'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:129:in `call_function'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:123:in `prepare_function'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:26:in `[]'
         # /tmp/d20160121-5693-1bkon5b/spec.rb:171:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-1bkon5b/spec.rb:171:in `block (3 levels) in <top (required)>'
         # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
         # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:171:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  12) Spreadsheet#[] divides numbers via cell references
     Failure/Error: expect(sheet1['C1']).to eq('42')
     Spreadsheet::Error:
       Cell 'C1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:190:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  13) Spreadsheet#[] raises an exception when DIVIDE is called with a wrong number of arguments
     Failure/Error: expect { Spreadsheet.new('=DIVIDE(1)')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Wrong number of arguments for 'DIVIDE': expected 2, got 1/, got #<ArgumentError: wrong number of arguments (1 for 2)> with backtrace:
         # /tmp/d20160121-5693-1bkon5b/solution.rb:190:in `divide'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:129:in `call_function'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:123:in `prepare_function'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:26:in `[]'
         # /tmp/d20160121-5693-1bkon5b/spec.rb:195:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-1bkon5b/spec.rb:195:in `block (3 levels) in <top (required)>'
         # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
         # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:195:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  14) Spreadsheet#[] calculates the modulo of two numbers with MOD via cell references
     Failure/Error: expect(sheet1['C1']).to eq('4')
     Spreadsheet::Error:
       Cell 'C1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:214:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  15) Spreadsheet#[] raises an exception when MOD is called with a wrong number of arguments
     Failure/Error: expect { Spreadsheet.new('=MOD(1)')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Wrong number of arguments for 'MOD': expected 2, got 1/, got #<ArgumentError: wrong number of arguments (1 for 2)> with backtrace:
         # /tmp/d20160121-5693-1bkon5b/solution.rb:195:in `mod'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:129:in `call_function'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:123:in `prepare_function'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:26:in `[]'
         # /tmp/d20160121-5693-1bkon5b/spec.rb:219:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-1bkon5b/spec.rb:219:in `block (3 levels) in <top (required)>'
         # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
         # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:219:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  16) Spreadsheet#[] adds floating point numbers with ADD
     Failure/Error: expect(Spreadsheet.new('10  =ADD(A1, 1.1)')['B1']).to eq '11.10'
     Spreadsheet::Error:
       Cell 'B1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:229:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  17) Spreadsheet#[] subtracts floating point numbers with SUBTRACT
     Failure/Error: expect(Spreadsheet.new('10  =SUBTRACT(A1, 1.1)')['B1']).to eq '8.90'
     Spreadsheet::Error:
       Cell 'B1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:234:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  18) Spreadsheet#[] multiplies floating point numbers with MULTIPLY
     Failure/Error: expect(Spreadsheet.new('10  =MULTIPLY(A1, 1.1)')['B1']).to eq '11'
     Spreadsheet::Error:
       Cell 'B1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:239:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  19) Spreadsheet#[] divides floating point numbers with DIVIDE
     Failure/Error: expect(Spreadsheet.new('10  =DIVIDE(A1, 4)')['B1']).to eq '2.50'
     Spreadsheet::Error:
       Cell 'B1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:244:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  20) Spreadsheet#[] evaluates deeply-nested cell references
     Failure/Error: expect(Spreadsheet.new('10  =ADD(5, A1)  3  =DIVIDE(B1, C1)  =MOD(D1, 4)')['E1']).to eq '1'
     Spreadsheet::Error:
       Cell 'E1' does not exist
     # /tmp/d20160121-5693-1bkon5b/solution.rb:78:in `cell'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:18:in `cell_at'
     # /tmp/d20160121-5693-1bkon5b/solution.rb:22:in `[]'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:250:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  21) Spreadsheet#[] raises an exception for unknown functions
     Failure/Error: expect { Spreadsheet.new('=FOO(42)  100')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Unknown function 'FOO'/, got #<Spreadsheet::Error: Unknown function 'foo'> with backtrace:
         # /tmp/d20160121-5693-1bkon5b/solution.rb:142:in `check_function_name'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:128:in `call_function'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:123:in `prepare_function'
         # /tmp/d20160121-5693-1bkon5b/solution.rb:26:in `[]'
         # /tmp/d20160121-5693-1bkon5b/spec.rb:254:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-1bkon5b/spec.rb:254:in `block (3 levels) in <top (required)>'
         # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
         # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'
     # /tmp/d20160121-5693-1bkon5b/spec.rb:254:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  22) Spreadsheet#[] raises an exception for invalid expressions
     Failure/Error: expect { Spreadsheet.new('=FOO  100')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Invalid expression 'FOO'/ but nothing was raised
     # /tmp/d20160121-5693-1bkon5b/spec.rb:266:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.03365 seconds
40 examples, 22 failures

Failed examples:

rspec /tmp/d20160121-5693-1bkon5b/spec.rb:43 # Spreadsheet#to_s returns the evaluated spreadsheet as a table
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:62 # Spreadsheet#cell_at returns the raw value of existing cells
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:90 # Spreadsheet#[] returns the value of existing cells for complex cell indexes
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:98 # Spreadsheet#[] returns the calculated value of formulae cells
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:118 # Spreadsheet#[] raises an exception for less than two arguments passed to ADD
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:128 # Spreadsheet#[] adds numbers from cell references and as immediate arguments with ADD
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:134 # Spreadsheet#[] adds numbers only from cell references with ADD
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:140 # Spreadsheet#[] multiplies numbers with MULTIPLY
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:148 # Spreadsheet#[] raises an exception for less than two arguments to MULTIPLY
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:164 # Spreadsheet#[] subtracts numbers via cell references
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:170 # Spreadsheet#[] raises an exception when SUBTRACT is called with a wrong number of arguments
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:186 # Spreadsheet#[] divides numbers via cell references
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:194 # Spreadsheet#[] raises an exception when DIVIDE is called with a wrong number of arguments
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:210 # Spreadsheet#[] calculates the modulo of two numbers with MOD via cell references
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:218 # Spreadsheet#[] raises an exception when MOD is called with a wrong number of arguments
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:228 # Spreadsheet#[] adds floating point numbers with ADD
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:233 # Spreadsheet#[] subtracts floating point numbers with SUBTRACT
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:238 # Spreadsheet#[] multiplies floating point numbers with MULTIPLY
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:243 # Spreadsheet#[] divides floating point numbers with DIVIDE
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:249 # Spreadsheet#[] evaluates deeply-nested cell references
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:253 # Spreadsheet#[] raises an exception for unknown functions
rspec /tmp/d20160121-5693-1bkon5b/spec.rb:265 # Spreadsheet#[] raises an exception for invalid expressions

История (1 версия и 0 коментара)

Веселин обнови решението на 11.01.2016 15:12 (преди над 8 години)

+class Spreadsheet
+ attr_accessor :table
+
+ def initialize(data = nil)
+ @table = data.nil? ? [] : Spreadsheet::Helpers::parse_table_data(data)
+ end
+
+ def empty?
+ @table.empty?
+ end
+
+ def cell_at(cell_index)
+ row_string = /[A-Z]+/.match(cell_index)
+ column_string = /\d+/.match(cell_index)
+ if row_string.nil? or column_string.nil?
+ raise Error, "Invalid cell index '#{cell_index}'"
+ end
+ Spreadsheet::Helpers::cell(row_string[0], column_string[0], self)
+ end
+
+ def [](cell_index)
+ cell = Spreadsheet::Helpers::cell_evaluate(cell_at(cell_index))
+ case cell[:type]
+ when 0 then cell[:data].to_s
+ when 1 then self[cell[:data]]
+ when 2 then Spreadsheet::Functions::prepare_function(cell[:data], self)
+ end
+ end
+
+ private
+ def cell_direct(x, y)
+ cell = Spreadsheet::Helpers::cell_evaluate(@table[x][y])
+ case cell[:type]
+ when 0 then cell[:data].to_s
+ when 1 then self[cell[:data]]
+ when 2 then Spreadsheet::Functions::prepare_function(cell[:data], self)
+ end
+ end
+
+ public
+ def to_s
+ string = '' and @table.each_with_index do |row, x|
+ row.each_index do |y|
+ Spreadsheet::GeneratorHelpers::add_row_cell(string, cell_direct(x, y))
+ end and string.strip!
+ string << "\n"
+ end and string.strip
+ end
+
+ class Error < IndexError
+ end
+
+ class Helpers
+ class << self
+ def parse_table_data(data)
+ table, rows = [], data.strip.split("\n")
+ rows.each do |row|
+ prepare = row.strip.gsub(/,\s+/m, ",")
+ table << prepare.gsub(/\s+/m, "\t").split("\t")
+ end
+ table.delete_if(&:empty?)
+ end
+
+ def calculate_row_number(row_string)
+ chars = row_string.chars
+ count, last = 0, chars.pop
+ chars.each do |char|
+ count += ('A'..char).count * 26
+ end
+ count += ('A'..last).count
+ end
+
+ def cell(row_string, column_string, i)
+ x, y = calculate_row_number(row_string), column_string.to_i
+ x -= 1 unless x == 0
+ y -= 1 unless y == 0
+ index = row_string.concat(column_string)
+ raise Error, "Cell '#{index}' does not exist" unless exists?(x, y, i)
+ i.table[y][x]
+ end
+
+ def exists?(row, column, instance)
+ !(instance.table[row].nil? or instance.table[row][column].nil?)
+ end
+
+ def cell_evaluate(raw)
+ a, b, c = is_number?(raw), is_reference?(raw), is_function?(raw)
+ return {:type => 0, :data => a} if a
+ return {:type => 1, :data => b} if b
+ return {:type => 2, :data => c} if c
+ {:type => 0, :data => raw}
+ end
+
+ def is_number?(raw, equals = true)
+ expression = /[-+]?\d*\.?\d+/.match(raw) unless equals
+ expression = /\=[-+]?\d*\.?\d+/.match(raw) if equals
+ return false if expression.nil?
+ number = equals ? expression[0][1..-1] : expression[0]
+ /\./.match(number).nil? ? number.to_i : number.to_f
+ end
+
+ def is_reference?(raw, equals = true)
+ expression = /[A-Z]+\d+/.match(raw) unless equals
+ expression = /\=[A-Z]+\d+/.match(raw) if equals
+ return false if expression.nil?
+ equals ? expression[0][1..-1] : expression[0]
+ end
+
+ def is_function?(raw)
+ expression = /\=\w+\(.+\)/.match(raw)
+ return false if expression.nil?
+ expression[0][1..-1]
+ end
+ end
+ end
+
+ class Functions
+ class << self
+ def prepare_function(function, instance)
+ data = function.split('(')
+ function_name = data[0].downcase
+ function_arguments = data[1][0..-2].split(',').map! { |a| a.strip }
+ call_function(function_name, function_arguments, instance)
+ end
+
+ def call_function(name, arguments, instance)
+ arguments = prepare_arguments(arguments, instance)
+ check_function_name(name) and check_function_arguments(name, arguments)
+ Spreadsheet::SheetFunctions.new.send(name.to_sym, *arguments)
+ end
+
+ def prepare_arguments(arguments, instance)
+ arguments.map! do |a|
+ number = Spreadsheet::Helpers::is_number?(a, false)
+ reference = Spreadsheet::Helpers::is_reference?(a, false)
+ (instance[reference] if reference) or number
+ end
+ end
+
+ def check_function_name(name)
+ unless SheetFunctions.instance_methods(false).include?(name.to_sym)
+ raise Spreadsheet::Error, "Unknown function '#{name}'"
+ end
+ end
+
+ def check_function_arguments(name, arguments)
+ if ['add', 'multiply'].include?(name)
+ at_least_expected_error(name, 2, arguments.count)
+ else
+ expected_error(name, 2, arguments.count)
+ end
+ end
+
+ def at_least_expected_error(name, expected, got)
+ if got < expected
+ a = "Wrong number of arguments for '#{name}':"
+ a.concat("expected at least #{expected}, got #{got}")
+ raise Spreadsheet::Error, a
+ end
+ end
+
+ def expected_error(name, expected, got)
+ unless expected == got
+ a = "Wrong number of arguments for '#{name}':"
+ a.concat("expected #{expected}, got #{got}")
+ raise Spreadsheet::Error, a
+ end
+ end
+ end
+ end
+
+ class SheetFunctions
+ def add(*numbers)
+ result = 0
+ numbers.each { |number| result += number.to_f }
+ (result.to_i == result.to_f ? result.to_i : result.to_f).to_s
+ end
+
+ def multiply(*numbers)
+ result = 1
+ numbers.each { |number| result *= number.to_f }
+ (result.to_i == result.to_f ? result.to_i : result.to_f).to_s
+ end
+
+ def subtract(a, b)
+ result = a.to_f - b.to_f
+ (result.to_i == result.to_f ? result.to_i : result.to_f).to_s
+ end
+
+ def divide(a, b)
+ result = a.to_f / b.to_f
+ (result.to_i == result.to_f ? result.to_i : result.to_f).to_s
+ end
+
+ def mod(a, b)
+ result = a.to_f % b.to_f
+ (result.to_i == result.to_f ? result.to_i : result.to_f).to_s
+ end
+ end
+
+ class GeneratorHelpers
+ def self.add_row_cell(string, cell)
+ string << cell << "\t"
+ end
+ end
+end