money 6.5.1 → 6.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,10 +16,37 @@ class Money
16
16
  extend Money::Currency::Loader
17
17
  extend Money::Currency::Heuristics
18
18
 
19
+ # Keeping cached instances in sync between threads
20
+ @@mutex = Mutex.new
21
+
22
+ # Thrown when a Currency has been registered without all the attributes
23
+ # which are required for the current action.
24
+ class MissingAttributeError < StandardError
25
+ def initialize(method, currency, attribute)
26
+ super(
27
+ "Can't call Currency.#{method} - currency '#{currency}' is missing "\
28
+ "the attribute '#{attribute}'"
29
+ )
30
+ end
31
+ end
32
+
19
33
  # Thrown when an unknown currency is requested.
20
34
  class UnknownCurrency < ArgumentError; end
21
35
 
22
36
  class << self
37
+ alias_method :original_new, :new
38
+ def new(id)
39
+ id = id.to_s.downcase
40
+ unless stringified_keys.include?(id)
41
+ raise UnknownCurrency, "Unknown currency '#{id}'"
42
+ end
43
+
44
+ @@mutex.synchronize { instances[id] } || super
45
+ end
46
+
47
+ def instances
48
+ @instances ||= Hash.new { |h, k| h[k] = original_new(k) }
49
+ end
23
50
 
24
51
  # Lookup a currency with given +id+ an returns a +Currency+ instance on
25
52
  # success, +nil+ otherwise.
@@ -103,7 +130,13 @@ class Money
103
130
  # Money::Currency.iso_codes()
104
131
  # [#<Currency ..USD>, 'CAD', 'EUR']...
105
132
  def all
106
- table.keys.map {|curr| Currency.new(curr)}.sort_by(&:priority)
133
+ table.keys.map do |curr|
134
+ c = Currency.new(curr)
135
+ if c.priority.nil?
136
+ raise MissingAttributeError.new(:all, c.id, :priority)
137
+ end
138
+ c
139
+ end.sort_by(&:priority)
107
140
  end
108
141
 
109
142
  # We need a string-based validator before creating an unbounded number of
@@ -135,6 +168,7 @@ class Money
135
168
  # @option delimiter [String] character between each thousands place
136
169
  def register(curr)
137
170
  key = curr.fetch(:iso_code).downcase.to_sym
171
+ @@mutex.synchronize { instances.delete(key.to_s) }
138
172
  @table[key] = curr
139
173
  @stringified_keys = stringify_keys
140
174
  end
@@ -171,40 +205,40 @@ class Money
171
205
  end
172
206
  end
173
207
 
174
- # @!attribute [r] id
208
+ # @!attribute [r] id
175
209
  # @return [Symbol] The symbol used to identify the currency, usually THE
176
210
  # lowercase +iso_code+ attribute.
177
- # @!attribute [r] priority
211
+ # @!attribute [r] priority
178
212
  # @return [Integer] A numerical value you can use to sort/group the
179
213
  # currency list.
180
- # @!attribute [r] iso_code
214
+ # @!attribute [r] iso_code
181
215
  # @return [String] The international 3-letter code as defined by the ISO
182
216
  # 4217 standard.
183
- # @!attribute [r] iso_numeric
217
+ # @!attribute [r] iso_numeric
184
218
  # @return [String] The international 3-numeric code as defined by the ISO
185
219
  # 4217 standard.
186
- # @!attribute [r] name
220
+ # @!attribute [r] name
187
221
  # @return [String] The currency name.
188
- # @!attribute [r] symbol
222
+ # @!attribute [r] symbol
189
223
  # @return [String] The currency symbol (UTF-8 encoded).
190
- # @!attribute [r] disambiguate_symbol
224
+ # @!attribute [r] disambiguate_symbol
191
225
  # @return [String] Alternative currency used if symbol is ambiguous
192
- # @!attribute [r] html_entity
226
+ # @!attribute [r] html_entity
193
227
  # @return [String] The html entity for the currency symbol
194
- # @!attribute [r] subunit
228
+ # @!attribute [r] subunit
195
229
  # @return [String] The name of the fractional monetary unit.
