Решение на Шеста задача от Валентин Ейткен

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

Към профила на Валентин Ейткен

Резултати

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

Код

require 'bigdecimal'
require 'bigdecimal/util'
class ExchangeRate
attr_reader :rates
class Rate
attr_reader :from_currency, :to_currency
def initialize(from_currency, to_currency, rate = nil)
@from_currency, @to_currency, @rate = from_currency, to_currency, rate
end
def get(to_currency)
if to_currency == @to_currency
@rate
else
1/@rate
end
end
def hash
@from_currency.hash + @to_currency.hash
end
def eql?(other)
other.class == self.class &&
(@from_currency == other.from_currency && @to_currency == other.to_currency ||
@from_currency == other.to_currency && @to_currency == other.from_currency)
end
end
def initialize
@rates = {}
end
def set(from_currency, to_currency, rate)
@rates[Rate.new(from_currency, to_currency)] = Rate.new(from_currency, to_currency, rate)
end
def get(from_currency, to_currency)
if from_currency == to_currency
1
else
@rates[Rate.new(from_currency, to_currency)] &&
@rates[Rate.new(from_currency, to_currency)].get(to_currency)
end
end
def convert(from_currency, to_currency, amount)
from_currency == to_currency ? amount : get(from_currency, to_currency) * amount
end
end
class Money
class Unknown < Exception
end
class IncompatibleCurrencies < Exception
end
include Comparable
attr_reader :amount, :currency
def initialize(amount, currency)
@amount, @currency = amount, currency
end
def to_s
str = @amount.round(2).to_s('F')
dot_pos = str.index('.')
"#{str.length - dot_pos == 2 ? str + '0' : str} #{@currency.to_s}"
end
def in(currency, exchange_rate)
unless rate_value = exchange_rate.get(@currency, currency)
raise Unknown
end
Money.new(@amount * rate_value, currency)
end
def +(other)
money_operation :+, other
end
def -(other)
money_operation :-, other
end
def *(other)
numeric_operation :*, other
end
def /(other)
numeric_operation :/, other
end
def <=>(other)
if other.kind_of? Money
if @currency == other.currency
@amount <=> other.amount
else
raise IncompatibleCurrencies
end
else
raise ArgumentError
end
end
private
def money_operation(operation, other)
if other.kind_of? Money
if other.currency == @currency
Money.new @amount.send(operation, other.amount), @currency
else
raise IncompatibleCurrencies
end
else
raise ArgumentError
end
end
def numeric_operation(operation, other)
if other.kind_of? Numeric
Money.new @amount.send(operation, other), @currency
else
raise ArgumentError
end
end
end

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

.........F........F..................F.........

Failures:

  1) ExchangeRate#convert raises an ExchangeRate::Unknown exception when the rate is not defined
     Failure/Error: end.to raise_error(ExchangeRate::Unknown)
     NameError:
       uninitialized constant ExchangeRate::Unknown
     # /tmp/d20130203-23049-61gxdy/spec.rb:58:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Money convertion raises an ExchangeRate::Unknown exception for unknown rates
     Failure/Error: end.to raise_error(ExchangeRate::Unknown)
     NameError:
       uninitialized constant ExchangeRate::Unknown
     # /tmp/d20130203-23049-61gxdy/spec.rb:113:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) Money comparison with == raises ArgumentError when comparing with other objects
     Failure/Error: expect do
       expected ArgumentError but nothing was raised
     # /tmp/d20130203-23049-61gxdy/spec.rb:195:in `block (4 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.05908 seconds
47 examples, 3 failures

Failed examples:

rspec /tmp/d20130203-23049-61gxdy/spec.rb:55 # ExchangeRate#convert raises an ExchangeRate::Unknown exception when the rate is not defined
rspec /tmp/d20130203-23049-61gxdy/spec.rb:110 # Money convertion raises an ExchangeRate::Unknown exception for unknown rates
rspec /tmp/d20130203-23049-61gxdy/spec.rb:194 # Money comparison with == raises ArgumentError when comparing with other objects

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

