i'm testing small , simple library made in ruby. goal convert eur
cny
, vice versa. simple.
i tested sure works got unexpected issue. when use to_euro
followed to_yuan
should go original amount
; doesn't happen. tried .to_f
or round(2)
amount
variable fix tests, raise new ones, it's never equal expect globally ; i'm running out of idea fix :(
class currency attr_reader :amount, :currency def initialize(amount, currency='eur') @amount = amount @currency = currency end def to_yuan update_currency!('cny', amount * settings.instance.exchange_rate_to_yuan) end def to_euro update_currency!('eur', amount / settings.instance.exchange_rate_to_yuan) end def display "%.2f #{current_symbol}" % amount end private def current_symbol if currency == 'eur' symbol = settings.instance.supplier_currency.symbol elsif currency == 'cny' symbol = settings.instance.platform_currency.symbol end end def update_currency!(new_currency, new_amount) unless new_currency == currency @currency = new_currency @amount = new_amount end self end end
tests
describe currency let(:rate) { settings.instance.exchange_rate_to_yuan.to_f } context "#to_yuan" "should return currency object" expect(currency.new(20).to_yuan).to be_a(currency) end "should convert yuan" expect(currency.new(20).to_yuan.amount).to eql(20.00 * rate) end "should convert euro , yuan" # state data test currency = currency.new(150, 'cny') expect(currency.to_euro).to be_a(currency) expect(currency.to_yuan).to be_a(currency) expect(currency.amount).to eql(150.00) end end context "#to_euro" "should convert euro" expect(currency.new(150, 'cny').to_euro.amount).to eql(150 / rate) end end context "#display" "should display euros" expect(currency.new(10, 'eur').display).to eql("10.00 €") end "should display yuan" expect(currency.new(60.50, 'cny').display).to eql("60.50 ¥") end end end
and here's rspec result
i'm pretty sure problem common, idea how solve ?
float isn't exact number representation, stated in ruby docs:
float objects represent inexact real numbers using native architecture's double-precision floating point representation.
this not ruby fault, floats can represented fixed number of bytes , therefor cannot store decimal numbers correctly.
alternatively, can use ruby rational or bigdecimal
its common use money gem when dealing currency , money conversion.
Comments
Post a Comment