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

- (Object) mutex (readonly)

Returns the value of attribute mutex



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

def mutex
  @mutex
end

- (Object) rates (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

- (Numeric) add_rate(from, to, rate)

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)


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

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

- (Object) calculate_fractional(from, to_currency)



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

- (Object) exchange(fractional, rate, &block)



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

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

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>

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)

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

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

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}"

Options Hash (opts):

  • :without_mutex (Boolean)

    disables the usage of a mutex

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

- (Numeric) get_rate(from, to, opts = {})

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

Options Hash (opts):

  • :without_mutex (Boolean)

    disables the usage of a mutex



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

- (self) import_rates(format, s, opts = {})

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

Options Hash (opts):

  • :without_mutex (Boolean)

    disables the usage of a mutex

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

- (Object) marshal_dump



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

def marshal_dump
  [@rates, @rounding_method]
end

- (Object) marshal_load(arr)



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

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

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)

Options Hash (opts):

  • :without_mutex (Boolean)

    disables the usage of a mutex



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

- (self) setup

Setup rates hash and mutex for rates locking



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

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