mmorga-money 2.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2005 Tobias Lutke
2
+ Copyright (c) 2008 Phusion
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,97 @@
1
+ = Introduction
2
+
3
+ This library aids one in handling money and different currencies. Features:
4
+
5
+ - Provides a Money class which encapsulates all information about an certain
6
+ amount of money, such as its value and its currency.
7
+ - Represents monetary values as integers, in cents. This avoids floating point
8
+ rounding errors.
9
+ - Provides APIs for exchanging money from one currency to another.
10
+ - Has the ability to parse a money string into a Money object.
11
+
12
+ Resources:
13
+
14
+ - Website: http://money.rubyforge.org
15
+ - RDoc API: http://money.rubyforge.org
16
+ - Git repository: http://github.com/FooBarWidget/money/tree/master
17
+
18
+ == Download
19
+
20
+ Install stable releases with the following command:
21
+
22
+ gem install money
23
+
24
+ The development version (hosted on Github) can be installed with:
25
+
26
+ gem sources -a http://gems.github.com
27
+ gem install FooBarWidget-money
28
+
29
+ == Usage
30
+
31
+ === Synopsis
32
+
33
+ require 'money'
34
+
35
+ # 10.00 USD
36
+ money = Money.new(1000, "USD")
37
+ money.cents # => 1000
38
+ money.currency # => "USD"
39
+
40
+ Money.new(1000, "USD") == Money.new(1000, "USD") # => true
41
+ Money.new(1000, "USD") == Money.new(100, "USD") # => false
42
+ Money.new(1000, "USD") == Money.new(1000, "EUR") # => false
43
+
44
+ === Currency Exchange
45
+
46
+ Exchanging money is performed through an exchange bank object. The default
47
+ exchange bank object requires one to manually specify the exchange rate. Here's
48
+ an example of how it works:
49
+
50
+ Money.add_rate("USD", "CAD", 1.24515)
51
+ Money.add_rate("CAD", "USD", 0.803115)
52
+
53
+ Money.us_dollar(100).exchange_to("CAD") # => Money.new(124, "CAD")
54
+ Money.ca_dollar(100).exchange_to("USD") # => Money.new(80, "USD")
55
+
56
+ Comparison and arithmetic operations work as expected:
57
+
58
+ Money.new(1000, "USD") <=> Money.new(900, "USD") # => 1; 9.00 USD is smaller
59
+ Money.new(1000, "EUR") + Money.new(10, "EUR") == Money.new(1010, "EUR")
60
+
61
+ Money.add_rate("USD", "EUR", 0.5)
62
+ Money.new(1000, "EUR") + Money.new(1000, "USD") == Money.new(1500, "EUR")
63
+
64
+ There is nothing stopping you from creating bank objects which scrapes
65
+ www.xe.com for the current rates or just returns <tt>rand(2)</tt>:
66
+
67
+ Money.default_bank = ExchangeBankWhichScrapesXeDotCom.new
68
+
69
+ === Ruby on Rails
70
+
71
+ Use the +compose_of+ helper to let Active Record deal with embedding the money
72
+ object in your models. The following example requires a +cents+ and a +currency+
73
+ field.
74
+
75
+ class ProductUnit < ActiveRecord::Base
76
+ belongs_to :product
77
+ composed_of :price, :class_name => "Money", :mapping => [%w(cents cents), %w(currency currency)]
78
+
79
+ private
80
+ validate :cents_not_zero
81
+
82
+ def cents_not_zero
83
+ errors.add("cents", "cannot be zero or less") unless cents > 0
84
+ end
85
+
86
+ validates_presence_of :sku, :currency
87
+ validates_uniqueness_of :sku
88
+ end
89
+
90
+ === Default Currency
91
+
92
+ By default Money defaults to USD as its currency. This can be overwritten using
93
+
94
+ Money.default_currency = "CAD"
95
+
96
+ If you use Rails, then environment.rb is a very good place to put this.
97
+
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ desc "Build a gem"
2
+ task :gem do
3
+ sh "gem build money.gemspec"
4
+ end
5
+
6
+ task "Generate RDoc documentation"
7
+ task :rdoc do
8
+ sh "hanna README.rdoc lib -U"
9
+ end
10
+
11
+ task :upload => :rdoc do
12
+ sh "scp -r doc/* rubyforge.org:/var/www/gforge-projects/money/"
13
+ end
14
+
15
+ desc "Run unit tests"
16
+ task :test do
17
+ ruby "-S spec -f s -c test/*_spec.rb"
18
+ end
@@ -0,0 +1,138 @@
1
+ class Numeric
2
+ # Converts this numeric to a Money object in the default currency. It
3
+ # multiplies the numeric value by 100 and treats that as cents.
4
+ #
5
+ # 100.to_money => #<Money @cents=10000>
6
+ # 100.37.to_money => #<Money @cents=10037>
7
+ def to_money
8
+ Money.new(self * 100)
9
+ end
10
+ end
11
+
12
+ class String
13
+ # Parses the current string and converts it to a Money object.
14
+ # Excess characters will be discarded.
15
+ #
16
+ # '100'.to_money # => #<Money @cents=10000>
17
+ # '100.37'.to_money # => #<Money @cents=10037>
18
+ # '100 USD'.to_money # => #<Money @cents=10000, @currency="USD">
19
+ # 'USD 100'.to_money # => #<Money @cents=10000, @currency="USD">
20
+ # '$100 USD'.to_money # => #<Money @cents=10000, @currency="USD">
21
+ # 'hello 2000 world'.to_money # => #<Money @cents=200000 @currency="USD")>
22
+ def to_money
23
+ # Get the currency.
24
+ matches = scan /([A-Z]{2,3})/
25
+ currency = matches[0] ? matches[0][0] : Money.default_currency
26
+ cents = calculate_cents(self)
27
+ Money.new(cents, currency)
28
+ end
29
+
30
+ private
31
+
32
+ def calculate_cents(number)
33
+ # remove anything that's not a number, potential delimiter, or minus sign
34
+ num = number.gsub(/[^\d|\.|,|\'|\s|\-]/, '').strip
35
+
36
+ # set a boolean flag for if the number is negative or not
37
+ negative = num.split(//).first == "-"
38
+
39
+ # if negative, remove the minus sign from the number
40
+ num = num.gsub(/^-/, '') if negative
41
+
42
+ # gather all separators within the result number
43
+ used_separators = num.scan /[^\d]/
44
+
45
+ # determine the number of unique separators within the number
46
+ #
47
+ # e.g.
48
+ # $1,234,567.89 would return 2 (, and .)
49
+ # $125,00 would return 1
50
+ # $199 would return 0
51
+ # $1 234,567.89 would raise an error (separators are space, comma, and period)
52
+ case used_separators.uniq.length
53
+ # no separator or delimiter; major (dollars) is the number, and minor (cents) is 0
54
+ when 0 then major, minor = num, 0
55
+
56
+ # two separators, so we know the last item in this array is the
57
+ # major/minor delimiter and the rest are separators
58
+ when 2
59
+ separator, delimiter = used_separators.uniq
60
+ # remove all separators, split on the delimiter
61
+ major, minor = num.gsub(separator, '').split(delimiter)
62
+ min = 0 unless min
63
+ when 1
64
+ # we can't determine if the comma or period is supposed to be a separator or a delimiter
65
+ # e.g.
66
+ # 1,00 - comma is a delimiter
67
+ # 1.000 - period is a delimiter
68
+ # 1,000 - comma is a separator
69
+ # 1,000,000 - comma is a separator
70
+ # 10000,00 - comma is a delimiter
71
+ # 1000,000 - comma is a delimiter
72
+
73
+ # assign first separator for reusability
74
+ separator = used_separators.first
75
+
76
+ # separator is used as a separator when there are multiple instances, always
77
+ if num.scan(separator).length > 1 # multiple matches; treat as separator
78
+ major, minor = num.gsub(separator, ''), 0
79
+ else
80
+ # ex: 1,000 - 1.0000 - 10001.000
81
+ # split number into possible major (dollars) and minor (cents) values
82
+ possible_major, possible_minor = num.split(separator)
83
+ possible_major ||= "0"
84
+ possible_minor ||= "00"
85
+
86
+ # if the minor (cents) length isn't 3, assign major/minor from the possibles
87
+ # e.g.
88
+ # 1,00 => 1.00
89
+ # 1.0000 => 1.00
90
+ # 1.2 => 1.20
91
+ if possible_minor.length != 3 # delimiter
92
+ major, minor = possible_major, possible_minor
93
+ else
94
+ # minor length is three
95
+ # let's try to figure out intent of the delimiter
96
+
97
+ # the major length is greater than three, which means
98
+ # the comma or period is used as a delimiter
99
+ # e.g.
100
+ # 1000,000
101
+ # 100000,000
102
+ if possible_major.length > 3
103
+ major, minor = possible_major, possible_minor
104
+ else
105
+ # number is in format ###{sep}### or ##{sep}### or #{sep}###
106
+ # handle as , is sep, . is delimiter
107
+ if separator == '.'
108
+ major, minor = possible_major, possible_minor
109
+ else
110
+ major, minor = "#{possible_major}#{possible_minor}", 0
111
+ end
112
+ end
113
+ end
114
+ end
115
+ else
116
+ raise ArgumentError, "Invalid currency amount"
117
+ end
118
+
119
+ # build the string based on major/minor since separator/delimiters have been removed
120
+ # avoiding floating point arithmetic here to ensure accuracy
121
+ cents = (major.to_i * 100)
122
+ # add the minor number as well. this may have any number of digits,
123
+ # so we treat minor as a string and truncate or right-fill it with zeroes
124
+ # until it becomes a two-digit number string, which we add to cents.
125
+ minor = minor.to_s
126
+ truncated_minor = minor[0..1]
127
+ truncated_minor << "0" * (2 - truncated_minor.size) if truncated_minor.size < 2
128
+ cents += truncated_minor.to_i
129
+ # respect rounding rules
130
+ if minor.size >= 3 && minor[2..2].to_i >= 5
131
+ cents += 1
132
+ end
133
+
134
+ # if negative, multiply by -1; otherwise, return positive cents
135
+ negative ? cents * -1 : cents
136
+ end
137
+
138
+ end
@@ -0,0 +1,4 @@
1
+ class Money
2
+ class UnknownRate < StandardError
3
+ end
4
+ end
@@ -0,0 +1,289 @@
1
+ require 'money/variable_exchange_bank'
2
+
3
+ # Represents an amount of money in a certain currency.
4
+ class Money
5
+ include Comparable
6
+
7
+ attr_reader :cents, :currency, :bank
8
+
9
+ class << self
10
+ # Each Money object is associated to a bank object, which is responsible
11
+ # for currency exchange. This property allows one to specify the default
12
+ # bank object.
13
+ #
14
+ # bank1 = MyBank.new
15
+ # bank2 = MyOtherBank.new
16
+ #
17
+ # Money.default_bank = bank1
18
+ # money1 = Money.new(10)
19
+ # money1.bank # => bank1
20
+ #
21
+ # Money.default_bank = bank2
22
+ # money2 = Money.new(10)
23
+ # money2.bank # => bank2
24
+ # money1.bank # => bank1
25
+ #
26
+ # The default value for this property is an instance if VariableExchangeBank.
27
+ # It allows one to specify custom exchange rates:
28
+ #
29
+ # Money.default_bank.add_rate("USD", "CAD", 1.24515)
30
+ # Money.default_bank.add_rate("CAD", "USD", 0.803115)
31
+ # Money.us_dollar(100).exchange_to("CAD") # => Money.ca_dollar(124)
32
+ # Money.ca_dollar(100).exchange_to("USD") # => Money.us_dollar(80)
33
+ attr_accessor :default_bank
34
+
35
+ # The default currency, which is used when <tt>Money.new</tt> is called
36
+ # without an explicit currency argument. The default value is "USD".
37
+ attr_accessor :default_currency
38
+ end
39
+
40
+ self.default_bank = VariableExchangeBank.instance
41
+ self.default_currency = "USD"
42
+
43
+
44
+ # Create a new money object with value 0.
45
+ def self.empty(currency = default_currency)
46
+ Money.new(0, currency)
47
+ end
48
+
49
+ # Creates a new Money object of the given value, using the Canadian dollar currency.
50
+ def self.ca_dollar(cents)
51
+ Money.new(cents, "CAD")
52
+ end
53
+
54
+ # Creates a new Money object of the given value, using the American dollar currency.
55
+ def self.us_dollar(cents)
56
+ Money.new(cents, "USD")
57
+ end
58
+
59
+ # Creates a new Money object of the given value, using the Euro currency.
60
+ def self.euro(cents)
61
+ Money.new(cents, "EUR")
62
+ end
63
+
64
+ def self.add_rate(from_currency, to_currency, rate)
65
+ Money.default_bank.add_rate(from_currency, to_currency, rate)
66
+ end
67
+
68
+
69
+ # Creates a new money object.
70
+ # Money.new(100)
71
+ #
72
+ # Alternativly you can use the convinience methods like
73
+ # Money.ca_dollar and Money.us_dollar
74
+ def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
75
+ @cents = cents.round
76
+ @currency = currency
77
+ @bank = bank
78
+ end
79
+
80
+ # Do two money objects equal? Only works if both objects are of the same currency
81
+ def ==(other_money)
82
+ other_money = other_money.to_money
83
+ cents == other_money.cents && bank.same_currency?(currency, other_money.currency)
84
+ end
85
+
86
+ def <=>(other_money)
87
+ other_money = other_money.to_money
88
+ if bank.same_currency?(currency, other_money.currency)
89
+ cents <=> other_money.cents
90
+ else
91
+ cents <=> other_money.exchange_to(currency).cents
92
+ end
93
+ end
94
+
95
+ def +(other_money)
96
+ other_money = other_money.to_money
97
+ if currency == other_money.currency
98
+ Money.new(cents + other_money.cents, other_money.currency)
99
+ else
100
+ Money.new(cents + other_money.exchange_to(currency).cents,currency)
101
+ end
102
+ end
103
+
104
+ def -(other_money)
105
+ other_money = other_money.to_money
106
+ if currency == other_money.currency
107
+ Money.new(cents - other_money.cents, other_money.currency)
108
+ else
109
+ Money.new(cents - other_money.exchange_to(currency).cents, currency)
110
+ end
111
+ end
112
+
113
+ # get the cents value of the object
114
+ def cents
115
+ @cents
116
+ end
117
+
118
+ # multiply money by fixnum
119
+ def *(fixnum)
120
+ Money.new(cents * fixnum, currency)
121
+ end
122
+
123
+ # divide money by fixnum
124
+ def /(fixnum)
125
+ Money.new(cents / fixnum, currency)
126
+ end
127
+
128
+ # Test if the money amount is zero
129
+ def zero?
130
+ cents == 0
131
+ end
132
+
133
+
134
+ # Creates a formatted price string according to several rules. The following
135
+ # options are supported: :display_free, :with_currency, :no_cents, :symbol
136
+ # and :html.
137
+ #
138
+ # === +:display_free+
139
+ #
140
+ # Whether a zero amount of money should be formatted of "free" or as the
141
+ # supplied string.
142
+ #
143
+ # Money.us_dollar(0).format(:display_free => true) => "free"
144
+ # Money.us_dollar(0).format(:display_free => "gratis") => "gratis"
145
+ # Money.us_dollar(0).format => "$0.00"
146
+ #
147
+ # === +:with_currency+
148
+ #
149
+ # Whether the currency name should be appended to the result string.
150
+ #
151
+ # Money.ca_dollar(100).format => "$1.00"
152
+ # Money.ca_dollar(100).format(:with_currency => true) => "$1.00 CAD"
153
+ # Money.us_dollar(85).format(:with_currency => true) => "$0.85 USD"
154
+ #
155
+ # === +:no_cents+
156
+ #
157
+ # Whether cents should be omitted.
158
+ #
159
+ # Money.ca_dollar(100).format(:no_cents => true) => "$1"
160
+ # Money.ca_dollar(599).format(:no_cents => true) => "$5"
161
+ #
162
+ # Money.ca_dollar(570).format(:no_cents => true, :with_currency => true) => "$5 CAD"
163
+ # Money.ca_dollar(39000).format(:no_cents => true) => "$390"
164
+ #
165
+ # === +:symbol+
166
+ #
167
+ # Whether a money symbol should be prepended to the result string. The default is true.
168
+ # This method attempts to pick a symbol that's suitable for the given currency.
169
+ #
170
+ # Money.new(100, "USD") => "$1.00"
171
+ # Money.new(100, "GBP") => "£1.00"
172
+ # Money.new(100, "EUR") => "€1.00"
173
+ #
174
+ # # Same thing.
175
+ # Money.new(100, "USD").format(:symbol => true) => "$1.00"
176
+ # Money.new(100, "GBP").format(:symbol => true) => "£1.00"
177
+ # Money.new(100, "EUR").format(:symbol => true) => "€1.00"
178
+ #
179
+ # You can specify a false expression or an empty string to disable prepending
180
+ # a money symbol:
181
+ #
182
+ # Money.new(100, "USD").format(:symbol => false) => "1.00"
183
+ # Money.new(100, "GBP").format(:symbol => nil) => "1.00"
184
+ # Money.new(100, "EUR").format(:symbol => "") => "1.00"
185
+ #
186
+ #
187
+ # If the symbol for the given currency isn't known, then it will default
188
+ # to "$" as symbol:
189
+ #
190
+ # Money.new(100, "AWG").format(:symbol => true) => "$1.00"
191
+ #
192
+ # You can specify a string as value to enforce using a particular symbol:
193
+ #
194
+ # Money.new(100, "AWG").format(:symbol => "ƒ") => "ƒ1.00"
195
+ #
196
+ # === +:html+
197
+ #
198
+ # Whether the currency should be HTML-formatted. Only useful in combination with +:with_currency+.
199
+ #
200
+ # Money.ca_dollar(570).format(:html => true, :with_currency => true)
201
+ # => "$5.70 <span class=\"currency\">CAD</span>"
202
+ def format(*rules)
203
+ # support for old format parameters
204
+ rules = normalize_formatting_rules(rules)
205
+
206
+ if cents == 0
207
+ if rules[:display_free].respond_to?(:to_str)
208
+ return rules[:display_free]
209
+ elsif rules[:display_free]
210
+ return "free"
211
+ end
212
+ end
213
+
214
+ if !rules.has_key?(:symbol) || rules[:symbol] === true
215
+ symbol = SYMBOLS[currency] || "$"
216
+ elsif rules[:symbol]
217
+ symbol = rules[:symbol]
218
+ else
219
+ symbol = ""
220
+ end
221
+
222
+ if rules[:no_cents]
223
+ formatted = sprintf("#{symbol}%d", cents.to_f / 100)
224
+ else
225
+ formatted = sprintf("#{symbol}%.2f", cents.to_f / 100)
226
+ end
227
+
228
+ # Commify ("10000" => "10,000")
229
+ formatted.gsub!(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/,'\1,\2')
230
+
231
+ if rules[:with_currency]
232
+ formatted << " "
233
+ formatted << '<span class="currency">' if rules[:html]
234
+ formatted << currency
235
+ formatted << '</span>' if rules[:html]
236
+ end
237
+ formatted
238
+ end
239
+
240
+ # Returns the amount of money as a string.
241
+ #
242
+ # Money.ca_dollar(100).to_s => "1.00"
243
+ def to_s
244
+ sprintf("%.2f", cents / 100.00)
245
+ end
246
+
247
+ # Recieve the amount of this money object in another currency.
248
+ def exchange_to(other_currency)
249
+ Money.new(@bank.exchange(self.cents, currency, other_currency), other_currency)
250
+ end
251
+
252
+ # Recieve a money object with the same amount as the current Money object
253
+ # in american dollar
254
+ def as_us_dollar
255
+ exchange_to("USD")
256
+ end
257
+
258
+ # Recieve a money object with the same amount as the current Money object
259
+ # in canadian dollar
260
+ def as_ca_dollar
261
+ exchange_to("CAD")
262
+ end
263
+
264
+ # Recieve a money object with the same amount as the current Money object
265
+ # in euro
266
+ def as_euro
267
+ exchange_to("EUR")
268
+ end
269
+
270
+ # Conversation to self
271
+ def to_money
272
+ self
273
+ end
274
+
275
+ private
276
+
277
+ def normalize_formatting_rules(rules)
278
+ if rules.size == 1
279
+ rules = rules.pop
280
+ rules = { rules => true } if rules.is_a?(Symbol)
281
+ else
282
+ rules = rules.inject({}) do |h,s|
283
+ h[s] = true
284
+ h
285
+ end
286
+ end
287
+ rules
288
+ end
289
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ # Add more from http://www.xe.com/symbols.php
4
+ Money::SYMBOLS = {
5
+ "GBP" => "£",
6
+ "JPY" => "¥",
7
+ "EUR" => "€",
8
+ "ZWD" => "Z$",
9
+ "CNY" => "¥",
10
+ "INR" => "₨",
11
+ "NPR" => "₨",
12
+ "SCR" => "₨",
13
+ "LKR" => "₨",
14
+ "SEK" => "kr",
15
+ "GHC" => "¢"
16
+
17
+ # Everything else defaults to $
18
+ }
@@ -0,0 +1,72 @@
1
+ require 'thread'
2
+ require 'money/errors'
3
+
4
+ # Class for aiding in exchanging money between different currencies.
5
+ # By default, the Money class uses an object of this class (accessible through
6
+ # Money#bank) for performing currency exchanges.
7
+ #
8
+ # By default, VariableExchangeBank has no knowledge about conversion rates.
9
+ # One must manually specify them with +add_rate+, after which one can perform
10
+ # exchanges with +exchange+. For example:
11
+ #
12
+ # bank = Money::VariableExchangeBank.new
13
+ # bank.add_rate("USD", "CAD", 1.24515)
14
+ # bank.add_rate("CAD", "USD", 0.803115)
15
+ #
16
+ # # Exchange 100 CAD to USD:
17
+ # bank.exchange(100_00, "CAD", "USD") # => 124
18
+ # # Exchange 100 USD to CAD:
19
+ # bank.exchange(100_00, "USD", "CAD") # => 80
20
+ class Money
21
+ class VariableExchangeBank
22
+ # Returns the singleton instance of VariableExchangeBank.
23
+ #
24
+ # By default, <tt>Money.default_bank</tt> returns the same object.
25
+ def self.instance
26
+ @@singleton
27
+ end
28
+
29
+ def initialize
30
+ @rates = {}
31
+ @mutex = Mutex.new
32
+ end
33
+
34
+ # Registers a conversion rate. +from+ and +to+ are both currency names.
35
+ def add_rate(from, to, rate)
36
+ @mutex.synchronize do
37
+ @rates["#{from}_TO_#{to}".upcase] = rate
38
+ end
39
+ end
40
+
41
+ # Gets the rate for exchanging the currency named +from+ to the currency
42
+ # named +to+. Returns nil if the rate is unknown.
43
+ def get_rate(from, to)
44
+ @mutex.synchronize do
45
+ @rates["#{from}_TO_#{to}".upcase]
46
+ end
47
+ end
48
+
49
+ # Given two currency names, checks whether they're both the same currency.
50
+ #
51
+ # bank = VariableExchangeBank.new
52
+ # bank.same_currency?("usd", "USD") # => true
53
+ # bank.same_currency?("usd", "EUR") # => false
54
+ def same_currency?(currency1, currency2)
55
+ currency1.upcase == currency2.upcase
56
+ end
57
+
58
+ # Exchange the given amount of cents in +from_currency+ to +to_currency+.
59
+ # Returns the amount of cents in +to_currency+ as an integer, rounded down.
60
+ #
61
+ # If the conversion rate is unknown, then Money::UnknownRate will be raised.
62
+ def exchange(cents, from_currency, to_currency)
63
+ rate = get_rate(from_currency, to_currency)
64
+ if !rate
65
+ raise Money::UnknownRate, "No conversion rate known for '#{from_currency}' -> '#{to_currency}'"
66
+ end
67
+ (cents * rate).floor
68
+ end
69
+
70
+ @@singleton = VariableExchangeBank.new
71
+ end
72
+ end
data/lib/money.rb ADDED
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2005 Tobias Luetke
2
+ # Copyright (c) 2008 Phusion
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
24
+ require 'money/money'
25
+ require 'money/symbols'
26
+ require 'money/core_extensions'
data/money.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "money"
3
+ s.version = "2.1.5"
4
+ s.summary = "Money and currency exchange support library"
5
+ s.email = ["hongli@phusion.nl", "mmorga@rackspace.com"]
6
+ s.homepage = "http://money.rubyforge.org/"
7
+ s.description = "Money and currency exchange support library."
8
+ s.has_rdoc = true
9
+ s.rubyforge_project = "money"
10
+ s.authors = ["Tobias Luetke", "Hongli Lai", "Jeremy McNevin", "Mark Morga"]
11
+
12
+ s.files = [
13
+ "README.rdoc", "MIT-LICENSE", "money.gemspec", "Rakefile",
14
+ "lib/money.rb",
15
+ "lib/money/core_extensions.rb",
16
+ "lib/money/errors.rb",
17
+ "lib/money/money.rb",
18
+ "lib/money/symbols.rb",
19
+ "lib/money/variable_exchange_bank.rb",
20
+ "test/core_extensions_spec.rb",
21
+ "test/exchange_bank_spec.rb",
22
+ "test/money_spec.rb"
23
+ ]
24
+ end
@@ -0,0 +1,73 @@
1
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
2
+ require 'money/core_extensions'
3
+
4
+ describe "Money core extensions" do
5
+ specify "Numberic#to_money works" do
6
+ money = 1234.to_money
7
+ money.cents.should == 1234_00
8
+ money.currency.should == Money.default_currency
9
+
10
+ money = 100.37.to_money
11
+ money.cents.should == 100_37
12
+ money.currency.should == Money.default_currency
13
+ end
14
+
15
+ specify "String#to_money works" do
16
+ "20.15".to_money.should == Money.new(20_15)
17
+ "100".to_money.should == Money.new(100_00)
18
+ "100.37".to_money.should == Money.new(100_37)
19
+ "100,37".to_money.should == Money.new(100_37)
20
+ "100 000".to_money.should == Money.new(100_000_00)
21
+ "100,000.00".to_money.should == Money.new(100_000_00)
22
+ "1,000".to_money.should == Money.new(1_000_00)
23
+ "-1,000".to_money.should == Money.new(-1_000_00)
24
+ "1,000.5".to_money.should == Money.new(1_000_50)
25
+ "1,000.51".to_money.should == Money.new(1_000_51)
26
+ "1,000.505".to_money.should == Money.new(1_000_51)
27
+ "1,000.504".to_money.should == Money.new(1_000_50)
28
+ "1,000.0000".to_money.should == Money.new(1_000_00)
29
+ "1,000.5000".to_money.should == Money.new(1_000_50)
30
+ "1,000.5099".to_money.should == Money.new(1_000_51)
31
+ "1.550".to_money.should == Money.new(1_55)
32
+ "25.".to_money.should == Money.new(25_00)
33
+ ".75".to_money.should == Money.new(75)
34
+
35
+ "100 USD".to_money.should == Money.new(100_00, "USD")
36
+ "-100 USD".to_money.should == Money.new(-100_00, "USD")
37
+ "100 EUR".to_money.should == Money.new(100_00, "EUR")
38
+ "100.37 EUR".to_money.should == Money.new(100_37, "EUR")
39
+ "100,37 EUR".to_money.should == Money.new(100_37, "EUR")
40
+ "100,000.00 USD".to_money.should == Money.new(100_000_00, "USD")
41
+ "100.000,00 EUR".to_money.should == Money.new(100_000_00, "EUR")
42
+ "1,000 USD".to_money.should == Money.new(1_000_00, "USD")
43
+ "-1,000 USD".to_money.should == Money.new(-1_000_00, "USD")
44
+ "1,000.5500 USD".to_money.should == Money.new(1_000_55, "USD")
45
+ "-1,000.6500 USD".to_money.should == Money.new(-1_000_65, "USD")
46
+ "1.550 USD".to_money.should == Money.new(1_55, "USD")
47
+
48
+ "USD 100".to_money.should == Money.new(100_00, "USD")
49
+ "EUR 100".to_money.should == Money.new(100_00, "EUR")
50
+ "EUR 100.37".to_money.should == Money.new(100_37, "EUR")
51
+ "CAD -100.37".to_money.should == Money.new(-100_37, "CAD")
52
+ "EUR 100,37".to_money.should == Money.new(100_37, "EUR")
53
+ "EUR -100,37".to_money.should == Money.new(-100_37, "EUR")
54
+ "USD 100,000.00".to_money.should == Money.new(100_000_00, "USD")
55
+ "EUR 100.000,00".to_money.should == Money.new(100_000_00, "EUR")
56
+ "USD 1,000".to_money.should == Money.new(1_000_00, "USD")
57
+ "USD -1,000".to_money.should == Money.new(-1_000_00, "USD")
58
+ "USD 1,000.9000".to_money.should == Money.new(1_000_90, "USD")
59
+ "USD -1,000.090".to_money.should == Money.new(-1_000_09, "USD")
60
+ "USD 1.5500".to_money.should == Money.new(1_55, "USD")
61
+
62
+ "$100 USD".to_money.should == Money.new(100_00, "USD")
63
+ "$1,194.59 USD".to_money.should == Money.new(1_194_59, "USD")
64
+ "$-1,955 USD".to_money.should == Money.new(-1_955_00, "USD")
65
+ "$1,194.5900 USD".to_money.should == Money.new(1_194_59, "USD")
66
+ "$-1,955.000 USD".to_money.should == Money.new(-1_955_00, "USD")
67
+ "$1.99000 USD".to_money.should == Money.new(1_99, "USD")
68
+ end
69
+
70
+ specify "String#to_money ignores unrecognized data" do
71
+ "hello 2000 world".to_money.should == Money.new(2000_00)
72
+ end
73
+ end
@@ -0,0 +1,45 @@
1
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
2
+ require 'money/variable_exchange_bank'
3
+
4
+ describe Money::VariableExchangeBank do
5
+ before :each do
6
+ @bank = Money::VariableExchangeBank.new
7
+ end
8
+
9
+ it "returns the previously specified conversion rate" do
10
+ @bank.add_rate("USD", "EUR", 0.788332676)
11
+ @bank.add_rate("EUR", "YEN", 122.631477)
12
+ @bank.get_rate("USD", "EUR").should == 0.788332676
13
+ @bank.get_rate("EUR", "YEN").should == 122.631477
14
+ end
15
+
16
+ it "treats currency names case-insensitively" do
17
+ @bank.add_rate("usd", "eur", 1)
18
+ @bank.get_rate("USD", "EUR").should == 1
19
+ @bank.same_currency?("USD", "usd").should be_true
20
+ @bank.same_currency?("EUR", "usd").should be_false
21
+ end
22
+
23
+ it "returns nil if the conversion rate is unknown" do
24
+ @bank.get_rate("American Pesos", "EUR").should be_nil
25
+ end
26
+
27
+ it "exchanges money from one currency to another according to the specified conversion rates" do
28
+ @bank.add_rate("USD", "EUR", 0.5)
29
+ @bank.add_rate("EUR", "YEN", 10)
30
+ @bank.exchange(10_00, "USD", "EUR").should == 5_00
31
+ @bank.exchange(500_00, "EUR", "YEN").should == 5000_00
32
+ end
33
+
34
+ it "rounds the exchanged result down" do
35
+ @bank.add_rate("USD", "EUR", 0.788332676)
36
+ @bank.add_rate("EUR", "YEN", 122.631477)
37
+ @bank.exchange(10_00, "USD", "EUR").should == 788
38
+ @bank.exchange(500_00, "EUR", "YEN").should == 6131573
39
+ end
40
+
41
+ it "raises Money::UnknownRate upon conversion if the conversion rate is unknown" do
42
+ block = lambda { @bank.exchange(10, "USD", "EUR") }
43
+ block.should raise_error(Money::UnknownRate)
44
+ end
45
+ end
@@ -0,0 +1,272 @@
1
+ # encoding: utf-8
2
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
3
+ require 'money/money'
4
+ require 'money/symbols'
5
+
6
+ describe Money do
7
+ it "is associated to the singleton instance of VariableExchangeBank by default" do
8
+ Money.new(0).bank.object_id.should == Money::VariableExchangeBank.instance.object_id
9
+ end
10
+
11
+ specify "#cents returns the amount of cents passed to the constructor" do
12
+ Money.new(200_00, "USD").cents.should == 200_00
13
+ end
14
+
15
+ it "rounds the given cents to an integer" do
16
+ Money.new(1.00, "USD").cents.should == 1
17
+ Money.new(1.01, "USD").cents.should == 1
18
+ Money.new(1.50, "USD").cents.should == 2
19
+ end
20
+
21
+ specify "#currency returns the currency passed to the constructor" do
22
+ Money.new(200_00, "USD").currency.should == "USD"
23
+ end
24
+
25
+ specify "#zero? returns whether the amount is 0" do
26
+ Money.new(0, "USD").should be_zero
27
+ Money.new(0, "EUR").should be_zero
28
+ Money.new(1, "USD").should_not be_zero
29
+ Money.new(10, "YEN").should_not be_zero
30
+ Money.new(-1, "EUR").should_not be_zero
31
+ end
32
+
33
+ specify "#exchange_to exchanges the amount via its exchange bank" do
34
+ money = Money.new(100_00, "USD")
35
+ money.bank.should_receive(:exchange).with(100_00, "USD", "EUR").and_return(200_00)
36
+ money.exchange_to("EUR")
37
+ end
38
+
39
+ specify "#exchange_to exchanges the amount properly" do
40
+ money = Money.new(100_00, "USD")
41
+ money.bank.should_receive(:exchange).with(100_00, "USD", "EUR").and_return(200_00)
42
+ money.exchange_to("EUR").should == Money.new(200_00, "EUR")
43
+ end
44
+
45
+ specify "#== returns true if and only if their amount and currency are equal" do
46
+ Money.new(1_00, "USD").should == Money.new(1_00, "USD")
47
+ Money.new(1_00, "USD").should_not == Money.new(1_00, "EUR")
48
+ Money.new(1_00, "USD").should_not == Money.new(2_00, "USD")
49
+ Money.new(1_00, "USD").should_not == Money.new(99_00, "EUR")
50
+ end
51
+
52
+ specify "#== returns true if compared with a string money value" do
53
+ Money.new(1_00, "USD").should == "1.00"
54
+ Money.new(1_00, "USD").should_not == "2.00"
55
+ Money.new(1_00, "GBP").should_not == "1.00"
56
+ end
57
+
58
+ specify "#== returns true if compared with a numeric money value" do
59
+ Money.new(1_00, "USD").should == 1
60
+ Money.new(1_57, "USD").should == 1.57
61
+ Money.new(1_00, "USD").should_not == 2
62
+ Money.new(1_00, "GBP").should_not == 1
63
+ end
64
+
65
+ specify "#* multiplies the money's amount by the multiplier while retaining the currency" do
66
+ (Money.new(1_00, "USD") * 10).should == Money.new(10_00, "USD")
67
+ end
68
+
69
+ specify "#* divides the money's amount by the divisor while retaining the currency" do
70
+ (Money.new(10_00, "USD") / 10).should == Money.new(1_00, "USD")
71
+ end
72
+
73
+ specify "Money.empty creates a new Money object of 0 cents" do
74
+ Money.empty.should == Money.new(0)
75
+ end
76
+
77
+ specify "Money.ca_dollar creates a new Money object of the given value in CAD" do
78
+ Money.ca_dollar(50).should == Money.new(50, "CAD")
79
+ end
80
+
81
+ specify "Money.ca_dollar creates a new Money object of the given value in USD" do
82
+ Money.us_dollar(50).should == Money.new(50, "USD")
83
+ end
84
+
85
+ specify "Money.ca_dollar creates a new Money object of the given value in EUR" do
86
+ Money.euro(50).should == Money.new(50, "EUR")
87
+ end
88
+
89
+ specify "Money.add_rate works" do
90
+ Money.add_rate("EUR", "USD", 10)
91
+ Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
92
+ end
93
+
94
+ describe "#format" do
95
+ it "returns the monetary value as a string" do
96
+ Money.ca_dollar(100).format.should == "$1.00"
97
+ end
98
+
99
+ describe "if the monetary value is 0" do
100
+ before :each do
101
+ @money = Money.us_dollar(0)
102
+ end
103
+
104
+ it "returns 'free' when :display_free is true" do
105
+ @money.format(:display_free => true).should == 'free'
106
+ end
107
+
108
+ it "returns '$0.00' when :display_free is false or not given" do
109
+ @money.format.should == '$0.00'
110
+ @money.format(:display_free => false).should == '$0.00'
111
+ @money.format(:display_free => nil).should == '$0.00'
112
+ end
113
+
114
+ it "returns the value specified by :display_free if it's a string-like object" do
115
+ @money.format(:display_free => 'gratis').should == 'gratis'
116
+ end
117
+ end
118
+
119
+ specify "#format(:with_currency => true) works as documented" do
120
+ Money.ca_dollar(100).format(:with_currency => true).should == "$1.00 CAD"
121
+ Money.us_dollar(85).format(:with_currency => true).should == "$0.85 USD"
122
+ Money.us_dollar(85).format(:with_currency).should == "$0.85 USD"
123
+ end
124
+
125
+ specify "#format(:with_currency) works as documented" do
126
+ Money.ca_dollar(100).format(:with_currency).should == "$1.00 CAD"
127
+ Money.us_dollar(85).format(:with_currency).should == "$0.85 USD"
128
+ end
129
+
130
+ specify "#format(:no_cents => true) works as documented" do
131
+ Money.ca_dollar(100).format(:no_cents => true).should == "$1"
132
+ Money.ca_dollar(599).format(:no_cents => true).should == "$5"
133
+ Money.ca_dollar(570).format(:no_cents => true, :with_currency => true).should == "$5 CAD"
134
+ Money.ca_dollar(39000).format(:no_cents => true).should == "$390"
135
+ end
136
+
137
+ specify "#format(:no_cents) works as documented" do
138
+ Money.ca_dollar(100).format(:no_cents).should == "$1"
139
+ Money.ca_dollar(599).format(:no_cents).should == "$5"
140
+ Money.ca_dollar(570).format(:no_cents, :with_currency).should == "$5 CAD"
141
+ Money.ca_dollar(39000).format(:no_cents).should == "$390"
142
+ end
143
+
144
+ specify "#format(:symbol => a symbol string) uses the given value as the money symbol" do
145
+ Money.new(100, "USD").format(:symbol => "£").should == "£1.00"
146
+ end
147
+
148
+ specify "#format(:symbol => true) returns symbol based on the given currency code" do
149
+ one = Proc.new {|currency| Money.new(100, currency).format(:symbol => true) }
150
+
151
+ # Pounds
152
+ one["GBP"].should == "£1.00"
153
+
154
+ # Dollars
155
+ one["USD"].should == "$1.00"
156
+ one["CAD"].should == "$1.00"
157
+ one["AUD"].should == "$1.00"
158
+ one["NZD"].should == "$1.00"
159
+ one["ZWD"].should == "Z$1.00"
160
+
161
+ # Yen
162
+ one["JPY"].should == "¥1.00"
163
+ one["CNY"].should == "¥1.00"
164
+
165
+ # Euro
166
+ one["EUR"].should == "€1.00"
167
+
168
+ # Rupees
169
+ one["INR"].should == "₨1.00"
170
+ one["NPR"].should == "₨1.00"
171
+ one["SCR"].should == "₨1.00"
172
+ one["LKR"].should == "₨1.00"
173
+
174
+ # Other
175
+ one["SEK"].should == "kr1.00"
176
+ one["GHC"].should == "¢1.00"
177
+ end
178
+
179
+ specify "#format(:symbol => true) returns $ when currency code is not recognized" do
180
+ Money.new(100, "XYZ").format(:symbol => true).should == "$1.00"
181
+ end
182
+
183
+ specify "#format(:symbol => some non-Boolean value that evaluates to true) returs symbol based on the given currency code" do
184
+ Money.new(100, "GBP").format(:symbol => true).should == "£1.00"
185
+ Money.new(100, "EUR").format(:symbol => true).should == "€1.00"
186
+ Money.new(100, "SEK").format(:symbol => true).should == "kr1.00"
187
+ end
188
+
189
+ specify "#format with :symbol == "", nil or false returns the amount without a symbol" do
190
+ money = Money.new(100, "GBP")
191
+ money.format(:symbol => "").should == "1.00"
192
+ money.format(:symbol => nil).should == "1.00"
193
+ money.format(:symbol => false).should == "1.00"
194
+ end
195
+
196
+ specify "#format(:html => true) works as documented" do
197
+ string = Money.ca_dollar(570).format(:html => true, :with_currency => true)
198
+ string.should == "$5.70 <span class=\"currency\">CAD</span>"
199
+ end
200
+
201
+ it "should insert commas into the result if the amount is sufficiently large" do
202
+ Money.us_dollar(1_000_000_000_12).format.should == "$1,000,000,000.12"
203
+ Money.us_dollar(1_000_000_000_12).format(:no_cents => true).should == "$1,000,000,000"
204
+ end
205
+ end
206
+ end
207
+
208
+ describe "Actions involving two Money objects" do
209
+ describe "if the other Money object has the same currency" do
210
+ specify "#<=> compares the two objects' amounts" do
211
+ (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
212
+ (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
213
+ (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
214
+ end
215
+
216
+ specify "#<=> compares the two objects when other is a string' amounts" do
217
+ (Money.new(1_00, "USD") <=> "1.00").should == 0
218
+ (Money.new(1_00, "USD") <=> ".99").should > 0
219
+ (Money.new(1_00, "USD") <=> "2.00").should < 0
220
+ end
221
+
222
+ specify "#<=> compares the two objects when other is a numeric' amounts" do
223
+ (Money.new(1_00, "USD") <=> 1).should == 0
224
+ (Money.new(1_00, "USD") <=> 0.99).should > 0
225
+ (Money.new(1_00, "USD") <=> 2.00).should < 0
226
+ end
227
+
228
+ specify "#+ adds the other object's amount to the current object's amount while retaining the currency" do
229
+ (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
230
+ end
231
+
232
+ specify "#+ adds the other object's amount to the current object's amount while retaining the currency when passed a string" do
233
+ (Money.new(10_00, "USD") + ".90").should == Money.new(10_90, "USD")
234
+ end
235
+
236
+ specify "#+ adds the other object's amount to the current object's amount while retaining the currency when passed a string" do
237
+ (Money.new(10_00, "USD") + 0.90).should == Money.new(10_90, "USD")
238
+ end
239
+
240
+ specify "#- substracts the other object's amount from the current object's amount while retaining the currency" do
241
+ (Money.new(10_00, "USD") - 0.90).should == Money.new(9_10, "USD")
242
+ end
243
+ end
244
+
245
+ describe "if the other Money object has a different currency" do
246
+ specify "#<=> compares the two objects' amount after converting the other object's amount to its own currency" do
247
+ target = Money.new(200_00, "EUR")
248
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(300_00, "USD"))
249
+ (Money.new(100_00, "USD") <=> target).should < 0
250
+
251
+ target = Money.new(200_00, "EUR")
252
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(100_00, "USD"))
253
+ (Money.new(100_00, "USD") <=> target).should == 0
254
+
255
+ target = Money.new(200_00, "EUR")
256
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(99_00, "USD"))
257
+ (Money.new(100_00, "USD") <=> target).should > 0
258
+ end
259
+
260
+ specify "#+ adds the other object's amount, converted to this object's currency, to this object's amount while retaining its currency" do
261
+ other = Money.new(90, "EUR")
262
+ other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
263
+ (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
264
+ end
265
+
266
+ specify "#- substracts the other object's amount, converted to this object's currency, from this object's amount while retaining its currency" do
267
+ other = Money.new(90, "EUR")
268
+ other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
269
+ (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
270
+ end
271
+ end
272
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mmorga-money
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Tobias Luetke
8
+ - Hongli Lai
9
+ - Jeremy McNevin
10
+ - Mark Morga
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+
15
+ date: 2009-05-16 00:00:00 -07:00
16
+ default_executable:
17
+ dependencies: []
18
+
19
+ description: Money and currency exchange support library.
20
+ email:
21
+ - hongli@phusion.nl
22
+ - mmorga@rackspace.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - README.rdoc
31
+ - MIT-LICENSE
32
+ - money.gemspec
33
+ - Rakefile
34
+ - lib/money.rb
35
+ - lib/money/core_extensions.rb
36
+ - lib/money/errors.rb
37
+ - lib/money/money.rb
38
+ - lib/money/symbols.rb
39
+ - lib/money/variable_exchange_bank.rb
40
+ - test/core_extensions_spec.rb
41
+ - test/exchange_bank_spec.rb
42
+ - test/money_spec.rb
43
+ has_rdoc: true
44
+ homepage: http://money.rubyforge.org/
45
+ licenses:
46
+ post_install_message:
47
+ rdoc_options: []
48
+
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project: money
66
+ rubygems_version: 1.3.5
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: Money and currency exchange support library
70
+ test_files: []
71
+