196
- # @!attribute [r] subunit_to_unit
230
+ # @!attribute [r] subunit_to_unit
197
231
  # @return [Integer] The proportion between the unit and the subunit
198
- # @!attribute [r] decimal_mark
232
+ # @!attribute [r] decimal_mark
199
233
  # @return [String] The decimal mark, or character used to separate the
200
234
  # whole unit from the subunit.
201
- # @!attribute [r] The
235
+ # @!attribute [r] The
202
236
  # @return [String] character used to separate thousands grouping of the
203
237
  # whole unit.
204
- # @!attribute [r] symbol_first
238
+ # @!attribute [r] symbol_first
205
239
  # @return [Boolean] Should the currency symbol precede the amount, or
206
240
  # should it come after?
207
- # @!attribute [r] smallest_denomination
241
+ # @!attribute [r] smallest_denomination
208
242
  # @return [Integer] Smallest amount of cash possible (in the subunit of
209
243
  # this currency)
210
244
 
@@ -214,6 +248,7 @@ class Money
214
248
 
215
249
  alias_method :separator, :decimal_mark
216
250
  alias_method :delimiter, :thousands_separator
251
+ alias_method :eql?, :==
217
252
 
218
253
  # Create a new +Currency+ object.
219
254
  #
@@ -225,10 +260,6 @@ class Money
225
260
  # @example
226
261
  # Money::Currency.new(:usd) #=> #<Money::Currency id: usd ...>
227
262
  def initialize(id)
228
- id = id.to_s.downcase
229
- unless self.class.stringified_keys.include?(id)
230
- raise UnknownCurrency, "Unknown currency '#{id}'"
231
- end
232
263
  @id = id.to_sym
233
264
  initialize_data!
234
265
  end
@@ -283,22 +314,6 @@ class Money
283
314
  end
284
315
  private :compare_ids
285
316
 
286
- # Compares +self+ with +other_currency+ and returns +true+ if the are the
287
- # same or if their +id+ attributes match.
288
- #
289
- # @param [Money::Currency] other_currency The currency to compare to.
290
- #
291
- # @return [Boolean]
292
- #
293
- # @example
294
- # c1 = Money::Currency.new(:usd)
295
- # c2 = Money::Currency.new(:jpy)
296
- # c1.eql? c1 #=> true
297
- # c1.eql? c2 #=> false
298
- def eql?(other_currency)
299
- self == other_currency
300
- end
301
-
302
317
  # Returns a Fixnum hash value based on the +id+ attribute in order to use
303
318
  # functions like & (intersection), group_by, etc.
304
319
  #
@@ -12,25 +12,27 @@ class Money
12
12
  end
13
13
 
14
14
  # Checks whether two money objects have the same currency and the same
15
- # amount. Checks against money objects with a different currency and checks
16
- # against objects that do not respond to #to_money will always return false.
15
+ # amount. If money objects have a different currency it will only be true
16
+ # if the amounts are both zero. Checks against objects that do not respond
17
+ # to #to_money, in which case, it will always return false.
17
18
  #
18
19
  # @param [Money] other_money Value to compare with.
19
20
  #
20
21
  # @return [Boolean]
21
22
  #
22
23
  # @example
23
- # Money.new(100) == Money.new(101) #=> false
24
- # Money.new(100) == Money.new(100) #=> true
25
- def ==(other_money)
24
+ # Money.new(100).eql?(Money.new(101)) #=> false
25
+ # Money.new(100).eql?(Money.new(100)) #=> true
26
+ # Money.new(0, "USD").eql?(Money.new(0, "EUR")) #=> true
27
+ def eql?(other_money)
26
28
  if other_money.respond_to?(:to_money)
27
29
  other_money = other_money.to_money
28
- fractional == other_money.fractional && currency == other_money.currency
30
+ (fractional == other_money.fractional && currency == other_money.currency) ||
31
+ (fractional == 0 && other_money.fractional == 0)
29
32
  else
30
33
  false
31
34
  end
32
35
  end
33
- alias_method :eql?, :==
34
36
 
35
37
  def <=>(val)
36
38
  if val.respond_to?(:to_money)
@@ -39,8 +41,6 @@ class Money
39
41
  val = val.exchange_to(currency)
