Class: Money::Bank::VariableExchange

Inherits:
Base
  • Object
show all
Defined in:
lib/money/bank/variable_exchange.rb

Overview

Class for aiding in exchanging money between different currencies. By default, the Money class uses an object of this class (accessible through Money#bank) for performing currency exchanges.

By default, Money::Bank::VariableExchange has no knowledge about conversion rates. One must manually specify them with add_rate, after which one can perform exchanges with #exchange_with.

Exchange rates are stored in memory using Money::RatesStore::Memory by default. Pass custom rates stores for other types of storage (file, database, etc)

Examples:

bank = Money::Bank::VariableExchange.new
bank.add_rate("USD", "CAD", 1.24515)
bank.add_rate("CAD", "USD", 0.803115)

c1 = Money.new(100_00, "USD")
c2 = Money.new(100_00, "CAD")

# Exchange 100 USD to CAD:
bank.exchange_with(c1, "CAD") #=> #<Money fractional:12451 currency:CAD>

# Exchange 100 CAD to USD:
bank.exchange_with(c2, "USD") #=> #<Money fractional:8031 currency:USD>

# With custom exchange rates storage
redis_store = MyCustomRedisStore.new(host: 'localhost:6379')
bank = Money::Bank::VariableExchange.new(redis_store)
# Store rates in redis
bank.add_rate 'USD', 'CAD', 0.98
# Get rate from redis
bank.get_rate 'USD', 'CAD'

Constant Summary

RATE_FORMATS =

Available formats for importing/exporting rates.

[:json, :ruby, :yaml].freeze
SERIALIZER_SEPARATOR =
'_TO_'.freeze
FORMAT_SERIALIZERS =
{:json => JSON, :ruby => Marshal, :yaml => YAML}.freeze

Instance Attribute Summary collapse

Attributes inherited from Base

#rounding_method

Instance Method Summary collapse

Methods inherited from Base

instance, #same_currency?, #setup

Constructor Details

#initialize(st = Money::RatesStore::Memory.new) {|n| ... } ⇒ VariableExchange

Initializes a new Money::Bank::VariableExchange object. It defaults to using an in-memory, thread safe store instance for storing exchange rates.

Parameters:

  • st (RateStore) (defaults to: Money::RatesStore::Memory.new)

    An exchange rate store, used to persist exchange rate pairs.

Yields:

  • (n)

    Optional block to use when rounding after exchanging one currency for another. See Money::bank::base



59
60
61
62
# File 'lib/money/bank/variable_exchange.rb', line 59

def initialize(st = Money::RatesStore::Memory.new, &block)
  @store = st
  super(&block)
end

Instance Attribute Details

#mutexObject (readonly)

Returns the value of attribute mutex



45
46
47
# File 'lib/money/bank/variable_exchange.rb', line 45

def mutex
  @mutex
end

#storeObject (readonly)

Returns the value of attribute store



45
46
47
# File 'lib/money/bank/variable_exchange.rb', line 45

def store
  @store
end

Instance Method Details

#add_rate(from, to, rate) ⇒ Numeric

Registers a conversion rate and returns it (uses #set_rate). Delegates to Money::RatesStore::Memory

Examples:

bank = Money::Bank::VariableExchange.new
bank.add_rate("USD", "CAD", 1.24515)
bank.add_rate("CAD", "USD", 0.803115)

Parameters:

  • from (Currency, String, Symbol)

    Currency to exchange from.

  • to (Currency, String, Symbol)

    Currency to exchange to.

  • rate (Numeric)

    Rate to use when exchanging currencies.

Returns:

  • (Numeric)


152
153
154
# File 'lib/money/bank/variable_exchange.rb', line 152

def add_rate(from, to, rate)
  set_rate(from, to, rate)
end

#calculate_fractional(from, to_currency) ⇒ Object



121
122
123
124
125
126
# File 'lib/money/bank/variable_exchange.rb', line 121

def calculate_fractional(from, to_currency)
  BigDecimal.new(from.fractional.to_s) / (
    BigDecimal.new(from.currency.subunit_to_unit.to_s) /
    BigDecimal.new(to_currency.subunit_to_unit.to_s)
  )
end

#exchange(fractional, rate, &block) ⇒ Object



128
129
130
131
132
133
134
135
136
137
# File 'lib/money/bank/variable_exchange.rb', line 128

def exchange(fractional, rate, &block)
  ex = fractional * BigDecimal.new(rate.to_s)
  if block_given?
    yield ex
  elsif @rounding_method
    @rounding_method.call(ex)
  else
    ex
  end
end

#exchange_with(from, to_currency) {|n| ... } ⇒ Money

Exchanges the given Money object to a new Money object in to_currency.

Examples:

bank = Money::Bank::VariableExchange.new
bank.add_rate("USD", "CAD", 1.24515)
bank.add_rate("CAD", "USD", 0.803115)

c1 = Money.new(100_00, "USD")
c2 = Money.new(100_00, "CAD")

# Exchange 100 USD to CAD:
bank.exchange_with(c1, "CAD") #=> #<Money fractional:12451 currency:CAD>

# Exchange 100 CAD to USD:
bank.exchange_with(c2, "USD") #=> #<Money fractional:8031 currency:USD>

Parameters:

  • from (Money)

    The Money object to exchange.

  • to_currency (Currency, String, Symbol)

    The currency to exchange to.

Yields:

  • (n)

    Optional block to use when rounding after exchanging one currency for another.

Yield Parameters:

  • n (Float)

    The resulting float after exchanging one currency for another.

Yield Returns:

  • (Integer)

Returns:

Raises:

  • Money::Bank::UnknownRate if the conversion rate is unknown.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/money/bank/variable_exchange.rb', line 105

def exchange_with(from, to_currency, &block)
  to_currency = Currency.wrap(to_currency)
  if from.currency == to_currency
    from
  else
    if rate = get_rate(from.currency, to_currency)
      fractional = calculate_fractional(from, to_currency)
      from.class.new(
        exchange(fractional, rate, &block), to_currency
      )
    else
      raise UnknownRate, "No conversion rate known for '#{from.currency.iso_code}' -> '#{to_currency}'"
    end
  end
end

#export_rates(format, file = nil, opts = {}) ⇒ String

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.

Examples:

bank = Money::Bank::VariableExchange.new
bank.set_rate("USD", "CAD", 1.24515)
bank.set_rate("CAD", "USD", 0.803115)

s = bank.export_rates(:json)
s #=> "{\"USD_TO_CAD\":1.24515,\"CAD_TO_USD\":0.803115}"

Parameters:

  • format (Symbol)

    Request format for the resulting string.

  • file (String) (defaults to: nil)

    Optional file location to write the rates to.

  • opts (Hash) (defaults to: {})

    Options hash to set special parameters. Backwards compatibility only.

Returns:

Raises:

  • Money::Bank::UnknownRateFormat if format is unknown.



215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/money/bank/variable_exchange.rb', line 215

def export_rates(format, file = nil, opts = {})
  raise Money::Bank::UnknownRateFormat unless
    RATE_FORMATS.include? format

  store.transaction do
    s = FORMAT_SERIALIZERS[format].dump(rates)

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

    s
  end
end

#get_rate(from, to, opts = {}) ⇒ Numeric

Retrieve the rate for the given currencies. data access. Delegates to Money::RatesStore::Memory

Examples:

bank = Money::Bank::VariableExchange.new
bank.set_rate("USD", "CAD", 1.24515)
bank.set_rate("CAD", "USD", 0.803115)

bank.get_rate("USD", "CAD") #=> 1.24515
bank.get_rate("CAD", "USD") #=> 0.803115

Parameters:

  • from (Currency, String, Symbol)

    Currency to exchange from.

  • to (Currency, String, Symbol)

    Currency to exchange to.

  • opts (Hash) (defaults to: {})

    Options hash to set special parameters. Backwards compatibility only.

Returns:

  • (Numeric)


192
193
194
# File 'lib/money/bank/variable_exchange.rb', line 192

def get_rate(from, to, opts = {})
  store.get_rate(Currency.wrap(from).iso_code, Currency.wrap(to).iso_code)
end

#import_rates(format, s, opts = {}) ⇒ self

Loads rates provided in s given the specified format. Available formats are :json, :ruby and :yaml. Delegates to Money::RatesStore::Memory

Examples:

s = "{\"USD_TO_CAD\":1.24515,\"CAD_TO_USD\":0.803115}"
bank = Money::Bank::VariableExchange.new
bank.import_rates(:json, s)

bank.get_rate("USD", "CAD") #=> 1.24515
bank.get_rate("CAD", "USD") #=> 0.803115

Parameters:

  • format (Symbol)

    The format of s.

  • s (String)

    The rates string.

  • opts (Hash) (defaults to: {})

    Options hash to set special parameters. Backwards compatibility only.

Returns:

  • (self)

Raises:

  • Money::Bank::UnknownRateFormat if format is unknown.



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/money/bank/variable_exchange.rb', line 256

def import_rates(format, s, opts = {})
  raise Money::Bank::UnknownRateFormat unless
    RATE_FORMATS.include? format

  store.transaction do
    data = FORMAT_SERIALIZERS[format].load(s)

    data.each do |key, rate|
      from, to = key.split(SERIALIZER_SEPARATOR)
      store.add_rate from, to, rate
    end
  end

  self
end

#marshal_dumpObject



64
65
66
# File 'lib/money/bank/variable_exchange.rb', line 64

def marshal_dump
  [store.marshal_dump, @rounding_method]
end

#marshal_load(arr) ⇒ Object



68
69
70
71
72
# File 'lib/money/bank/variable_exchange.rb', line 68

def marshal_load(arr)
  store_info = arr[0]
  @store = store_info.shift.new(*store_info)
  @rounding_method = arr[1]
end

#ratesObject

This should be deprecated.



231
232
233
234
235
# File 'lib/money/bank/variable_exchange.rb', line 231

def rates
  store.each_rate.each_with_object({}) do |(from,to,rate),hash|
    hash[[from, to].join(SERIALIZER_SEPARATOR)] = rate
  end
end

#set_rate(from, to, rate, opts = {}) ⇒ Numeric

Set the rate for the given currencies. access. Delegates to Money::RatesStore::Memory

Examples:

bank = Money::Bank::VariableExchange.new
bank.set_rate("USD", "CAD", 1.24515)
bank.set_rate("CAD", "USD", 0.803115)

Parameters:

  • from (Currency, String, Symbol)

    Currency to exchange from.

  • to (Currency, String, Symbol)

    Currency to exchange to.

  • rate (Numeric)

    Rate to use when exchanging currencies.

  • opts (Hash) (defaults to: {})

    Options hash to set special parameters. Backwards compatibility only.

Returns:

  • (Numeric)


171
172
173
# File 'lib/money/bank/variable_exchange.rb', line 171

def set_rate(from, to, rate, opts = {})
  store.add_rate(Currency.wrap(from).iso_code, Currency.wrap(to).iso_code, rate)
end