Skip to content

Commit

Permalink
patch for #issue/21, add #export_rate and #import_rates
Browse files Browse the repository at this point in the history
  • Loading branch information
semmons99 committed Aug 31, 2010
1 parent e211a70 commit c471834
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 4 deletions.
63 changes: 59 additions & 4 deletions lib/money/bank/variable_exchange.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
require 'money/bank/base'
require 'json'
require 'yaml'

class Money
module Bank
# Thrown by VariableExchange#export_rates and VariableExchange#import_rates
# when an unknown rate format is requested.
class UnknownRateFormat < StandardError; end

# Class for aiding in exchanging money between different currencies.
# By default, the Money class uses an object of this class (accessible through
Expand All @@ -22,6 +27,8 @@ module Bank
#
class VariableExchange < Base

RATE_FORMATS = [:json, :ruby, :yaml]

def setup
@rates = {}
@mutex = Mutex.new
Expand Down Expand Up @@ -71,12 +78,60 @@ def get_rate(from, to)
@mutex.synchronize { @rates[rate_key_for(from, to)] }
end

# Return the known rates as a string in the format specified. If +file+
# is given will also write the string out to the file specified.
# Available formats are +:json+, +:ruby+ and +:yaml+.
#
# Raises +Money::Bank::UnknownRateFormat+ if format is unknown.
def export_rates(format, file=nil)
raise Money::Bank::UnknownRateFormat unless
RATE_FORMATS.include? format

s = ""
@mutex.synchronize {
s = case format
when :json
@rates.to_json
when :ruby
Marshal.dump(@rates)
when :yaml
@rates.to_yaml
end

unless file.nil?
File.open(file, "w").write(s)
end
}
s
end

# Loads rates provided in +s+ given the specified format. Available
# formats are +:json+, +:ruby+ and +:yaml+.
#
# Raises +Money::Bank::UnknownRateFormat+ if format is unknown.
def import_rates(format, s)
raise Money::Bank::UnknownRateFormat unless
RATE_FORMATS.include? format

@mutex.synchronize {
@rates = case format
when :json
JSON.load(s)
when :ruby
Marshal.load(s)
when :yaml
YAML.load(s)
end
}
self
end

private

# Return the rate hashkey for the given currencies.
def rate_key_for(from, to)
"#{Currency.wrap(from).iso_code}_TO_#{Currency.wrap(to).iso_code}".upcase
end
# Return the rate hashkey for the given currencies.
def rate_key_for(from, to)
"#{Currency.wrap(from).iso_code}_TO_#{Currency.wrap(to).iso_code}".upcase
end

end

Expand Down
81 changes: 81 additions & 0 deletions spec/bank/variable_exchange_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require "spec_helper"
require "json"
require "yaml"

describe Money::Bank::VariableExchange do

Expand Down Expand Up @@ -165,6 +167,85 @@
end
end

describe '#export_rates' do
before :each do
@bank.set_rate('USD', 'EUR', 1.25)
@bank.set_rate('USD', 'JPY', 2.55)
end

describe 'with format == :json' do
it 'should return rates formatted as json' do
rates_as_json = '{"USD_TO_EUR":1.25,"USD_TO_JPY":2.55}'
@bank.export_rates(:json).should == rates_as_json
end
end

describe 'with format == :ruby' do
it 'should return rates formatted as ruby objects' do
rates = {"USD_TO_EUR"=>1.25,"USD_TO_JPY"=>2.55}
@bank.export_rates(:ruby).should == Marshal.dump(rates)
end
end

describe 'with format == :yaml' do
it 'should return rates formatted as yaml' do
rates_as_yaml = "--- \nUSD_TO_EUR: 1.25\nUSD_TO_JPY: 2.55\n"
@bank.export_rates(:yaml).should == rates_as_yaml
end
end

describe 'with unknown format' do
it 'should raise `UnknownRateFormat`' do
lambda{@bank.export_rates(:foo)}.should raise_error Money::Bank::UnknownRateFormat
end
end

describe 'with :file provided' do
it 'should write rates to file' do
f = mock('IO')
File.should_receive(:open).with('null', 'w').and_return(f)
f.should_receive(:write).with('{"USD_TO_EUR":1.25,"USD_TO_JPY":2.55}')

@bank.export_rates(:json, 'null')
end
end
end

describe '#import_rates' do
describe 'with format == :json' do
it 'should load the rates provided' do
s = '{"USD_TO_EUR":1.25,"USD_TO_JPY":2.55}'
@bank.import_rates(:json, s)
@bank.get_rate('USD', 'EUR').should == 1.25
@bank.get_rate('USD', 'JPY').should == 2.55
end
end

describe 'with format == :ruby' do
it 'should load the rates provided' do
s = Marshal.dump({"USD_TO_EUR"=>1.25,"USD_TO_JPY"=>2.55})
@bank.import_rates(:ruby, s)
@bank.get_rate('USD', 'EUR').should == 1.25
@bank.get_rate('USD', 'JPY').should == 2.55
end
end

describe 'with format == :yaml' do
it 'should load the rates provided' do
s = "--- \nUSD_TO_EUR: 1.25\nUSD_TO_JPY: 2.55\n"
@bank.import_rates(:yaml, s)
@bank.get_rate('USD', 'EUR').should == 1.25
@bank.get_rate('USD', 'JPY').should == 2.55
end
end

describe 'with unknown format' do
it 'should raise `UnknownRateFormat`' do
lambda{@bank.import_rates(:foo, "")}.should raise_error Money::Bank::UnknownRateFormat
end
end
end

describe '#rate_key_for' do
it 'should accept str/str' do
lambda{@bank.send(:rate_key_for, 'USD', 'EUR')}.should_not raise_exception
Expand Down

0 comments on commit c471834

Please sign in to comment.