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.

Examples:

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

c1 = 100_00.to_money("USD")
c2 = 100_00.to_money("CAD")

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

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

Constant Summary

RATE_FORMATS =

Available formats for importing/exporting rates.

[:json, :ruby, :yaml]

Instance Attribute Summary collapse

Attributes inherited from Base

#rounding_method

Instance Method Summary collapse

Methods inherited from Base

#initialize, instance, #same_currency?

Constructor Details

This class inherits a constructor from Money::Bank::Base

Instance Attribute Details

#mutexObject (readonly)

Returns the value of attribute mutex



33
34
35
# File 'lib/money/bank/variable_exchange.rb', line 33

def mutex
  @mutex
end

#ratesObject (readonly)

Returns the value of attribute rates



33
34
35
# File 'lib/money/bank/variable_exchange.rb', line 33

def rates
  @rates
end

Instance Method Details

#add_rate(from, to, rate) ⇒ Numeric

Registers a conversion rate and returns it (uses #set_rate).

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)


133
134
135
# File 'lib/money/bank/variable_exchange.rb', line 133

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

#calculate_fractional(from, to_currency) ⇒ Object



103
104
105
106
107
108
# File 'lib/money/bank/variable_exchange.rb', line 103

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



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

def exchange(fractional, rate, &block)
  ex = (fractional * BigDecimal.new(rate.to_s)).to_f
  if block_given?
    yield ex
  elsif @rounding_method
    @rounding_method.call(ex)
  else
    ex.to_s.to_i
  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 = 100_00.to_money("USD")
c2 = 100_00.to_money("CAD")

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

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

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.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/money/bank/variable_exchange.rb', line 87

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)
      Money.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

Options Hash (opts):

  • :without_mutex (Boolean)

    disables the usage of a mutex

Returns:

  • (String)

Raises:

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



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/money/bank/variable_exchange.rb', line 207

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

  s = ""
  fn = -> {
    s = case format
        when :json
          JSON.dump(@rates)
        when :ruby
          Marshal.dump(@rates)
        when :yaml
          YAML.dump(@rates)
        end

    unless file.nil?
      File.open(file, "w") {|f| f.write(s) }
    end
  }
  if opts[:without_mutex]
    fn.call
  else
    @mutex.synchronize { fn.call }
  end
  s
end

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

Retrieve the rate for the given currencies. Uses Mutex to synchronize data access.

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

Options Hash (opts):

  • :without_mutex (Boolean)

    disables the usage of a mutex

Returns:

  • (Numeric)


178
179
180
181
182
183
184
185
# File 'lib/money/bank/variable_exchange.rb', line 178

def get_rate(from, to, opts = {})
  fn = -> { @rates[rate_key_for(from, to)] }
  if opts[:without_mutex]
    fn.call
  else
    @mutex.synchronize { fn.call }
  end
end

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

Loads rates provided in s given the specified format. Available formats are :json, :ruby and :yaml.

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

Options Hash (opts):

  • :without_mutex (Boolean)

    disables the usage of a mutex

Returns:

  • (self)

Raises:

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



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

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

  fn = -> {
    @rates = case format
             when :json
               JSON.load(s)
             when :ruby
               Marshal.load(s)
             when :yaml
               YAML.load(s)
             end
  }
  if opts[:without_mutex]
    fn.call
  else
    @mutex.synchronize { fn.call }
  end
  self
end

#marshal_dumpObject



47
48
49
# File 'lib/money/bank/variable_exchange.rb', line 47

def marshal_dump
  [@rates, @rounding_method]
end

#marshal_load(arr) ⇒ Object



51
52
53
54
# File 'lib/money/bank/variable_exchange.rb', line 51

def marshal_load(arr)
  @rates, @rounding_method = arr
  @mutex = Mutex.new
end

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

Set the rate for the given currencies. Uses Mutex to synchronize data access.

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

Options Hash (opts):

  • :without_mutex (Boolean)

    disables the usage of a mutex

Returns:

  • (Numeric)


152
153
154
155
156
157
158
159
# File 'lib/money/bank/variable_exchange.rb', line 152

def set_rate(from, to, rate, opts = {})
  fn = -> { @rates[rate_key_for(from, to)] = rate }
  if opts[:without_mutex]
    fn.call
  else
    @mutex.synchronize { fn.call }
  end
end

#setupself

Setup rates hash and mutex for rates locking

Returns:

  • (self)


41
42
43
44
45
# File 'lib/money/bank/variable_exchange.rb', line 41

def setup
  @rates = {}
  @mutex = Mutex.new
  self
end