Валентин обнови решението на 16.01.2013 04:54 (преди около 11 години)

+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class ExchangeRate
+ attr_reader :rates
+
+ class Rate
+ attr_reader :from_currency, :to_currency
+
+ def initialize(from_currency, to_currency, rate = nil)
+ @from_currency, @to_currency, @rate = from_currency, to_currency, rate
+ end
+
+ def get(to_currency)
+ if to_currency == @to_currency
+ @rate
+ else
+ 1/@rate
+ end
+ end
+
+ def hash
+ @from_currency.hash + @to_currency.hash
+ end
+
+ def eql?(other)
+ other.class == self.class &&
+ (@from_currency == other.from_currency && @to_currency == other.to_currency ||
+ @from_currency == other.to_currency && @to_currency == other.from_currency)
+ end
+ end
+
+ def initialize
+ @rates = {}
+ end
+
+ def set(from_currency, to_currency, rate)
+ # TODO Има ли начин да вземем стойността на ключа,
+ # за да не се налага да пазя нова инстанция на Rate като стойност в хеша?
+ @rates[Rate.new(from_currency, to_currency)] = Rate.new(from_currency, to_currency, rate)
+ end
+
+ def get(from_currency, to_currency)
+ @rates[Rate.new(from_currency, to_currency)] &&
+ @rates[Rate.new(from_currency, to_currency)].get(to_currency)
+ end
+
+ def convert(from_currency, to_currency, amount)
+ get(from_currency, to_currency) * amount
+ end
+end

Валентин обнови решението на 16.01.2013 05:16 (преди около 11 години)

require 'bigdecimal'
require 'bigdecimal/util'
class ExchangeRate
attr_reader :rates
class Rate
attr_reader :from_currency, :to_currency
def initialize(from_currency, to_currency, rate = nil)
@from_currency, @to_currency, @rate = from_currency, to_currency, rate
end
def get(to_currency)
if to_currency == @to_currency
@rate
else
1/@rate
end
end
def hash
@from_currency.hash + @to_currency.hash
end
def eql?(other)
other.class == self.class &&
(@from_currency == other.from_currency && @to_currency == other.to_currency ||
@from_currency == other.to_currency && @to_currency == other.from_currency)
end
end
def initialize
@rates = {}
end
def set(from_currency, to_currency, rate)
# TODO Има ли начин да вземем стойността на ключа,
# за да не се налага да пазя нова инстанция на Rate като стойност в хеша?
@rates[Rate.new(from_currency, to_currency)] = Rate.new(from_currency, to_currency, rate)
end
def get(from_currency, to_currency)
@rates[Rate.new(from_currency, to_currency)] &&
@rates[Rate.new(from_currency, to_currency)].get(to_currency)
end
def convert(from_currency, to_currency, amount)
get(from_currency, to_currency) * amount
end
end
+
+
+class Money
+ class Unknown < Exception
+ end
+
+ attr_reader :amount, :currency
+
+ def initialize(amount, currency)
+ @amount, @currency = amount, currency
+ end
+
+ def to_s
+ "#{@amount.to_s('F')} #{@currency.to_s}"
+ end
+
+ def in(currency, exchange_rate)
+ unless rate_value = exchange_rate.get(@currency, currency)
+ raise Unknown
+ end
+
+ Money.new(@amount * rate_value, currency)
+ end
+end

Валентин обнови решението на 16.01.2013 13:05 (преди около 11 години)

