money 4.0.1 → 4.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,19 +1,21 @@
1
- require 'pathname'
2
-
3
- module CurrencyLoader
4
- extend self
5
-
6
- DATA_PATH = Pathname.new(__FILE__).dirname + "../../config/"
7
-
8
- # Loads and returns the currencies stored in JSON files in the config directory.
9
- #
10
- # @return [Hash]
11
- def load_currencies
12
- json = File.read(DATA_PATH + 'currency.json')
13
- currencies = JSON.parse(json, :symbolize_names => true)
14
-
15
- # merge the currencies kept for backwards compatibility
16
- json = File.read(DATA_PATH + 'currency_bc.json')
17
- currencies.merge!(JSON.parse(json, :symbolize_names => true))
18
- end
19
- end
1
+ module CurrencyLoader
2
+ extend self
3
+
4
+ DATA_PATH = File.expand_path("../../../config", __FILE__)
5
+
6
+ # Loads and returns the currencies stored in JSON files in the config directory.
7
+ #
8
+ # @return [Hash]
9
+ def load_currencies
10
+ currencies = parse_currency_file("currency.json")
11
+ currencies.merge! parse_currency_file("currency_bc.json")
12
+ end
13
+
14
+ private
15
+
16
+ def parse_currency_file(filename)
17
+ json = File.read("#{DATA_PATH}/#{filename}")
18
+ json.force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
19
+ JSON.parse(json, :symbolize_names => true)
20
+ end
21
+ end
data/lib/money/money.rb CHANGED
@@ -1,405 +1,411 @@
1
- # encoding: utf-8
2
- require 'money/bank/variable_exchange'
3
- require 'money/money/arithmetic'
4
- require 'money/money/parsing'
5
- require 'money/money/formatting'
6
-
7
- # Represents an amount of money in a given currency.
8
- class Money
9
- include Comparable
10
- include Arithmetic
11
- include Formatting
12
- include Parsing
13
-
14
- # The value of the money in cents.
15
- #
16
- # @return [Integer]
17
- attr_reader :cents
18
-
19
- # The currency the money is in.
20
- #
21
- # @return [Currency]
22
- attr_reader :currency
23
-
24
- # The +Money::Bank+ based object used to perform currency exchanges with.
25
- #
26
- # @return [Money::Bank::*]
27
- attr_reader :bank
28
-
29
- # Class Methods
30
- class << self
31
- # Each Money object is associated to a bank object, which is responsible
32
- # for currency exchange. This property allows you to specify the default
33
- # bank object. The default value for this property is an instance if
34
- # +Bank::VariableExchange.+ It allows one to specify custom exchange rates.
35
- #
36
- # @return [Money::Bank::*]
37
- attr_accessor :default_bank
38
-
39
- # The default currency, which is used when +Money.new+ is called without an
40
- # explicit currency argument. The default value is Currency.new("USD"). The
41
- # value must be a valid +Money::Currency+ instance.
42
- #
43
- # @return [Money::Currency]
44
- attr_accessor :default_currency
45
-
46
- # Use this to disable i18n even if it's used by other objects in your app.
47
- #
48
- # @return [true,false]
49
- attr_accessor :use_i18n
50
- end
51
-
52
- # Set the default bank for creating new +Money+ objects.
53
- self.default_bank = Bank::VariableExchange.instance
54
-
55
- # Set the default currency for creating new +Money+ object.
56
- self.default_currency = Currency.new("USD")
57
-
58
- # Default to using i18n
59
- self.use_i18n = true
60
-
61
- # Create a new money object with value 0.
62
- #
63
- # @param [Currency, String, Symbol] currency The currency to use.
64
- #
65
- # @return [Money]
66
- #
67
- # @example
68
- # Money.empty #=> #<Money @cents=0>
69
- def self.empty(currency = default_currency)
70
- Money.new(0, currency)
71
- end
72
-
73
- # Creates a new Money object of the given value, using the Canadian
74
- # dollar currency.
75
- #
76
- # @param [Integer] cents The cents value.
77
- #
78
- # @return [Money]
79
- #
80
- # @example
81
- # n = Money.ca_dollar(100)
82
- # n.cents #=> 100
83
- # n.currency #=> #<Money::Currency id: cad>
84
- def self.ca_dollar(cents)
85
- Money.new(cents, "CAD")
86
- end
87
-
88
- # Creates a new Money object of the given value, using the American dollar
89
- # currency.
90
- #
91
- # @param [Integer] cents The cents value.
92
- #
93
- # @return [Money]
94
- #
95
- # @example
96
- # n = Money.us_dollar(100)
97
- # n.cents #=> 100
98
- # n.currency #=> #<Money::Currency id: usd>
99
- def self.us_dollar(cents)
100
- Money.new(cents, "USD")
101
- end
102
-
103
- # Creates a new Money object of the given value, using the Euro currency.
104
- #
105
- # @param [Integer] cents The cents value.
106
- #
107
- # @return [Money]
108
- #
109
- # @example
110
- # n = Money.euro(100)
111
- # n.cents #=> 100
112
- # n.currency #=> #<Money::Currency id: eur>
113
- def self.euro(cents)
114
- Money.new(cents, "EUR")
115
- end
116
-
117
-
118
- # Creates a new Money object of +amount+ value in dollars,
119
- # with given +currency+.
120
- #
121
- # The amount value is expressed in +dollars+
122
- # where the +dollar+ is the main monetary unit,
123
- # opposite to the subunit-based representation
124
- # used internally by this library called +cents+.
125
- #
126
- # @param [Numeric] amount The money amount, in dollars.
127
- # @param [Currency, String, Symbol] currency The currency format.
128
- # @param [Money::Bank::*] bank The exchange bank to use.
129
- #
130
- # @return [Money]
131
- #
132
- # @example
133
- # Money.new_with_dollars(100)
134
- # #=> #<Money @cents=10000 @currency="USD">
135
- # Money.new_with_dollars(100, "USD")
136
- # #=> #<Money @cents=10000 @currency="USD">
137
- # Money.new_with_dollars(100, "EUR")
138
- # #=> #<Money @cents=10000 @currency="EUR">
139
- #
140
- # @see Money.new
141
- #
142
- def self.new_with_dollars(amount, currency = Money.default_currency, bank = Money.default_bank)
143
- money = from_numeric(amount, currency)
144
- # Hack! You can't change a bank
145
- money.instance_variable_set("@bank", bank)
146
- money
147
- end
148
- # Adds a new exchange rate to the default bank and return the rate.
149
- #
150
- # @param [Currency, String, Symbol] from_currency Currency to exchange from.
151
- # @param [Currency, String, Symbol] to_currency Currency to exchange to.
152
- # @param [Numeric] rate Rate to exchange with.
153
- #
154
- # @return [Numeric]
155
- #
156
- # @example
157
- # Money.add_rate("USD", "CAD", 1.25) #=> 1.25
158
- def self.add_rate(from_currency, to_currency, rate)
159
- Money.default_bank.add_rate(from_currency, to_currency, rate)
160
- end
161
-
162
-
163
- # Creates a new Money object of +cents+ value in cents,
164
- # with given +currency+.
165
- #
166
- # Alternatively you can use the convenience
167
- # methods like {Money.ca_dollar} and {Money.us_dollar}.
168
- #
169
- # @param [Integer] cents The money amount, in cents.
170
- # @param [Currency, String, Symbol] currency The currency format.
171
- # @param [Money::Bank::*] bank The exchange bank to use.
172
- #
173
- # @return [Money]
174
- #
175
- # @example
176
- # Money.new(100)
177
- # #=> #<Money @cents=100 @currency="USD">
178
- # Money.new(100, "USD")
179
- # #=> #<Money @cents=100 @currency="USD">
180
- # Money.new(100, "EUR")
181
- # #=> #<Money @cents=100 @currency="EUR">
182
- #
183
- # @see Money.new_with_dollars
184
- #
185
- def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
186
- @cents = cents.round.to_i
187
- @currency = Currency.wrap(currency)
188
- @bank = bank
189
- end
190
-
191
- # Returns the value of the money in dollars,
192
- # instead of in cents.
193
- #
194
- # @return [Float]
195
- #
196
- # @example
197
- # Money.new(100).dollars # => 1.0
198
- # Money.new_with_dollars(1).dollar # => 1.0
199
- #
200
- # @see #to_f
201
- # @see #cents
202
- #
203
- def dollars
204
- to_f
205
- end
206
-
207
- # Return string representation of currency object
208
- #
209
- # @return [String]
210
- #
211
- # @example
212
- # Money.new(100, :USD).currency_as_string #=> "USD"
213
- def currency_as_string
214
- self.currency.to_s
215
- end
216
-
217
- # Set currency object using a string
218
- #
219
- # @param [String] val The currency string.
220
- #
221
- # @return [Money::Currency]
222
- #
223
- # @example
224
- # Money.new(100).currency_as_string("CAD") #=> #<Money::Currency id: cad>
225
- def currency_as_string=(val)
226
- @currency = Currency.wrap(val)
227
- end
228
-
229
- # Returns a Fixnum hash value based on the +cents+ and +currency+ attributes
230
- # in order to use functions like & (intersection), group_by, etc.
231
- #
232
- # @return [Fixnum]
233
- #
234
- # @example
235
- # Money.new(100).hash #=> 908351
236
- def hash
237
- [cents.hash, currency.hash].hash
238
- end
239
-
240
- # Uses +Currency#symbol+. If +nil+ is returned, defaults to "¤".
241
- #
242
- # @return [String]
243
- #
244
- # @example
245
- # Money.new(100, "USD").symbol #=> "$"
246
- def symbol
247
- currency.symbol || "¤"
248
- end
249
-
250
- # Returns the amount of money as a string.
251
- #
252
- # @return [String]
253
- #
254
- # @example
255
- # Money.ca_dollar(100).to_s #=> "1.00"
256
- def to_s
257
- unit, subunit = cents.abs.divmod(currency.subunit_to_unit).map{|o| o.to_s}
258
- if currency.decimal_places == 0
259
- return "-#{unit}" if cents < 0
260
- return unit
261
- end
262
- subunit = (("0" * currency.decimal_places) + subunit)[(-1*currency.decimal_places)..-1]
263
- return "-#{unit}#{decimal_mark}#{subunit}" if cents < 0
264
- "#{unit}#{decimal_mark}#{subunit}"
265
- end
266
-
267
- # Return the amount of money as a BigDecimal.
268
- #
269
- # @return [BigDecimal]
270
- #
271
- # @example
272
- # Money.us_dollar(100).to_d => BigDecimal.new("1.0")
273
- def to_d
274
- BigDecimal.new(cents.to_s) / BigDecimal.new(currency.subunit_to_unit.to_s)
275
- end
276
-
277
- # Return the amount of money as a float. Floating points cannot guarantee
278
- # precision. Therefore, this function should only be used when you no longer
279
- # need to represent currency or working with another system that requires
280
- # decimals.
281
- #
282
- # @return [Float]
283
- #
284
- # @example
285
- # Money.us_dollar(100).to_f => 1.0
286
- def to_f
287
- to_d.to_f
288
- end
289
-
290
- # Receive the amount of this money object in another Currency.
291
- #
292
- # @param [Currency, String, Symbol] other_currency Currency to exchange to.
293
- #
294
- # @return [Money]
295
- #
296
- # @example
297
- # Money.new(2000, "USD").exchange_to("EUR")
298
- # Money.new(2000, "USD").exchange_to(Currency.new("EUR"))
299
- def exchange_to(other_currency)
300
- other_currency = Currency.wrap(other_currency)
301
- @bank.exchange_with(self, other_currency)
302
- end
303
-
304
- # Receive a money object with the same amount as the current Money object
305
- # in american dollars.
306
- #
307
- # @return [Money]
308
- #
309
- # @example
310
- # n = Money.new(100, "CAD").as_us_dollar
311
- # n.currency #=> #<Money::Currency id: usd>
312
- def as_us_dollar
313
- exchange_to("USD")
314
- end
315
-
316
- # Receive a money object with the same amount as the current Money object
317
- # in canadian dollar.
318
- #
319
- # @return [Money]
320
- #
321
- # @example
322
- # n = Money.new(100, "USD").as_ca_dollar
323
- # n.currency #=> #<Money::Currency id: cad>
324
- def as_ca_dollar
325
- exchange_to("CAD")
326
- end
327
-
328
- # Receive a money object with the same amount as the current Money object
329
- # in euro.
330
- #
331
- # @return [Money]
332
- #
333
- # @example
334
- # n = Money.new(100, "USD").as_euro
335
- # n.currency #=> #<Money::Currency id: eur>
336
- def as_euro
337
- exchange_to("EUR")
338
- end
339
-
340
- # Conversation to +self+.
341
- #
342
- # @return [self]
343
- def to_money
344
- self
345
- end
346
-
347
- # Common inspect function
348
- #
349
- # @return [String]
350
- def inspect
351
- "#<Money cents:#{cents} currency:#{currency}>"
352
- end
353
-
354
- # Allocates money between different parties without loosing pennies.
355
- # After the mathmatically split has been performed, left over pennies will
356
- # be distributed round-robin amongst the parties. This means that parties
357
- # listed first will likely recieve more pennies then ones that are listed later
358
- #
359
- # @param [0.50, 0.25, 0.25] to give 50% of the cash to party1, 25% ot party2, and 25% to party3.
360
- #
361
- # @return [Array<Money, Money, Money>]
362
- #
363
- # @example
364
- # Money.new(5, "USD").allocate([0.3,0.7)) #=> [Money.new(2), Money.new(3)]
365
- # Money.new(100, "USD").allocate([0.33,0.33,0.33]) #=> [Money.new(34), Money.new(33), Money.new(33)]
366
- def allocate(splits)
367
- allocations = splits.inject(0.0) {|sum, i| sum += i }
368
- raise ArgumentError, "splits add to more then 100%" if (allocations - 1.0) > Float::EPSILON
369
-
370
- left_over = cents
371
-
372
- amounts = splits.collect do |ratio|
373
- fraction = (cents * ratio / allocations).floor
374
- left_over -= fraction
375
- fraction
376
- end
377
-
378
- left_over.times { |i| amounts[i % amounts.length] += 1 }
379
-
380
- return amounts.collect { |cents| Money.new(cents, currency) }
381
- end
382
-
383
- # Split money amongst parties evenly without loosing pennies.
384
- #
385
- # @param [2] number of parties.
386
- #
387
- # @return [Array<Money, Money, Money>]
388
- #
389
- # @example
390
- # Money.new(100, "USD").split(3) #=> [Money.new(34), Money.new(33), Money.new(33)]
391
- def split(num)
392
- raise ArgumentError, "need at least one party" if num < 1
393
- low = Money.new(cents / num)
394
- high = Money.new(low.cents + 1)
395
-
396
- remainder = cents % num
397
- result = []
398
-
399
- num.times do |index|
400
- result[index] = index < remainder ? high : low
401
- end
402
-
403
- return result
404
- end
405
- end
1
+ # encoding: utf-8
2
+ require 'money/bank/variable_exchange'
3
+ require 'money/money/arithmetic'
4
+ require 'money/money/parsing'
5
+ require 'money/money/formatting'
6
+
7
+ # Represents an amount of money in a given currency.
8
+ class Money
9
+ include Comparable
10
+ include Arithmetic
11
+ include Formatting
12
+ include Parsing
13
+
14
+ # The value of the money in cents.
15
+ #
16
+ # @return [Integer]
17
+ attr_reader :cents
18
+
19
+ # The currency the money is in.
20
+ #
21
+ # @return [Currency]
22
+ attr_reader :currency
23
+
24
+ # The +Money::Bank+ based object used to perform currency exchanges with.
25
+ #
26
+ # @return [Money::Bank::*]
27
+ attr_reader :bank
28
+
29
+ # Class Methods
30
+ class << self
31
+ # Each Money object is associated to a bank object, which is responsible
32
+ # for currency exchange. This property allows you to specify the default
33
+ # bank object. The default value for this property is an instance if
34
+ # +Bank::VariableExchange.+ It allows one to specify custom exchange rates.
35
+ #
36
+ # @return [Money::Bank::*]
37
+ attr_accessor :default_bank
38
+
39
+ # The default currency, which is used when +Money.new+ is called without an
40
+ # explicit currency argument. The default value is Currency.new("USD"). The
41
+ # value must be a valid +Money::Currency+ instance.
42
+ #
43
+ # @return [Money::Currency]
44
+ attr_accessor :default_currency
45
+
46
+ # Use this to disable i18n even if it's used by other objects in your app.
47
+ #
48
+ # @return [true,false]
49
+ attr_accessor :use_i18n
50
+ end
51
+
52
+ # Set the default bank for creating new +Money+ objects.
53
+ self.default_bank = Bank::VariableExchange.instance
54
+
55
+ # Set the default currency for creating new +Money+ object.
56
+ self.default_currency = Currency.new("USD")
57
+
58
+ # Default to using i18n
59
+ self.use_i18n = true
60
+
61
+ # Create a new money object with value 0.
62
+ #
63
+ # @param [Currency, String, Symbol] currency The currency to use.
64
+ #
65
+ # @return [Money]
66
+ #
67
+ # @example
68
+ # Money.empty #=> #<Money @cents=0>
69
+ def self.empty(currency = default_currency)
70
+ Money.new(0, currency)
71
+ end
72
+
73
+ # Creates a new Money object of the given value, using the Canadian
74
+ # dollar currency.
75
+ #
76
+ # @param [Integer] cents The cents value.
77
+ #
78
+ # @return [Money]
79
+ #
80
+ # @example
81
+ # n = Money.ca_dollar(100)
82
+ # n.cents #=> 100
83
+ # n.currency #=> #<Money::Currency id: cad>
84
+ def self.ca_dollar(cents)
85
+ Money.new(cents, "CAD")
86
+ end
87
+
88
+ # Creates a new Money object of the given value, using the American dollar
89
+ # currency.
90
+ #
91
+ # @param [Integer] cents The cents value.
92
+ #
93
+ # @return [Money]
94
+ #
95
+ # @example
96
+ # n = Money.us_dollar(100)
97
+ # n.cents #=> 100
98
+ # n.currency #=> #<Money::Currency id: usd>
99
+ def self.us_dollar(cents)
100
+ Money.new(cents, "USD")
101
+ end
102
+
103
+ # Creates a new Money object of the given value, using the Euro currency.
104
+ #
105
+ # @param [Integer] cents The cents value.
106
+ #
107
+ # @return [Money]
108
+ #
109
+ # @example
110
+ # n = Money.euro(100)
111
+ # n.cents #=> 100
112
+ # n.currency #=> #<Money::Currency id: eur>
113
+ def self.euro(cents)
114
+ Money.new(cents, "EUR")
115
+ end
116
+
117
+ # Creates a new Money object of +amount+ value in dollars,
118
+ # with given +currency+.
119
+ #
120
+ # The amount value is expressed in +dollars+
121
+ # where the +dollar+ is the main monetary unit,
122
+ # opposite to the subunit-based representation
123
+ # used internally by this library called +cents+.
124
+ #
125
+ # @param [Numeric] amount The money amount, in dollars.
126
+ # @param [Currency, String, Symbol] currency The currency format.
127
+ # @param [Money::Bank::*] bank The exchange bank to use.
128
+ #
129
+ # @return [Money]
130
+ #
131
+ # @example
132
+ # Money.new_with_dollars(100)
133
+ # #=> #<Money @cents=10000 @currency="USD">
134
+ # Money.new_with_dollars(100, "USD")
135
+ # #=> #<Money @cents=10000 @currency="USD">
136
+ # Money.new_with_dollars(100, "EUR")
137
+ # #=> #<Money @cents=10000 @currency="EUR">
138
+ #
139
+ # @see Money.new
140
+ #
141
+ def self.new_with_dollars(amount, currency = Money.default_currency, bank = Money.default_bank)
142
+ money = from_numeric(amount, currency)
143
+ # Hack! You can't change a bank
144
+ money.instance_variable_set("@bank", bank)
145
+ money
146
+ end
147
+
148
+ # Adds a new exchange rate to the default bank and return the rate.
149
+ #
150
+ # @param [Currency, String, Symbol] from_currency Currency to exchange from.
151
+ # @param [Currency, String, Symbol] to_currency Currency to exchange to.
152
+ # @param [Numeric] rate Rate to exchange with.
153
+ #
154
+ # @return [Numeric]
155
+ #
156
+ # @example
157
+ # Money.add_rate("USD", "CAD", 1.25) #=> 1.25
158
+ def self.add_rate(from_currency, to_currency, rate)
159
+ Money.default_bank.add_rate(from_currency, to_currency, rate)
160
+ end
161
+
162
+
163
+ # Creates a new Money object of +cents+ value in cents,
164
+ # with given +currency+.
165
+ #
166
+ # Alternatively you can use the convenience
167
+ # methods like {Money.ca_dollar} and {Money.us_dollar}.
168
+ #
169
+ # @param [Integer] cents The money amount, in cents.
170
+ # @param [Currency, String, Symbol] currency The currency format.
171
+ # @param [Money::Bank::*] bank The exchange bank to use.
172
+ #
173
+ # @return [Money]
174
+ #
175
+ # @example
176
+ # Money.new(100)
177
+ # #=> #<Money @cents=100 @currency="USD">
178
+ # Money.new(100, "USD")
179
+ # #=> #<Money @cents=100 @currency="USD">
180
+ # Money.new(100, "EUR")
181
+ # #=> #<Money @cents=100 @currency="EUR">
182
+ #
183
+ # @see Money.new_with_dollars
184
+ #
185
+ def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
186
+ @cents = cents.round.to_i
187
+ @currency = Currency.wrap(currency)
188
+ @bank = bank
189
+ end
190
+
191
+ # Returns the value of the money in dollars,
192
+ # instead of in cents.
193
+ #
194
+ # @return [Float]
195
+ #
196
+ # @example
197
+ # Money.new(100).dollars # => 1.0
198
+ # Money.new_with_dollars(1).dollar # => 1.0
199
+ #
200
+ # @see #to_f
201
+ # @see #cents
202
+ #
203
+ def dollars
204
+ to_f
205
+ end
206
+
207
+ # Return string representation of currency object
208
+ #
209
+ # @return [String]
210
+ #
211
+ # @example
212
+ # Money.new(100, :USD).currency_as_string #=> "USD"
213
+ def currency_as_string
214
+ currency.to_s
215
+ end
216
+
217
+ # Set currency object using a string
218
+ #
219
+ # @param [String] val The currency string.
220
+ #
221
+ # @return [Money::Currency]
222
+ #
223
+ # @example
224
+ # Money.new(100).currency_as_string("CAD") #=> #<Money::Currency id: cad>
225
+ def currency_as_string=(val)
226
+ @currency = Currency.wrap(val)
227
+ end
228
+
229
+ # Returns a Fixnum hash value based on the +cents+ and +currency+ attributes
230
+ # in order to use functions like & (intersection), group_by, etc.
231
+ #
232
+ # @return [Fixnum]
233
+ #
234
+ # @example
235
+ # Money.new(100).hash #=> 908351
236
+ def hash
237
+ [cents.hash, currency.hash].hash
238
+ end
239
+
240
+ # Uses +Currency#symbol+. If +nil+ is returned, defaults to "¤".
241
+ #
242
+ # @return [String]
243
+ #
244
+ # @example
245
+ # Money.new(100, "USD").symbol #=> "$"
246
+ def symbol
247
+ currency.symbol || "¤"
248
+ end
249
+
250
+ # Common inspect function
251
+ #
252
+ # @return [String]
253
+ def inspect
254
+ "#<Money cents:#{cents} currency:#{currency}>"
255
+ end
256
+
257
+ # Returns the amount of money as a string.
258
+ #
259
+ # @return [String]
260
+ #
261
+ # @example
262
+ # Money.ca_dollar(100).to_s #=> "1.00"
263
+ def to_s
264
+ unit, subunit = cents.abs.divmod(currency.subunit_to_unit).map{|o| o.to_s}
265
+ if currency.decimal_places == 0
266
+ return "-#{unit}" if cents < 0
267
+ return unit
268
+ end
269
+ subunit = (("0" * currency.decimal_places) + subunit)[(-1*currency.decimal_places)..-1]
270
+ return "-#{unit}#{decimal_mark}#{subunit}" if cents < 0
271
+ "#{unit}#{decimal_mark}#{subunit}"
272
+ end
273
+
274
+ # Return the amount of money as a BigDecimal.
275
+ #
276
+ # @return [BigDecimal]
277
+ #
278
+ # @example
279
+ # Money.us_dollar(100).to_d => BigDecimal.new("1.0")
280
+ def to_d
281
+ BigDecimal.new(cents.to_s) / BigDecimal.new(currency.subunit_to_unit.to_s)
282
+ end
283
+
284
+ # Return the amount of money as a float. Floating points cannot guarantee
285
+ # precision. Therefore, this function should only be used when you no longer
286
+ # need to represent currency or working with another system that requires
287
+ # decimals.
288
+ #
289
+ # @return [Float]
290
+ #
291
+ # @example
292
+ # Money.us_dollar(100).to_f => 1.0
293
+ def to_f
294
+ to_d.to_f
295
+ end
296
+
297
+ # Conversation to +self+.
298
+ #
299
+ # @return [self]
300
+ def to_money(given_currency = nil)
301
+ given_currency = Currency.wrap(given_currency) if given_currency
302
+ if given_currency.nil? || self.currency == given_currency
303
+ self
304
+ else
305
+ exchange_to(given_currency)
306
+ end
307
+ end
308
+
309
+ # Receive the amount of this money object in another Currency.
310
+ #
311
+ # @param [Currency, String, Symbol] other_currency Currency to exchange to.
312
+ #
313
+ # @return [Money]
314
+ #
315
+ # @example
316
+ # Money.new(2000, "USD").exchange_to("EUR")
317
+ # Money.new(2000, "USD").exchange_to(Currency.new("EUR"))
318
+ def exchange_to(other_currency)
319
+ other_currency = Currency.wrap(other_currency)
320
+ @bank.exchange_with(self, other_currency)
321
+ end
322
+
323
+ # Receive a money object with the same amount as the current Money object
324
+ # in american dollars.
325
+ #
326
+ # @return [Money]
327
+ #
328
+ # @example
329
+ # n = Money.new(100, "CAD").as_us_dollar
330
+ # n.currency #=> #<Money::Currency id: usd>
331
+ def as_us_dollar
332
+ exchange_to("USD")
333
+ end
334
+
335
+ # Receive a money object with the same amount as the current Money object
336
+ # in canadian dollar.
337
+ #
338
+ # @return [Money]
339
+ #
340
+ # @example
341
+ # n = Money.new(100, "USD").as_ca_dollar
342
+ # n.currency #=> #<Money::Currency id: cad>
343
+ def as_ca_dollar
344
+ exchange_to("CAD")
345
+ end
346
+
347
+ # Receive a money object with the same amount as the current Money object
348
+ # in euro.
349
+ #
350
+ # @return [Money]
351
+ #
352
+ # @example
353
+ # n = Money.new(100, "USD").as_euro
354
+ # n.currency #=> #<Money::Currency id: eur>
355
+ def as_euro
356
+ exchange_to("EUR")
357
+ end
358
+
359
+ # Allocates money between different parties without loosing pennies.
360
+ # After the mathmatically split has been performed, left over pennies will
361
+ # be distributed round-robin amongst the parties. This means that parties
362
+ # listed first will likely recieve more pennies then ones that are listed later
363
+ #
364
+ # @param [0.50, 0.25, 0.25] to give 50% of the cash to party1, 25% ot party2, and 25% to party3.
365
+ #
366
+ # @return [Array<Money, Money, Money>]
367
+ #
368
+ # @example
369
+ # Money.new(5, "USD").allocate([0.3,0.7)) #=> [Money.new(2), Money.new(3)]
370
+ # Money.new(100, "USD").allocate([0.33,0.33,0.33]) #=> [Money.new(34), Money.new(33), Money.new(33)]
371
+ def allocate(splits)
372
+ allocations = splits.inject(0.0) {|sum, i| sum += i }
373
+ raise ArgumentError, "splits add to more then 100%" if (allocations - 1.0) > Float::EPSILON
374
+
375
+ left_over = cents
376
+
377
+ amounts = splits.collect do |ratio|
378
+ fraction = (cents * ratio / allocations).floor
379
+ left_over -= fraction
380
+ fraction
381
+ end
382
+
383
+ left_over.times { |i| amounts[i % amounts.length] += 1 }
384
+
385
+ amounts.collect { |cents| Money.new(cents, currency) }
386
+ end
387
+
388
+ # Split money amongst parties evenly without loosing pennies.
389
+ #
390
+ # @param [2] number of parties.
391
+ #
392
+ # @return [Array<Money, Money, Money>]
393
+ #
394
+ # @example
395
+ # Money.new(100, "USD").split(3) #=> [Money.new(34), Money.new(33), Money.new(33)]
396
+ def split(num)
397
+ raise ArgumentError, "need at least one party" if num < 1
398
+ low = Money.new(cents / num)
399
+ high = Money.new(low.cents + 1)
400
+
401
+ remainder = cents % num
402
+ result = []
403
+
404
+ num.times do |index|
405
+ result[index] = index < remainder ? high : low
406
+ end
407
+
408
+ result
409
+ end
410
+
411
+ end