Камелия обнови решението на 16.01.2013 07:16 (преди около 12 години)
+require 'bigdecimal'
+require 'bigdecimal/util'
+
+class ExchangeRate
+ attr_accessor :rates
+
+ def initialize
+ @rates = {}
+ end
+
+ def add_rate(from_currency, to_currency, rate)
+ @rates[from_currency] ||= {}
+ @rates[from_currency].store to_currency, rate
+ end
+
+ def set(from_currency, to_currency, rate)
+ return if from_currency == to_currency
+ add_rate from_currency, to_currency, rate
+ rate = 1 / rate
+ add_rate to_currency, from_currency, rate
+ end
+
+ def get(from_currency, to_currency)
+ return 1 if from_currency == to_currency
+ if @rates.has_key? from_currency and @rates.has_key? to_currency
+ @rates[from_currency][to_currency]
+ else
+ nil
+ end
+ end
+
+ def convert(from_currency, to_currency, amount)
+ rate = get(from_currency, to_currency)
+ if rate
+ amount * rate
+ else
+ raise Unknown
+ end
+ end
+
+ def self.const_missing(error)
+ if error.to_s == "Unknown"
+ const_set error, Class.new(RuntimeError)
+ else
+ super
+ end
+ end
+end
+
+class Money
+ include Comparable
+
+ attr_reader :amount, :currency
+
+ def initialize(amount, currency)
+ @amount = amount
+ @currency = currency
+ end
+
+ def to_s
+ whole_part = amount.truncate.to_s
+ partial_part = (amount.frac.to_s.match /(?<=\.)(\d){,2}/).to_s
+ if partial_part.size == 0 then whole_part + ".00 " + @currency.to_s
+ elsif partial_part.size == 1 then whole_part + "." + partial_part + "0 " + @currency.to_s
+ else whole_part + "." + partial_part + " " + @currency.to_s
+ end
+ end
+
+ def in(currency, exchange_rate)
+ Money.new exchange_rate.convert(@currency, currency, @amount).to_d, currency
+ end
+
+ def +(other)
+ raise ArgumentError if not other.instance_of? Money
+ if @currency == other.currency
+ Money.new (@amount + other.amount), @currency
+ else
+ raise IncompatibleCurrencies
+ end
+ end
+
+ def -(other)
+ raise ArgumentError if not other.instance_of? Money
+ if @currency == other.currency
+ Money.new (@amount - other.amount), @currency
+ else
+ raise IncompatibleCurrencies
+ end
+ end
+
+ def *(number)
+ raise ArgumentError if not number.is_a? Numeric
+ Money.new (@amount * number), @currency
+ end
+
+ def /(number)
+ raise ArgumentError if not number.is_a? Numeric
+ Money.new (@amount / number), @currency
+ end
+
+ def <=>(other)
+ if other.instance_of? Money and @currency == other.currency then @amount <=> other.amount
+ elsif other.instance_of? Money then raise IncompatibleCurrencies
+ else raise ArgumentError
+ end
+ end
+
+ def self.const_missing(error)
+ if error.to_s == "IncompatibleCurrencies"
+ const_set error, Class.new(ArgumentError)
+ else
+ super
+ end
+ end
+end