require 'bigdecimal'
require 'bigdecimal/util'
class ExchangeRate
attr_reader :rates
class Rate
attr_reader :from_currency, :to_currency
def initialize(from_currency, to_currency, rate = nil)
@from_currency, @to_currency, @rate = from_currency, to_currency, rate
end
def get(to_currency)
if to_currency == @to_currency
@rate
else
1/@rate
end
end
def hash
@from_currency.hash + @to_currency.hash
end
def eql?(other)
other.class == self.class &&
(@from_currency == other.from_currency && @to_currency == other.to_currency ||
@from_currency == other.to_currency && @to_currency == other.from_currency)
end
end
def initialize
@rates = {}
end
def set(from_currency, to_currency, rate)
# TODO Има ли начин да вземем стойността на ключа,
# за да не се налага да пазя нова инстанция на Rate като стойност в хеша?
@rates[Rate.new(from_currency, to_currency)] = Rate.new(from_currency, to_currency, rate)
end
def get(from_currency, to_currency)
- @rates[Rate.new(from_currency, to_currency)] &&
- @rates[Rate.new(from_currency, to_currency)].get(to_currency)
+ if from_currency == to_currency
+ 1
+ else
+ @rates[Rate.new(from_currency, to_currency)] &&
+ @rates[Rate.new(from_currency, to_currency)].get(to_currency)
+ end
end
def convert(from_currency, to_currency, amount)
- get(from_currency, to_currency) * amount
+ from_currency == to_currency ? amount : get(from_currency, to_currency) * amount
end
end
class Money
class Unknown < Exception
end
+ class IncompatibleCurrencies < Exception
+ end
+
attr_reader :amount, :currency
def initialize(amount, currency)
@amount, @currency = amount, currency
end
def to_s
"#{@amount.to_s('F')} #{@currency.to_s}"
end
def in(currency, exchange_rate)
unless rate_value = exchange_rate.get(@currency, currency)
raise Unknown
end
Money.new(@amount * rate_value, currency)
+ end
+
+ def +(other)
+ money_operation :+, other
+ end
+
+ def -(other)
+ money_operation :-, other
+ end
+
+ def *(other)
+ numeric_operation :*, other
+ end
+
+ def /(other)
+ numeric_operation :/, other
+ end
+
+ private
+ def money_operation(operation, other)
+ if other.kind_of? Money
+ if other.currency == @currency
+ Money.new @amount.send(operation, other.amount), @currency
+ else
+ raise IncompatibleCurrencies
+ end
+ else
+ raise ArgumentError
+ end
+ end
+
+ def numeric_operation(operation, other)
+ if other.kind_of? Numeric
+ Money.new @amount.send(operation, other), @currency
+ else
+ raise ArgumentError
+ end
end
end

Валентин обнови решението на 16.01.2013 13:36 (преди около 11 години)

require 'bigdecimal'
require 'bigdecimal/util'
class ExchangeRate
attr_reader :rates
class Rate
attr_reader :from_currency, :to_currency
def initialize(from_currency, to_currency, rate = nil)
@from_currency, @to_currency, @rate = from_currency, to_currency, rate
end
def get(to_currency)
if to_currency == @to_currency
@rate
else
1/@rate
end
end
def hash
@from_currency.hash + @to_currency.hash
end
def eql?(other)
other.class == self.class &&
(@from_currency == other.from_currency && @to_currency == other.to_currency ||
@from_currency == other.to_currency && @to_currency == other.from_currency)
end
end
def initialize
@rates = {}
end
def set(from_currency, to_currency, rate)
# TODO Има ли начин да вземем стойността на ключа,
# за да не се налага да пазя нова инстанция на Rate като стойност в хеша?
@rates[Rate.new(from_currency, to_currency)] = Rate.new(from_currency, to_currency, rate)
end
def get(from_currency, to_currency)
if from_currency == to_currency
1
else
@rates[Rate.new(from_currency, to_currency)] &&
@rates[Rate.new(from_currency, to_currency)].get(to_currency)
end
end
def convert(from_currency, to_currency, amount)
from_currency == to_currency ? amount : get(from_currency, to_currency) * amount
end
end
class Money
class Unknown < Exception
end
class IncompatibleCurrencies < Exception
end
+ include Comparable
+
attr_reader :amount, :currency
def initialize(amount, currency)
@amount, @currency = amount, currency
end
def to_s
- "#{@amount.to_s('F')} #{@currency.to_s}"
+ str = @amount.round(2).to_s('F')
+ dot_pos = str.index('.')
+ "#{str.length - dot_pos == 2 ? str + '0' : str} #{@currency.to_s}"
end
def in(currency, exchange_rate)
unless rate_value = exchange_rate.get(@currency, currency)
raise Unknown
end
Money.new(@amount * rate_value, currency)
end
def +(other)
money_operation :+, other
end
def -(other)
money_operation :-, other
end
def *(other)
numeric_operation :*, other
end
def /(other)
numeric_operation :/, other
+ end
+
+ def <=>(other)
+ if other.kind_of? Money
+ if @currency == other.currency
+ @amount <=> other.amount
+ else
+ raise IncompatibleCurrencies
+ end
+ else
+ raise ArgumentError
+ end
end
private
def money_operation(operation, other)
if other.kind_of? Money
if other.currency == @currency
Money.new @amount.send(operation, other.amount), @currency
else
raise IncompatibleCurrencies
end
else
raise ArgumentError
end
end
def numeric_operation(operation, other)
if other.kind_of? Numeric
Money.new @amount.send(operation, other), @currency
else
raise ArgumentError
end
end
end