40
42
  end
41
43
  fractional <=> val.fractional
42
- else
43
- raise ArgumentError, "Comparison of #{self.class} with #{val.inspect} failed"
44
44
  end
45
45
  end
46
46
 
@@ -15,7 +15,7 @@ class Money
15
15
  if self.class.use_i18n
16
16
  begin
17
17
  I18n.t name, :scope => "number.currency.format", :raise => true
18
- rescue I18n::MissingTranslationData => e
18
+ rescue I18n::MissingTranslationData
19
19
  I18n.t name, :scope =>"number.format", :default => (currency.send(method) || character)
20
20
  end
21
21
  else
@@ -184,24 +184,36 @@ class Money
184
184
  # due to equal symbols for different currencies. Uses the `disambiguate_symbol`.
185
185
  #
186
186
  # @example
187
- # Money.new(100, "USD").format(:disambiguate => false) #=> "$100.00"
188
- # Money.new(100, "CAD").format(:disambiguate => false) #=> "$100.00"
189
- # Money.new(100, "USD").format(:disambiguate => true) #=> "$100.00"
190
- # Money.new(100, "CAD").format(:disambiguate => true) #=> "C$100.00"
187
+ # Money.new(10000, "USD").format(:disambiguate => false) #=> "$100.00"
188
+ # Money.new(10000, "CAD").format(:disambiguate => false) #=> "$100.00"
189
+ # Money.new(10000, "USD").format(:disambiguate => true) #=> "$100.00"
190
+ # Money.new(10000, "CAD").format(:disambiguate => true) #=> "C$100.00"
191
191
  #
192
192
  # @option *rules [Boolean] :html_wrap_symbol (false) Wraps the currency symbol
193
193
  # in a html <span> tag.
194
194
  #
195
195
  # @example
196
- # Money.new(100, "USD").format(:disambiguate => false)
196
+ # Money.new(10000, "USD").format(:disambiguate => false)
197
197
  # #=> "<span class=\"currency_symbol\">$100.00</span>
198
198
  #
199
199
  # @option *rules [Symbol] :symbol_position (:before) `:before` if the currency
200
200
  # symbol goes before the amount, `:after` if it goes after.
201
201
  #
202
202
  # @example
203
- # Money.new(100, "USD").format(:symbol_position => :before) #=> "$100.00"
204
- # Money.new(100, "USD").format(:symbol_position => :after) #=> "100.00 $"
203
+ # Money.new(10000, "USD").format(:symbol_position => :before) #=> "$100.00"
204
+ # Money.new(10000, "USD").format(:symbol_position => :after) #=> "100.00 $"
205
+ #
206
+ # @option *rules [Boolean] :translate (true) `true` Checks for custom
207
+ # symbol definitions using I18n.
208
+ #
209
+ # @example
210
+ # # With the following entry in the translation files:
211
+ # # en:
212
+ # # number:
213
+ # # currency:
214
+ # # symbol:
215
+ # # CAD: "CAD$"
216
+ # Money.new(10000, "CAD").format(:translate => true) #=> "CAD$100.00"
205
217
  #
206
218
  # Note that the default rules can be defined through +Money.default_formatting_rules+ hash.
207
219
  #
@@ -212,6 +224,7 @@ class Money
212
224
 
213
225
  rules = default_formatting_rules.merge(rules)
214
226
  rules = localize_formatting_rules(rules)
227
+ rules = translate_formatting_rules(rules) if rules[:translate]
215
228
 
216
229
  if fractional == 0
217
230
  if rules[:display_free].respond_to?(:to_str)
@@ -343,6 +356,15 @@ class Money
343
356
  end
344
357
  end
345
358
 
359
+ def translate_formatting_rules(rules)
360
+ begin
361
+ rules[:symbol] = I18n.t currency.iso_code, :scope => "number.currency.symbol", :raise => true
362
+ rescue I18n::MissingTranslationData
363
+ # Do nothing
364
+ end
365
+ rules
366
+ end
367
+
346
368
  def localize_formatting_rules(rules)
347
369
  if currency.iso_code == "JPY" && I18n.locale == :ja
