Решение на Осма задача от Димитър Терзиев

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

Към профила на Димитър Терзиев

Резултати

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

Код

FIRST_LETTER = "A"
ALPHABET_LETTERS = 26
INVALID_INDEX = "Invalid cell index '%{index}'"
NO_CELL = "Cell '%{index}' does not exist"
UNKNOWN_FUNCTION = "Unknown function '%{name}'"
#ARGUMENTS_NUMBER = "Wrong number of arguments for %{name}: "
#ARGUMENTS_NUMBER += "expected at least %{expected}, got %{got}"
class Spreadsheet
def initialize(table_string = "")
rows = table_string.split("\n").reject(&:empty?)
@table = rows.map{|row| row.split(/ +/).reject(&:empty?)}
end
def empty?
@table.empty?
end
def cell_at(cell_index)
invalid_index = cell_index !~ /^[A-Z]+\d+$/
raise(Error.new, INVALID_INDEX % {index: cell_index}) if invalid_index
letters, number = cell_index.scan(/\d+|\D+/)
invalid_cell = @table[number.to_i - 1][letter_index(letters)].nil?
raise(Error.new, NO_CELL % {index: cell_index}) if invalid_cell
@table[number.to_i - 1][letter_index(letters)]
end
def [](cell_index)
Format.format_result(evaluate(cell_at cell_index)).to_s
end
def evaluate(raw_input)
case raw_input
when /^= *[A-Z]+\d+/ then self[((/[A-Z]+\d+/.match raw_input).to_s)]
when /^= *\d/ then raw_input.split(/^= */).last.to_f
when /^= *[A-Z]+(.+)/ then call_function(raw_input.split(/^= */).last)
else raw_input
end
end
def call_function(function_string)
function_name = function_string.split("(").first
arguments = function_string[/\((.*)\)/,1].split(/, */)
arguments = arguments.map{|argument| evaluate("=#{argument}").to_f}
Function.use_function function_name, arguments
end
def letter_index(letters)
letters.split("").each.with_index.inject(0) do | result, (letter, index) |
alphabetical_number = letter.ord - FIRST_LETTER.ord + 1
shift_multiplication = ALPHABET_LETTERS ** (letters.size - index - 1)
result += alphabetical_number * shift_multiplication
end - 1
end
def to_s
@table.map do |row|
row.map do |cell|
cell = Format.format_result evaluate cell
end.join("\t")
end.join("\n")
end
class Error < StandardError
end
module Format
def self.format_result(result)
if result.is_a? Float
result = result.round(2)
result = result.round == result ? result.round : result
end
result
end
end
module Function
def self.use_function(name, *arguments)
begin
return eval("#{name.downcase} #{arguments.join(", ")}")
rescue NoMethodError
raise Error.new, UNKNOWN_FUNCTION % {name: name}
end
end
def self.add(*arguments)
arguments.inject(&:+)
end
def self.multiply(*arguments)
arguments.inject(&:*)
end
def self.subtract(*arguments)
arguments.first - arguments.last
end
def self.divide(*arguments)
arguments.first / arguments.last
end
def self.mod(*arguments)
arguments.first * arguments.last
end
end
end

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

