Иван обнови решението на 12.01.2013 23:02 (преди около 12 години)
+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class ExchangeRate
+ class Unknown < RuntimeError
+ end
+
+ def initialize
+ @courses = {}
+ end
+
+ def set(from_currency, to_currency, rate)
+ @courses[[from_currency, to_currency]] = rate
+ @courses[[to_currency, from_currency]] = 1 / rate
+ end
+
+ def get(from_currency, to_currency)
+ if from_currency == to_currency then 1.to_d
+ else @courses[[from_currency, to_currency]]
+ end
+ end
+
+ def convert(from_currency, to_currency, amount)
+ if from_currency == to_currency then amount
+ elsif @courses[[from_currency, to_currency]]
+ (@courses[[from_currency, to_currency]] * amount).to_d
+ else raise ExchangeRate::Unknown
+ end
+ end
+end
+
+class Money
+ include Comparable
+
+ class IncompatibleCurrencies < ArgumentError
+ end
+
+ attr_reader :currency, :amount
+
+ def initialize(amount, currency)
+ @amount = amount
+ @currency = currency
+ end
+
+ def <=>(other)
+ if not other.class.to_s == 'Money' then raise ArgumentError
+ elsif not @currency == other.currency then raise Money::IncompatibleCurrencies
+ else @amount <=> other.amount
+ end
+ end
+
+ def transform(number)
+ if /\A*\.\d\z/ =~ number then number + '0'
+ else number
+ end
+ end
+
+ def to_s
+ "#{transform @amount.to_f.round(2).to_s } #{@currency}"
+ end
+
+ def in(current_currency, exchange_rate)
+ new_amount = exchange_rate.convert(@currency, current_currency, @amount)
+ Money.new(new_amount, current_currency)
+ end
+
+ def +(other)
+ if not other.class.to_s == 'Money' then raise ArgumentError
+ elsif not @currency == other.currency then raise Money::IncompatibleCurrencies
+ else Money.new amount + other.amount, currency
+ end
+ end
+
+ def -(other)
+ if not other.class.to_s == 'Money' then raise ArgumentError
+ elsif not @currency == other.currency then raise Money::IncompatibleCurrencies
+ else Money.new amount - other.amount, currency
+ end
+ end
+
+ def *(number)
+ if not number.is_a? Numeric then raise ArgumentError
+ else Money.new amount * number, currency
+ end
+ end
+
+ def /(number)
+ if not number.is_a? Numeric then raise ArgumentError
+ else Money.new amount / number, currency
+ end
+ end
+end