348
370
  rules[:symbol] = "円" unless rules[:symbol] == false
data/lib/money/money.rb CHANGED
@@ -15,7 +15,7 @@ require "money/money/formatting"
15
15
  #
16
16
  # @see http://en.wikipedia.org/wiki/Money
17
17
  class Money
18
- include Money::Arithmetic, Money::Formatting, Comparable
18
+ include Comparable, Money::Arithmetic, Money::Formatting
19
19
  extend Constructors
20
20
 
21
21
  # Raised when smallest denomination of a currency is not defined
@@ -94,12 +94,6 @@ class Money
94
94
  # this property is an instance of +Bank::VariableExchange.+ It allows
95
95
  # one to specify custom exchange rates.
96
96
  #
97
- # @!attribute default_currency
98
- # @return [Money::Currency] The default currency, which is used when
99
- # +Money.new+ is called without an explicit currency argument. The
100
- # default value is Currency.new("USD"). The value must be a valid
101
- # +Money::Currency+ instance.
102
- #
103
97
  # @!attribute default_formatting_rules
104
98
  # @return [Hash] Use this to define a default hash of rules for everytime
105
99
  # +Money#format+ is called. Rules provided on method call will be
@@ -123,11 +117,17 @@ class Money
123
117
  # @!attribute [rw] conversion_precision
124
118
  # @return [Fixnum] Use this to specify precision for converting Rational
125
119
  # to BigDecimal
126
- attr_accessor :default_bank, :default_currency, :default_formatting_rules,
120
+ attr_accessor :default_bank, :default_formatting_rules,
127
121
  :use_i18n, :infinite_precision, :conversion_precision
128
122
 
129
123
  # @attr_writer rounding_mode Use this to specify the rounding mode
130
- attr_writer :rounding_mode
124
+ #
125
+ # @!attribute default_currency
126
+ # @return [Money::Currency] The default currency, which is used when
127
+ # +Money.new+ is called without an explicit currency argument. The
128
+ # default value is Currency.new("USD"). The value must be a valid
129
+ # +Money::Currency+ instance.
130
+ attr_writer :rounding_mode, :default_currency
131
131
 
132
132
  end
133
133
 
@@ -211,13 +211,35 @@ class Money
211
211
  self.default_bank = Bank::SingleCurrency.instance
212
212
  end
213
213
 
214
+ # Creates a new Money object of value given in the +unit+ of the given
215
+ # +currency+.
216
+ #
217
+ # @param [Numeric] amount The numerical value of the money.
218
+ # @param [Currency, String, Symbol] currency The currency format.
219
+ # @param [Money::Bank::*] bank The exchange bank to use.
220
+ #
221
+ # @example
222
+ # Money.from_amount(23.45, "USD") # => #<Money fractional:2345 currency:USD>
223
+ # Money.from_amount(23.45, "JPY") # => #<Money fractional:23 currency:JPY>
224
+ #
225
+ # @return [Money]
226
+ #
227
+ # @see #initialize
228
+ def self.from_amount(amount, currency = default_currency, bank = default_bank)
229
+ Numeric === amount or raise ArgumentError, "'amount' must be numeric"
230
+ currency = Currency.wrap(currency)
231
+ value = amount.to_d * currency.subunit_to_unit
232
+ value = value.round(0, rounding_mode) unless infinite_precision
233
+ new(value, currency, bank)
234
+ end
235
+
214
236
  # Creates a new Money object of value given in the
215
237
  # +fractional unit+ of the given +currency+.
216
238
  #
217
239
  # Alternatively you can use the convenience
218
240
  # methods like {Money.ca_dollar} and {Money.us_dollar}.
219
241
  #
220
- # @param [Object] obj Either The fractional value of the money,
242
+ # @param [Object] obj Either the fractional value of the money,
221
243
  # a Money object, or a currency. (If passed a currency as the first
222
244
  # argument, a Money will be created in that currency with fractional value
223
245
  # = 0.