.........FF.F.FF..F...F..F..FFFFFF.FF.FF

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.6"
       
       (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.6
     # /tmp/d20160121-5693-13vkh70/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 raises and exception for non-existant cells
     Failure/Error: expect { Spreadsheet.new('foo')['B10'] }.to raise_error(Spreadsheet::Error, /Cell 'B10' does not exist/)
       expected Spreadsheet::Error with message matching /Cell 'B10' does not exist/, got #<NoMethodError: undefined method `[]' for nil:NilClass> with backtrace:
         # /tmp/d20160121-5693-13vkh70/solution.rb:24:in `cell_at'
         # /tmp/d20160121-5693-13vkh70/solution.rb:30:in `[]'
         # /tmp/d20160121-5693-13vkh70/spec.rb:59:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13vkh70/spec.rb:59: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-13vkh70/spec.rb:59: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#[] raises an exception for non-existant cells
     Failure/Error: expect { Spreadsheet.new()['A1'] }.to raise_error(Spreadsheet::Error, /Cell 'A1' does not exist/)
       expected Spreadsheet::Error with message matching /Cell 'A1' does not exist/, got #<NoMethodError: undefined method `[]' for nil:NilClass> with backtrace:
         # /tmp/d20160121-5693-13vkh70/solution.rb:24:in `cell_at'
         # /tmp/d20160121-5693-13vkh70/solution.rb:30:in `[]'
         # /tmp/d20160121-5693-13vkh70/spec.rb:75:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13vkh70/spec.rb:75: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-13vkh70/spec.rb:75: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 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-13vkh70/solution.rb:25:in `cell_at'
     # /tmp/d20160121-5693-13vkh70/solution.rb:30:in `[]'
     # /tmp/d20160121-5693-13vkh70/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)>'

  5) Spreadsheet#[] returns the calculated value of formulae cells
     Failure/Error: expect(sheet['A1']).to eq 'foo'
       
       expected: "foo"
            got: "foo\tADD(2, 2)\t=ADD(2, 2)"
       
       (compared using ==)
     # /tmp/d20160121-5693-13vkh70/spec.rb:101: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#[] 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-13vkh70/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)>'

  7) 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-13vkh70/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)>'

  8) 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/ but nothing was raised
     # /tmp/d20160121-5693-13vkh70/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)>'

  9) 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/ but nothing was raised
     # /tmp/d20160121-5693-13vkh70/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)>'

  10) Spreadsheet#[] calculates the modulo of two numbers with MOD
     Failure/Error: expect(Spreadsheet.new('=MOD(42, 5)')['A1']).to eq('2')
       
       expected: "2"
            got: "210"
       
       (compared using ==)
     # /tmp/d20160121-5693-13vkh70/spec.rb:205: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#[] calculates the modulo of two numbers with MOD via cell references
     Failure/Error: expect(sheet1['C1']).to eq('4')
       
       expected: "4"
            got: "840"
       
       (compared using ==)
     # /tmp/d20160121-5693-13vkh70/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)>'

  12) 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/ but nothing was raised
     # /tmp/d20160121-5693-13vkh70/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)>'

  13) Spreadsheet#[] adds floating point numbers with ADD
     Failure/Error: expect(Spreadsheet.new('10  =ADD(A1, 1.1)')['B1']).to eq '11.10'
       
       expected: "11.10"
            got: "11.1"
       
       (compared using ==)
     # /tmp/d20160121-5693-13vkh70/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)>'

  14) Spreadsheet#[] subtracts floating point numbers with SUBTRACT
     Failure/Error: expect(Spreadsheet.new('10  =SUBTRACT(A1, 1.1)')['B1']).to eq '8.90'
       
       expected: "8.90"
            got: "8.9"
       
       (compared using ==)
     # /tmp/d20160121-5693-13vkh70/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)>'

  15) Spreadsheet#[] divides floating point numbers with DIVIDE
     Failure/Error: expect(Spreadsheet.new('10  =DIVIDE(A1, 4)')['B1']).to eq '2.50'
       
       expected: "2.50"
            got: "2.5"
       
       (compared using ==)
     # /tmp/d20160121-5693-13vkh70/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)>'

  16) 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'
       
       expected: "1"
            got: "20"
       
       (compared using ==)
     # /tmp/d20160121-5693-13vkh70/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)>'

  17) Spreadsheet#[] raises an exception for missing cells passed as function arguments
     Failure/Error: expect { Spreadsheet.new('=ADD(1, B4)  100')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Cell 'B4' does not exist/, got #<NoMethodError: undefined method `[]' for nil:NilClass> with backtrace:
         # /tmp/d20160121-5693-13vkh70/solution.rb:24:in `cell_at'
         # /tmp/d20160121-5693-13vkh70/solution.rb:30:in `[]'
         # /tmp/d20160121-5693-13vkh70/solution.rb:35:in `evaluate'
         # /tmp/d20160121-5693-13vkh70/solution.rb:45:in `block in call_function'
         # /tmp/d20160121-5693-13vkh70/solution.rb:45:in `map'
         # /tmp/d20160121-5693-13vkh70/solution.rb:45:in `call_function'
         # /tmp/d20160121-5693-13vkh70/solution.rb:37:in `evaluate'
         # /tmp/d20160121-5693-13vkh70/solution.rb:30:in `[]'
         # /tmp/d20160121-5693-13vkh70/spec.rb:260:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13vkh70/spec.rb:260: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-13vkh70/spec.rb:260: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#[] 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'/, got #<NoMethodError: undefined method `split' for nil:NilClass> with backtrace:
         # /tmp/d20160121-5693-13vkh70/solution.rb:44:in `call_function'
         # /tmp/d20160121-5693-13vkh70/solution.rb:37:in `evaluate'
         # /tmp/d20160121-5693-13vkh70/solution.rb:30:in `[]'
         # /tmp/d20160121-5693-13vkh70/spec.rb:266:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13vkh70/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)>'
     # /tmp/d20160121-5693-13vkh70/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.03314 seconds
40 examples, 18 failures

Failed examples:

rspec /tmp/d20160121-5693-13vkh70/spec.rb:43 # Spreadsheet#to_s returns the evaluated spreadsheet as a table
rspec /tmp/d20160121-5693-13vkh70/spec.rb:58 # Spreadsheet#cell_at raises and exception for non-existant cells
rspec /tmp/d20160121-5693-13vkh70/spec.rb:74 # Spreadsheet#[] raises an exception for non-existant cells
rspec /tmp/d20160121-5693-13vkh70/spec.rb:90 # Spreadsheet#[] returns the value of existing cells for complex cell indexes
rspec /tmp/d20160121-5693-13vkh70/spec.rb:98 # Spreadsheet#[] returns the calculated value of formulae cells
rspec /tmp/d20160121-5693-13vkh70/spec.rb:118 # Spreadsheet#[] raises an exception for less than two arguments passed to ADD
rspec /tmp/d20160121-5693-13vkh70/spec.rb:148 # Spreadsheet#[] raises an exception for less than two arguments to MULTIPLY
rspec /tmp/d20160121-5693-13vkh70/spec.rb:170 # Spreadsheet#[] raises an exception when SUBTRACT is called with a wrong number of arguments
rspec /tmp/d20160121-5693-13vkh70/spec.rb:194 # Spreadsheet#[] raises an exception when DIVIDE is called with a wrong number of arguments
rspec /tmp/d20160121-5693-13vkh70/spec.rb:204 # Spreadsheet#[] calculates the modulo of two numbers with MOD
rspec /tmp/d20160121-5693-13vkh70/spec.rb:210 # Spreadsheet#[] calculates the modulo of two numbers with MOD via cell references
rspec /tmp/d20160121-5693-13vkh70/spec.rb:218 # Spreadsheet#[] raises an exception when MOD is called with a wrong number of arguments
rspec /tmp/d20160121-5693-13vkh70/spec.rb:228 # Spreadsheet#[] adds floating point numbers with ADD
rspec /tmp/d20160121-5693-13vkh70/spec.rb:233 # Spreadsheet#[] subtracts floating point numbers with SUBTRACT
rspec /tmp/d20160121-5693-13vkh70/spec.rb:243 # Spreadsheet#[] divides floating point numbers with DIVIDE
rspec /tmp/d20160121-5693-13vkh70/spec.rb:249 # Spreadsheet#[] evaluates deeply-nested cell references
rspec /tmp/d20160121-5693-13vkh70/spec.rb:259 # Spreadsheet#[] raises an exception for missing cells passed as function arguments
rspec /tmp/d20160121-5693-13vkh70/spec.rb:265 # Spreadsheet#[] raises an exception for invalid expressions

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

Димитър обнови решението на 10.01.2016 16:46 (преди над 8 години)

+FIRST_LETTER = "A"
+ALPHABET_LETTERS = 26
+
+INVALID_INDEX = "Invalid cell index '%{index}'"
+NO_CELL = "Cell '%{index}' does not exist"
+UNKNOWN_FUNCTION = "Unknown function '%{name}'"
+#ARGUMENTS_NUMBER = "Wrong number of arguments for %{name}: "
+#ARGUMENTS_NUMBER += "expected at least %{expected}, got %{got}"
+
+class Spreadsheet
+ def initialize(table_string = "")
+ rows = table_string.split("\n").reject(&:empty?)
+ @table = rows.map{|row| row.split(/ +/).reject(&:empty?)}
+ end
+
+ def empty?
+ @table.empty?
+ end
+
+ def cell_at(cell_index)
+ invalid_index = cell_index !~ /^[A-Z]+\d+$/
+ raise(Error.new, INVALID_INDEX % {index: cell_index}) if invalid_index
+ letters, number = cell_index.scan(/\d+|\D+/)
+ invalid_cell = @table[number.to_i - 1][letter_index(letters)].nil?
+ raise(Error.new, NO_CELL % {index: cell_index}) if invalid_cell
+ @table[number.to_i - 1][letter_index(letters)]
+ end
+
+ def [](cell_index)
+ Format.format_result(evaluate(cell_at cell_index)).to_s
+ end
+
+ def evaluate(raw_input)
+ case raw_input
+ when /^= *[A-Z]+\d+/ then self[((/[A-Z]+\d+/.match raw_input).to_s)]
+ when /^= *\d/ then raw_input.split(/^= */).last.to_f
+ when /^= *[A-Z]+(.+)/ then call_function(raw_input.split(/^= */).last)
+ else raw_input
+ end
+ end
+
+ def call_function(function_string)
+ function_name = function_string.split("(").first
+ arguments = function_string[/\((.*)\)/,1].split(/, */)
+ arguments = arguments.map{|argument| evaluate("=#{argument}").to_f}
+ Function.use_function function_name, arguments
+ end
+
+ def letter_index(letters)
+ letters.split("").each.with_index.inject(0) do | result, (letter, index) |
+ alphabetical_number = letter.ord - FIRST_LETTER.ord + 1
+ shift_multiplication = ALPHABET_LETTERS ** (letters.size - index - 1)
+ result += alphabetical_number * shift_multiplication
+ end - 1
+ end
+
+ def to_s
+ @table.map do |row|
+ row.map do |cell|
+ cell = Format.format_result evaluate cell
+ end.join("\t")
+ end.join("\n")
+ end
+
+ class Error < StandardError
+ end
+
+ module Format
+ def self.format_result(result)
+ if result.is_a? Float
+ result = result.round(2)
+ result = result.round == result ? result.round : result
+ end
+ result
+ end
+ end
+
+ module Function
+ def self.use_function(name, *arguments)
+ begin
+ return eval("#{name.downcase} #{arguments.join(", ")}")
+ rescue NoMethodError
+ raise Error.new, UNKNOWN_FUNCTION % {name: name}
+ end
+ end
+ def self.add(*arguments)
+ arguments.inject(&:+)
+ end
+ def self.multiply(*arguments)
+ arguments.inject(&:*)
+ end
+ def self.subtract(*arguments)
+ arguments.first - arguments.last
+ end
+ def self.divide(*arguments)
+ arguments.first / arguments.last
+ end
+ def self.mod(*arguments)
+ arguments.first * arguments.last
+ end
+ end
+end