Решение на Осма задача от Виктор Радивчев

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

Към профила на Виктор Радивчев

Резултати

  • 4 точки от тестове
  • 0 бонус точки
  • 4 точки общо
  • 28 успешни тест(а)
  • 12 неуспешни тест(а)

Код

module HelpFunctionsFirstPart
def add(parameters)
if parameters.size < 2
raise Spreadsheet::Error, add_message(parameters.size)
end
result = 0
parameters.each { |number| result += number.to_f }
number(result.to_s)
end
def multiply(parameters)
if parameters.size < 2
raise Spreadsheet::Error, multiply_message(parameters.size)
end
result = 1
parameters.each { |number| result *= number.to_f }
number(result.to_s)
end
def subtract(parameters)
if parameters.size != 2
raise Spreadsheet::Error, subtract_message(parameters.size)
end
result = parameters.first.to_f - parameters.last.to_f
number(result.to_s)
end
def divide(parameters)
if parameters.size != 2
raise Spreadsheet::Error, divide_message(parameters.size)
end
result = parameters.first.to_f / parameters.last.to_f
number(result.to_s)
end
def mod(parameters)
if parameters.size != 2
raise Spreadsheet::Error,
"Wrong number of arguments for 'MOD': expected 2, got #{parameters.size}"
end
result = parameters.first.to_i / parameters.last.to_i
number(result.to_s)
end
def calculate(formula, parameters)
case formula
when 'ADD' then add(parameters)
when 'MULTIPLY' then multiply(parameters)
when 'SUBTRACT' then subtract(parameters)
when 'DIVIDE' then divide(parameters)
when 'MOD' then mod(parameters)
end
end
def parameter_to_number(parameter)
return self. [] (parameter) if ('A'..'Z').include? parameter.chars.first
parameter
end
def function(string)
check_valid_function(string)
formula = string.chars.take_while { |char| char != '(' }.join
parameters = string.sub(formula, '').sub('(', '').sub(')', '').split(',')
parameters = parameters.map { |parameter| parameter.strip }
parameters = parameters.map { |parameter| parameter_to_number(parameter) }
calculate(formula, parameters)
end
end
module HelpFunctionsSecondPart
def add_message(number)
"Wrong number of arguments for 'ADD': expected at least 2, got #{number}"
end
def multiply_message(number)
result = "Wrong number of arguments for 'MULTIPLY':"
result += " expected at least 2, got #{number}"
result
end
def subtract_message(number)
result = "Wrong number of arguments for 'SUBTRACT':"
result += " expected at least 2, got #{number}"
result
end
def divide_message(number)
result = "Wrong number of arguments for 'DIVIDE':"
result += " expected at least 2, got #{number}"
result
end
def cell_index_to_column_number(cell_index)
column_string = cell_index.chars.select { |char| ('A'..'Z').include? char }
number = 0
column_string.each { |char| number = number * 26 + char.ord - 'A'.ord + 1 }
number
end
def cell_index_to_row_number(cell_index)
cell_index.reverse.to_i.to_s.reverse.to_i
end
def check_valid_cell(row, column, cell_index)
usable_index = /[A-Z]+\d+/.match cell_index
if usable_index[0] != cell_index
raise Spreadsheet::Error, "Invalid cell index '#{cell_index}'"
end
if row + 1 > @table.size or column + 1 > @table.first.size
raise Spreadsheet::Error, "Cell '#{cell_index}' does not exist"
end
end
def check_valid_function(string)
usable_function = /[A-Z]+\((\w|,| )+\)/.match string
unless usable_function
raise Spreadsheet::Error, "Invalid expression '#{string}'"
end
function = /[A-Z]+/.match string
unless ['ADD', 'MULTIPLY', 'DIVIDE', 'SUBTRACT', 'MOD'].include? function[0]
raise Spreadsheet::Error, "Unknown function '#{function[0]}'"
end
end
end
class Spreadsheet
class Error < Exception
end
include HelpFunctionsFirstPart
include HelpFunctionsSecondPart
def initialize(string = '')
@table = string.strip.split("\n").map do |row|
row.strip.gsub("\t", ' ').split(' ').map { |cell| cell.strip }
end
@table.each { |row| row.delete('') }
@table.delete([])
end
def calculate_position(column_index, row_index)
result = ''
result += 'A' if column_index == 0
while column_index > 0
result += (column_index % 26 + 'A'.ord).chr
column_index /= 26
end
result.reverse + (row_index + 1).to_s
end
def to_s
@table.map.with_index do |row, row_index|
row.map.with_index do |cell, column_index|
self. [] (calculate_position(column_index, row_index))
end.join("\t")
end.join("\n")
end
def empty?
@table.empty?
end
def cell_at(cell_index)
row = cell_index_to_row_number(cell_index) - 1
column = cell_index_to_column_number(cell_index) - 1
check_valid_cell(row, column, cell_index)
@table[row][column]
end
def number(string)
return string.to_i.to_s if string.to_i == string.to_f
format('%.2f', string.to_f)
end
def [](cell_index)
cell = cell_at(cell_index)
return cell unless cell.chars.first == '='
if ('0'..'9').include? cell.chars.last and ('A'..'Z').include? cell.chars[1]
return self. [] (cell.sub('=', '')) unless cell.chars.include? '('
end
return number(cell.sub('=', '')) if ('0'..'9').include? cell.chars[1]
function(cell.sub('=', ''))
end
end

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