@@ -0,0 +1,120 @@
1
+ class Money
2
+ module RatesStore
3
+
4
+ # Class for thread-safe storage of exchange rate pairs.
5
+ # Used by instances of +Money::Bank::VariableExchange+.
6
+ #
7
+ # @example
8
+ # store = Money::RatesStore::Memory.new
9
+ # store.add_rate 'USD', 'CAD', 0.98
10
+ # store.get_rate 'USD', 'CAD' # => 0.98
11
+ # # iterates rates
12
+ # store.each_rate {|iso_from, iso_to, rate| puts "#{from} -> #{to}: #{rate}" }
13
+ class Memory
14
+ INDEX_KEY_SEPARATOR = '_TO_'.freeze
15
+
16
+ # Initializes a new +Money::RatesStore::Memory+ object.
17
+ #
18
+ # @param [Hash] opts Optional store options.
19
+ # @option opts [Boolean] :without_mutex disables the usage of a mutex
20
+ # @param [Hash] rt Optional initial exchange rate data.
21
+ def initialize(opts = {}, rt = {})
22
+ @options, @index = opts, rt
23
+ @mutex = Mutex.new
24
+ @in_transaction = false
25
+ end
26
+
27
+ # Registers a conversion rate and returns it. Uses +Mutex+ to synchronize data access.
28
+ #
29
+ # @param [String] currency_iso_from Currency to exchange from.
30
+ # @param [String] currency_iso_to Currency to exchange to.
31
+ # @param [Numeric] rate Rate to use when exchanging currencies.
32
+ #
33
+ # @return [Numeric]
34
+ #
35
+ # @example
36
+ # store = Money::RatesStore::Memory.new
37
+ # store.add_rate("USD", "CAD", 1.24515)
38
+ # store.add_rate("CAD", "USD", 0.803115)
39
+ def add_rate(currency_iso_from, currency_iso_to, rate)
40
+ transaction { index[rate_key_for(currency_iso_from, currency_iso_to)] = rate }
41
+ end
42
+
43
+ # Retrieve the rate for the given currencies. Uses +Mutex+ to synchronize data access.
44
+ # Delegates to +Money::RatesStore::Memory+
45
+ #
46
+ # @param [String] currency_iso_from Currency to exchange from.
47
+ # @param [String] currency_iso_to Currency to exchange to.
48
+ #
49
+ # @return [Numeric]
50
+ #
51
+ # @example
52
+ # store = Money::RatesStore::Memory.new
53
+ # store.add_rate("USD", "CAD", 1.24515)
54
+ #
55
+ # store.get_rate("USD", "CAD") #=> 1.24515
56
+ def get_rate(currency_iso_from, currency_iso_to)
57
+ transaction { index[rate_key_for(currency_iso_from, currency_iso_to)] }
58
+ end
59
+
60
+ def marshal_dump
61
+ [self.class, index, options]
62
+ end
63
+
64
+
65
+ # Wraps block execution in a thread-safe transaction
66
+ def transaction(&block)
67
+ if @in_transaction || options[:without_mutex]
68
+ block.call self
69
+ else
70
+ @mutex.synchronize do
71
+ @in_transaction = true
72
+ result = block.call
73
+ @in_transaction = false
74
+ result
75
+ end
76
+ end
77
+ end
78
+
79
+ # Iterate over rate tuples (iso_from, iso_to, rate)
80
+ #
81
+ # @yieldparam iso_from [String] Currency ISO string.
82
+ # @yieldparam iso_to [String] Currency ISO string.
83
+ # @yieldparam rate [Numeric] Exchange rate.
84
+ #
85
+ # @return [Enumerator]
86
+ #
87
+ # @example
88
+ # store.each_rate do |iso_from, iso_to, rate|
89
+ # puts [iso_from, iso_to, rate].join
90
+ # end
91
+ def each_rate(&block)
92
+ enum = Enumerator.new do |yielder|
93
+ index.each do |key, rate|
94
+ iso_from, iso_to = key.split(INDEX_KEY_SEPARATOR)
95
+ yielder.yield iso_from, iso_to, rate
96
+ end
97
+ end
98
+
99
+ block_given? ? enum.each(&block) : enum
100
+ end
101
+
102
+ private
103
+
104
+ attr_reader :index, :options
105
+
106
+ # Return the rate hashkey for the given currencies.
107
+ #
108
+ # @param [String] currency_iso_from The currency to exchange from.
109
+ # @param [String] currency_iso_to The currency to exchange to.
110
+ #
111
+ # @return [String]
112
+ #
113
+ # @example
114
+ # rate_key_for("USD", "CAD") #=> "USD_TO_CAD"
115
+ def rate_key_for(currency_iso_from, currency_iso_to)
116
+ [currency_iso_from, currency_iso_to].join(INDEX_KEY_SEPARATOR).upcase
117
+ end
118
+ end
119
+ end
120
+ end
data/lib/money/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Money
2
- VERSION = "6.5.1"
2
+ VERSION = "6.6.0"
3
3
  end