Валентин обнови решението на 16.01.2013 13:38 (преди около 11 години)

require 'bigdecimal'
require 'bigdecimal/util'
class ExchangeRate
attr_reader :rates
class Rate
attr_reader :from_currency, :to_currency
def initialize(from_currency, to_currency, rate = nil)
@from_currency, @to_currency, @rate = from_currency, to_currency, rate
end
def get(to_currency)
if to_currency == @to_currency
@rate
else
1/@rate
end
end
def hash
@from_currency.hash + @to_currency.hash
end
def eql?(other)
other.class == self.class &&
(@from_currency == other.from_currency && @to_currency == other.to_currency ||
@from_currency == other.to_currency && @to_currency == other.from_currency)
end
end
def initialize
@rates = {}
end
def set(from_currency, to_currency, rate)
- # TODO Има ли начин да вземем стойността на ключа,
- # за да не се налага да пазя нова инстанция на Rate като стойност в хеша?
@rates[Rate.new(from_currency, to_currency)] = Rate.new(from_currency, to_currency, rate)
end
def get(from_currency, to_currency)
if from_currency == to_currency
1
else
@rates[Rate.new(from_currency, to_currency)] &&
@rates[Rate.new(from_currency, to_currency)].get(to_currency)
end
end
def convert(from_currency, to_currency, amount)
from_currency == to_currency ? amount : get(from_currency, to_currency) * amount
end
end
class Money
class Unknown < Exception
end
class IncompatibleCurrencies < Exception
end
include Comparable
attr_reader :amount, :currency
def initialize(amount, currency)
@amount, @currency = amount, currency
end
def to_s
str = @amount.round(2).to_s('F')
dot_pos = str.index('.')
"#{str.length - dot_pos == 2 ? str + '0' : str} #{@currency.to_s}"
end
def in(currency, exchange_rate)
unless rate_value = exchange_rate.get(@currency, currency)
raise Unknown
end
Money.new(@amount * rate_value, currency)
end
def +(other)
money_operation :+, other
end
def -(other)
money_operation :-, other
end
def *(other)
numeric_operation :*, other
end
def /(other)
numeric_operation :/, other
end
def <=>(other)
if other.kind_of? Money
if @currency == other.currency
@amount <=> other.amount
else
raise IncompatibleCurrencies
end
else
raise ArgumentError
end
end
private
def money_operation(operation, other)
if other.kind_of? Money
if other.currency == @currency
Money.new @amount.send(operation, other.amount), @currency
else
raise IncompatibleCurrencies
end
else
raise ArgumentError
end
end
def numeric_operation(operation, other)
if other.kind_of? Numeric
Money.new @amount.send(operation, other), @currency
else
raise ArgumentError
end
end
end