.........F........F...F..F..FFF.FFFF...F

Failures:

  1) Spreadsheet#to_s returns the evaluated spreadsheet as a table
     Failure/Error: expect(sheet.to_s).to eq \
     Spreadsheet::Error:
       Invalid expression 'ADD(B1, C1, 2.9)'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:117:in `check_valid_function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:61:in `function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:154:in `block (2 levels) in to_s'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:153:in `map'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:153:in `with_index'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:153:in `block in to_s'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:152:in `map'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:152:in `with_index'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:152:in `to_s'
     # /tmp/d20160121-5693-13s1qg5/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#[] raises an exception for less than two arguments passed to ADD
     Failure/Error: expect { Spreadsheet.new('=ADD()')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Wrong number of arguments for 'ADD': expected at least 2, got 0/, got #<Spreadsheet::Error: Invalid expression 'ADD()'> with backtrace:
         # /tmp/d20160121-5693-13s1qg5/solution.rb:117:in `check_valid_function'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:61:in `function'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
         # /tmp/d20160121-5693-13s1qg5/spec.rb:123:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13s1qg5/spec.rb:123: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-13s1qg5/spec.rb:123: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 less than two arguments to MULTIPLY
     Failure/Error: expect { Spreadsheet.new('=MULTIPLY()')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Wrong number of arguments for 'MULTIPLY': expected at least 2, got 0/, got #<Spreadsheet::Error: Invalid expression 'MULTIPLY()'> with backtrace:
         # /tmp/d20160121-5693-13s1qg5/solution.rb:117:in `check_valid_function'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:61:in `function'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
         # /tmp/d20160121-5693-13s1qg5/spec.rb:153:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13s1qg5/spec.rb:153: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-13s1qg5/spec.rb:153: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#[] 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 #<Spreadsheet::Error: Wrong number of arguments for 'SUBTRACT': expected at least 2, got 1> with backtrace:
         # /tmp/d20160121-5693-13s1qg5/solution.rb:22:in `subtract'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:49:in `calculate'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:66:in `function'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
         # /tmp/d20160121-5693-13s1qg5/spec.rb:171:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13s1qg5/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-13s1qg5/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)>'

  5) 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 #<Spreadsheet::Error: Wrong number of arguments for 'DIVIDE': expected at least 2, got 1> with backtrace:
         # /tmp/d20160121-5693-13s1qg5/solution.rb:30:in `divide'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:50:in `calculate'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:66:in `function'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
         # /tmp/d20160121-5693-13s1qg5/spec.rb:195:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13s1qg5/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-13s1qg5/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)>'

  6) Spreadsheet#[] calculates the modulo of two numbers with MOD
     Failure/Error: expect(Spreadsheet.new('=MOD(42, 5)')['A1']).to eq('2')
       
       expected: "2"
            got: "8"
       
       (compared using ==)
     # /tmp/d20160121-5693-13s1qg5/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)>'

  7) Spreadsheet#[] calculates the modulo of two numbers with MOD via cell references
     Failure/Error: expect(sheet1['C1']).to eq('4')
       
       expected: "4"
            got: "8"
       
       (compared using ==)
     # /tmp/d20160121-5693-13s1qg5/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)>'

  8) Spreadsheet#[] adds floating point numbers with ADD
     Failure/Error: expect(Spreadsheet.new('10  =ADD(A1, 1.1)')['B1']).to eq '11.10'
     Spreadsheet::Error:
       Invalid expression 'ADD(A1, 1.1)'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:117:in `check_valid_function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:61:in `function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
     # /tmp/d20160121-5693-13s1qg5/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)>'

  9) Spreadsheet#[] subtracts floating point numbers with SUBTRACT
     Failure/Error: expect(Spreadsheet.new('10  =SUBTRACT(A1, 1.1)')['B1']).to eq '8.90'
     Spreadsheet::Error:
       Invalid expression 'SUBTRACT(A1, 1.1)'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:117:in `check_valid_function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:61:in `function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
     # /tmp/d20160121-5693-13s1qg5/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)>'

  10) Spreadsheet#[] multiplies floating point numbers with MULTIPLY
     Failure/Error: expect(Spreadsheet.new('10  =MULTIPLY(A1, 1.1)')['B1']).to eq '11'
     Spreadsheet::Error:
       Invalid expression 'MULTIPLY(A1, 1.1)'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:117:in `check_valid_function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:61:in `function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
     # /tmp/d20160121-5693-13s1qg5/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)>'

  11) Spreadsheet#[] divides floating point numbers with DIVIDE
     Failure/Error: expect(Spreadsheet.new('10  =DIVIDE(A1, 4.0)')['B1']).to eq '2.50'
     Spreadsheet::Error:
       Invalid expression 'DIVIDE(A1, 4.0)'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:117:in `check_valid_function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:61:in `function'
     # /tmp/d20160121-5693-13s1qg5/solution.rb:182:in `[]'
     # /tmp/d20160121-5693-13s1qg5/spec.rb:245: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 for invalid expressions
     Failure/Error: expect { Spreadsheet.new('=FOO A1  100')['A1'] }.to raise_error(
       expected Spreadsheet::Error with message matching /Invalid expression 'FOO A1'/, got #<Spreadsheet::Error: Invalid cell index 'FOO A1'> with backtrace:
         # /tmp/d20160121-5693-13s1qg5/solution.rb:107:in `check_valid_cell'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:166:in `cell_at'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:176:in `[]'
         # /tmp/d20160121-5693-13s1qg5/solution.rb:179:in `[]'
         # /tmp/d20160121-5693-13s1qg5/spec.rb:274:in `block (4 levels) in <top (required)>'
         # /tmp/d20160121-5693-13s1qg5/spec.rb:274: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-13s1qg5/spec.rb:274: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.03188 seconds
40 examples, 12 failures

Failed examples:

rspec /tmp/d20160121-5693-13s1qg5/spec.rb:43 # Spreadsheet#to_s returns the evaluated spreadsheet as a table
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:118 # Spreadsheet#[] raises an exception for less than two arguments passed to ADD
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:148 # Spreadsheet#[] raises an exception for less than two arguments to MULTIPLY
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:170 # Spreadsheet#[] raises an exception when SUBTRACT is called with a wrong number of arguments
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:194 # Spreadsheet#[] raises an exception when DIVIDE is called with a wrong number of arguments
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:204 # Spreadsheet#[] calculates the modulo of two numbers with MOD
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:210 # Spreadsheet#[] calculates the modulo of two numbers with MOD via cell references
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:228 # Spreadsheet#[] adds floating point numbers with ADD
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:233 # Spreadsheet#[] subtracts floating point numbers with SUBTRACT
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:238 # Spreadsheet#[] multiplies floating point numbers with MULTIPLY
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:243 # Spreadsheet#[] divides floating point numbers with DIVIDE
rspec /tmp/d20160121-5693-13s1qg5/spec.rb:265 # Spreadsheet#[] raises an exception for invalid expressions

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

Виктор обнови решението на 10.01.2016 19:03 (преди около 9 години)

+module HelpFunctionsFirstPart
+ def add(parameters)
+ result = 0
+ parameters.each { |number| result += number.to_f }
+ number(result.to_s)
+ end
+
+ def multiply(parameters)
+ result = 0
+ parameters.each { |number| result *= number.to_f }
+ number(result.to_s)
+ end
+
+ def subtract(parameters)
+ result = parameters.first.to_f - parameters.last.to_f
+ number(result.to_s)
+ end
+
+ def divide(parameters)
+ result = parameters.first.to_f / parameters.last.to_f
+ number(result.to_s)
+ end
+
+ def mod(parameters)
+ result = parameters.first.to_i / parameters.last.to_i
+ number(result.to_s)
+ end
+
+ def calculate(formula, parameters)
+ case formula
+ when "ADD" then add(parameters)
+ when "MULTIPLY" then multiply(parameters)
+ when "SUBTRACT" then subtract(parameters)
+ when "DIVIDE" then divide(parameters)
+ when "MOD" then mod(parameters)
+ end
+ end
+
+ def parameter_to_number(parameter)
+ return self. [] (parameter) if ('A'..'Z').include? parameter.chars.first
+ parameter
+ end
+
+ def function(string)
+ formula = string.chars.take_while { |char| char != "(" }.join
+ parameters = string.sub(formula, "").sub("(", "").sub(")", "").split(",")
+ parameters = parameters.map { |parameter| parameter.strip }
+ parameters = parameters.map { |parameter| parameter_to_number(parameter) }
+ calculate(formula, parameters)
+ end
+end
+
+module HelpFunctionsSecondPart
+ def cell_index_to_column_number(cell_index)
+ column_string = cell_index.chars.select { |char| ('A'..'Z').include? char }
+ number = 0
+ column_string.each { |char| number = number * 26 + char.ord - 'A'.ord + 1 }
+ number
+ end
+
+ def cell_index_to_row_number(cell_index)
+ cell_index.reverse.to_i.to_s.reverse.to_i
+ end
+
+ def number(string)
+ return string.to_i.to_s if string.to_i == string.to_f
+ format('%.2f', string.to_f)
+ end
+end
+
+class Spreadsheet
+ class Error < Exception
+ end
+
+ include HelpFunctionsFirstPart
+ include HelpFunctionsSecondPart
+
+ def initialize(string = '')
+ @table = string.strip.split("\n").map do |row|
+ row.strip.gsub("\t", " ").split(" ").map { |cell| cell.strip}
+ end
+ @table.each{ |row| row.delete("") }
+ @table.delete([])
+ end
+
+ def calculate_position(column_index, row_index)
+ result = ''
+ result += 'A' if column_index == 0
+ while column_index > 0
+ result = result + (column_index % 26 + "A".ord).chr
+ column_index /= 26
+ end
+ result.reverse + (row_index + 1).to_s
+ end
+
+ def to_s
+ @table.map.with_index do |row, row_index|
+ row.map.with_index do |cell, column_index|
+ self. [] (calculate_position(column_index, row_index))
+ end.join("\t")
+ end.join("\n")
+ end
+
+ def empty?
+ @table.empty?
+ end
+
+ def cell_at(cell_index)
+ row = cell_index_to_row_number(cell_index) - 1
+ column = cell_index_to_column_number(cell_index) - 1
+ @table[row][column]
+ end
+
+ def [](cell_index)
+ cell = cell_at(cell_index)
+ return cell unless cell.chars.first == "="
+ if ('0'..'9').include? cell.chars.last and ('A'..'Z').include? cell.chars[1]
+ return self. [] (cell.sub("=", "")) unless cell.chars.include? "("
+ end
+ return number(cell.sub("=", "")) if ('0'..'9').include? cell.chars[1]
+ function(cell.sub("=", ""))
+ end
+end

Виктор обнови решението на 10.01.2016 22:38 (преди около 9 години)

module HelpFunctionsFirstPart
def add(parameters)
+ if parameters.size < 2
+ raise Spreadsheet::Error, add_message(parameters.size)
+ end
result = 0
parameters.each { |number| result += number.to_f }
number(result.to_s)
end
def multiply(parameters)
- result = 0
+ if parameters.size < 2
+ raise Spreadsheet::Error, multiply_message(parameters.size)
+ end
+ result = 1
parameters.each { |number| result *= number.to_f }
number(result.to_s)
end
def subtract(parameters)
+ if parameters.size != 2
+ raise Spreadsheet::Error, subtract_message(parameters.size)
+ end
result = parameters.first.to_f - parameters.last.to_f
number(result.to_s)
end
def divide(parameters)
+ if parameters.size != 2
+ raise Spreadsheet::Error, divide_message(parameters.size)
+ end
result = parameters.first.to_f / parameters.last.to_f
number(result.to_s)
end
def mod(parameters)
+ if parameters.size != 2
+ raise Spreadsheet::Error,
+ "Wrong number of arguments for 'MOD': expected 2, got #{parameters.size}"
+ end
result = parameters.first.to_i / parameters.last.to_i
number(result.to_s)
end
def calculate(formula, parameters)
case formula
- when "ADD" then add(parameters)
- when "MULTIPLY" then multiply(parameters)
- when "SUBTRACT" then subtract(parameters)
- when "DIVIDE" then divide(parameters)
- when "MOD" then mod(parameters)
+ when 'ADD' then add(parameters)
+ when 'MULTIPLY' then multiply(parameters)
+ when 'SUBTRACT' then subtract(parameters)
+ when 'DIVIDE' then divide(parameters)
+ when 'MOD' then mod(parameters)
end
end
def parameter_to_number(parameter)
return self. [] (parameter) if ('A'..'Z').include? parameter.chars.first
parameter
end
def function(string)
- formula = string.chars.take_while { |char| char != "(" }.join
- parameters = string.sub(formula, "").sub("(", "").sub(")", "").split(",")
+ check_valid_function(string)
+ formula = string.chars.take_while { |char| char != '(' }.join
+ parameters = string.sub(formula, '').sub('(', '').sub(')', '').split(',')
parameters = parameters.map { |parameter| parameter.strip }
parameters = parameters.map { |parameter| parameter_to_number(parameter) }
calculate(formula, parameters)
end
end
module HelpFunctionsSecondPart
+ def add_message(number)
+ "Wrong number of arguments for 'ADD': expected at least 2, got #{number}"
+ end
+
+ def multiply_message(number)
+ result = "Wrong number of arguments for 'MULTIPLY':"
+ result += " expected at least 2, got #{number}"
+ result
+ end
+
+ def subtract_message(number)
+ result = "Wrong number of arguments for 'SUBTRACT':"
+ result += " expected at least 2, got #{number}"
+ result
+ end
+
+ def divide_message(number)
+ result = "Wrong number of arguments for 'DIVIDE':"
+ result += " expected at least 2, got #{number}"
+ result
+ end
+
def cell_index_to_column_number(cell_index)
column_string = cell_index.chars.select { |char| ('A'..'Z').include? char }
number = 0
column_string.each { |char| number = number * 26 + char.ord - 'A'.ord + 1 }
number
end
def cell_index_to_row_number(cell_index)
cell_index.reverse.to_i.to_s.reverse.to_i
end
- def number(string)
- return string.to_i.to_s if string.to_i == string.to_f
- format('%.2f', string.to_f)
+ def check_valid_cell(row, column, cell_index)
+ usable_index = /[A-Z]+\d+/.match cell_index
+ if usable_index[0] != cell_index
+ raise Spreadsheet::Error, "Invalid cell index '#{cell_index}'"
+ end
+ if row + 1 > @table.size or column + 1 > @table.first.size
+ raise Spreadsheet::Error, "Cell '#{cell_index}' does not exist"
+ end
end
+
+ def check_valid_function(string)
+ usable_function = /[A-Z]+\((\w|,| )+\)/.match string
+ unless usable_function
+ raise Spreadsheet::Error, "Invalid expression '#{string}'"
+ end
+ function = /[A-Z]+/.match string
+ unless ['ADD', 'MULTIPLY', 'DIVIDE', 'SUBTRACT', 'MOD'].include? function[0]
+ raise Spreadsheet::Error, "Unknown function '#{function[0]}'"
+ end
+ end
end
class Spreadsheet
class Error < Exception
end
include HelpFunctionsFirstPart
include HelpFunctionsSecondPart
def initialize(string = '')
@table = string.strip.split("\n").map do |row|
- row.strip.gsub("\t", " ").split(" ").map { |cell| cell.strip}
+ row.strip.gsub("\t", ' ').split(' ').map { |cell| cell.strip }
end
- @table.each{ |row| row.delete("") }
+ @table.each { |row| row.delete('') }
@table.delete([])
end
def calculate_position(column_index, row_index)
result = ''
result += 'A' if column_index == 0
while column_index > 0
- result = result + (column_index % 26 + "A".ord).chr
+ result += (column_index % 26 + 'A'.ord).chr
column_index /= 26
end
result.reverse + (row_index + 1).to_s
end
def to_s
@table.map.with_index do |row, row_index|
row.map.with_index do |cell, column_index|
self. [] (calculate_position(column_index, row_index))
end.join("\t")
end.join("\n")
end
def empty?
@table.empty?
end
def cell_at(cell_index)
row = cell_index_to_row_number(cell_index) - 1
column = cell_index_to_column_number(cell_index) - 1
+ check_valid_cell(row, column, cell_index)
@table[row][column]
end
+ def number(string)
+ return string.to_i.to_s if string.to_i == string.to_f
+ format('%.2f', string.to_f)
+ end
+
def [](cell_index)
cell = cell_at(cell_index)
- return cell unless cell.chars.first == "="
+ return cell unless cell.chars.first == '='
if ('0'..'9').include? cell.chars.last and ('A'..'Z').include? cell.chars[1]
- return self. [] (cell.sub("=", "")) unless cell.chars.include? "("
+ return self. [] (cell.sub('=', '')) unless cell.chars.include? '('
end
- return number(cell.sub("=", "")) if ('0'..'9').include? cell.chars[1]
- function(cell.sub("=", ""))
+ return number(cell.sub('=', '')) if ('0'..'9').include? cell.chars[1]
+ function(cell.sub('=', ''))
end
end