data/money.gemspec CHANGED
@@ -29,7 +29,7 @@ MSG
29
29
 
30
30
  s.add_development_dependency "bundler", "~> 1.3"
31
31
  s.add_development_dependency "rake"
32
- s.add_development_dependency "rspec", "~> 3.0.0"
32
+ s.add_development_dependency "rspec", "~> 3.2.0"
33
33
  s.add_development_dependency "yard", "~> 0.8"
34
34
  s.add_development_dependency "kramdown", "~> 1.1"
35
35
 
@@ -1,77 +1,81 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Money::Bank::Base do
3
+ class Money
4
+ module Bank
5
+ describe Base do
4
6
 
5
- describe ".instance" do
6
- it "is local to one class" do
7
- klass = Money::Bank::Base
8
- subclass = Class.new(Money::Bank::Base)
9
- expect(klass.instance).not_to eq subclass.instance
10
- end
11
- end
7
+ describe ".instance" do
8
+ it "is local to one class" do
9
+ klass = Base
10
+ subclass = Class.new(Base)
11
+ expect(klass.instance).not_to eq subclass.instance
12
+ end
13
+ end
12
14
 
13
- describe "#initialize" do
14
- it "accepts a block and stores @rounding_method" do
15
- proc = Proc.new { |n| n.ceil }
16
- bank = Money::Bank::Base.new(&proc)
17
- expect(bank.rounding_method).to eq proc
18
- end
19
- end
15
+ describe "#initialize" do
16
+ it "accepts a block and stores @rounding_method" do
17
+ proc = Proc.new { |n| n.ceil }
18
+ bank = Base.new(&proc)
19
+ expect(bank.rounding_method).to eq proc
20
+ end
21
+ end
20
22
 
21
- describe "#setup" do
22
- it "calls #setup after #initialize" do
23
- class MyBank < Money::Bank::Base
24
- attr_reader :setup_called
23
+ describe "#setup" do
24
+ it "calls #setup after #initialize" do
25
+ class MyBank < Base
26
+ attr_reader :setup_called
25
27
 
26
- def setup
27
- @setup_called = true
28
+ def setup
29
+ @setup_called = true
30
+ end
31
+ end
32
+
33
+ bank = MyBank.new
34
+ expect(bank.setup_called).to eq true
28
35
  end
29
36
  end
30
37
 
31
- bank = MyBank.new
32
- expect(bank.setup_called).to eq true
33
- end
34
- end
35
-
36
- describe "#exchange_with" do
37
- it "is not implemented" do
38
- expect { subject.exchange_with(Money.new(100, 'USD'), 'EUR') }.to raise_exception(NotImplementedError)
39
- end
40
- end
38
+ describe "#exchange_with" do
39
+ it "is not implemented" do
40
+ expect { subject.exchange_with(Money.new(100, 'USD'), 'EUR') }.to raise_exception(NotImplementedError)
41
+ end
42
+ end
41
43
 
42
- describe "#same_currency?" do
43
- it "accepts str/str" do
44
- expect { subject.send(:same_currency?, 'USD', 'EUR') }.to_not raise_exception
45
- end
44
+ describe "#same_currency?" do
45
+ it "accepts str/str" do
46
+ expect { subject.send(:same_currency?, 'USD', 'EUR') }.to_not raise_exception
47
+ end
46
48
 
47
- it "accepts currency/str" do
48
- expect { subject.send(:same_currency?, Money::Currency.wrap('USD'), 'EUR') }.to_not raise_exception
49
- end
49
+ it "accepts currency/str" do
50
+ expect { subject.send(:same_currency?, Currency.wrap('USD'), 'EUR') }.to_not raise_exception
51
+ end
50
52
 
51
- it "accepts str/currency" do
52
- expect { subject.send(:same_currency?, 'USD', Money::Currency.wrap('EUR')) }.to_not raise_exception
53
- end
53
+ it "accepts str/currency" do
54
+ expect { subject.send(:same_currency?, 'USD', Currency.wrap('EUR')) }.to_not raise_exception
55
+ end
54
56
 
55
- it "accepts currency/currency" do
56
- expect { subject.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR')) }.to_not raise_exception
57
- end
57
+ it "accepts currency/currency" do
58
+ expect { subject.send(:same_currency?, Currency.wrap('USD'), Currency.wrap('EUR')) }.to_not raise_exception
59
+ end
58
60
 
59
- it "returns true when currencies match" do
60
- expect(subject.send(:same_currency?, 'USD', 'USD')).to be true
61
- expect(subject.send(:same_currency?, Money::Currency.wrap('USD'), 'USD')).to be true
62
- expect(subject.send(:same_currency?, 'USD', Money::Currency.wrap('USD'))).to be true
63
- expect(subject.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('USD'))).to be true
64
- end
61
+ it "returns true when currencies match" do
62
+ expect(subject.send(:same_currency?, 'USD', 'USD')).to be true
63
+ expect(subject.send(:same_currency?, Currency.wrap('USD'), 'USD')).to be true
64
+ expect(subject.send(:same_currency?, 'USD', Currency.wrap('USD'))).to be true
65
+ expect(subject.send(:same_currency?, Currency.wrap('USD'), Currency.wrap('USD'))).to be true
66
+ end
65
67
 
66
- it "returns false when currencies do not match" do
67
- expect(subject.send(:same_currency?, 'USD', 'EUR')).to be false
68
- expect(subject.send(:same_currency?, Money::Currency.wrap('USD'), 'EUR')).to be false
69
- expect(subject.send(:same_currency?, 'USD', Money::Currency.wrap('EUR'))).to be false
70
- expect(subject.send(:same_currency?, Money::Currency.wrap('USD'), Money::Currency.wrap('EUR'))).to be false
71
- end
68
+ it "returns false when currencies do not match" do
69
+ expect(subject.send(:same_currency?, 'USD', 'EUR')).to be false
70
+ expect(subject.send(:same_currency?, Currency.wrap('USD'), 'EUR')).to be false
71
+ expect(subject.send(:same_currency?, 'USD', Currency.wrap('EUR'))).to be false
72
+ expect(subject.send(:same_currency?, Currency.wrap('USD'), Currency.wrap('EUR'))).to be false
73
+ end
72
74
 
73
- it "raises an UnknownCurrency exception when an unknown currency is passed" do
74
- expect { subject.send(:same_currency?, 'AAA', 'BBB') }.to raise_exception(Money::Currency::UnknownCurrency)
75
+ it "raises an UnknownCurrency exception when an unknown currency is passed" do
76
+ expect { subject.send(:same_currency?, 'AAA', 'BBB') }.to raise_exception(Currency::UnknownCurrency)
77
+ end
78
+ end
75
79
  end
76
80
  end
77
81
  end
@@ -1,11 +1,15 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Money::Bank::SingleCurrency do
4
- describe "#exchange_with" do
5
- it "raises when called" do
6
- expect {
7
- subject.exchange_with(Money.new(100, 'USD'), 'EUR')
8
- }.to raise_exception(Money::Bank::DifferentCurrencyError, "No exchanging of currencies allowed: 1.00 USD to EUR")
3
+ class Money
4
+ module Bank
5
+ describe SingleCurrency do
6
+ describe "#exchange_with" do
7
+ it "raises when called" do
8
+ expect {
9
+ subject.exchange_with(Money.new(100, 'USD'), 'EUR')
10
+ }.to raise_exception(DifferentCurrencyError, "No exchanging of currencies allowed: 1.00 USD to EUR")
11
+ end
12
+ end
9
13
  end
10
14
  end
11
15
  end