nofxx-money 2.2.2 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -14,11 +14,12 @@ rails/init.rb
14
14
  script/console
15
15
  script/destroy
16
16
  script/generate
17
- spec/db/acts_as_money.sqlite3
18
17
  spec/db/database.yml
19
18
  spec/db/schema.rb
20
19
  spec/money/acts_as_money_spec.rb
21
20
  spec/money/core_extensions_spec.rb
22
21
  spec/money/exchange_bank_spec.rb
23
22
  spec/money/money_spec.rb
23
+ spec/spec.opts
24
24
  spec/spec_helper.rb
25
+ tmp/acts_as_money.sqlite3
data/README.rdoc CHANGED
@@ -17,6 +17,7 @@ Resources:
17
17
  - RDoc API: http://money.rubyforge.org
18
18
  - Git repository: http://github.com/FooBarWidget/money/tree/master
19
19
 
20
+
20
21
  == Download
21
22
 
22
23
  Install stable releases with the following command:
@@ -28,6 +29,7 @@ The development version (hosted on Github) can be installed with:
28
29
  gem sources -a http://gems.github.com
29
30
  gem install nofxx-money
30
31
 
32
+
31
33
  == Usage
32
34
 
33
35
  === Synopsis
@@ -38,6 +40,7 @@ The development version (hosted on Github) can be installed with:
38
40
  money = Money.new(1000, "USD")
39
41
  money.cents # => 1000
40
42
  money.currency # => "USD"
43
+ money.format # => "$10.00"
41
44
 
42
45
  Money.new(1000, "USD") == Money.new(1000, "USD") # => true
43
46
  Money.new(1000, "USD") == Money.new(100, "USD") # => false
@@ -56,6 +59,11 @@ an example of how it works:
56
59
  Money.us_dollar(100).exchange_to("CAD") # => Money.new(124, "CAD")
57
60
  Money.ca_dollar(100).exchange_to("USD") # => Money.new(80, "USD")
58
61
 
62
+ or
63
+
64
+ Money.us_dollar(100).to_cad # => Money.new(124, "CAD")
65
+ Money.ca_dollar(100).to_usd # => Money.new(80, "USD")
66
+
59
67
  Comparison and arithmetic operations work as expected:
60
68
 
61
69
  Money.new(1000, "USD") <=> Money.new(900, "USD") # => 1; 9.00 USD is smaller
@@ -86,15 +94,7 @@ app/models/product.rb
86
94
  belongs_to :product
87
95
  has_money :price
88
96
 
89
- private
90
- validate :cents_not_zero
91
-
92
- def cents_not_zero
93
- errors.add("price_cents", "cannot be zero or less") unless cents > 0
94
- end
95
-
96
- validates_presence_of :sku, :currency
97
- validates_uniqueness_of :sku
97
+ validates_numericality_of :price_cents, :greater_than => 0
98
98
  end
99
99
 
100
100
  migration:
@@ -116,6 +116,7 @@ If you use Rails, then environment.rb is a very good place to put this.
116
116
 
117
117
  == TODO
118
118
 
119
- * Better validation
119
+ * Better validation (fix composed_of allow_nil)
120
120
  * Interest (almost there..)
121
+ * Remote rate fetching
121
122
 
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/lib/money'
4
4
  # Generate all the Rake tasks
5
5
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
6
  $hoe = Hoe.new('money', Money::VERSION) do |p|
7
- p.developer('FIXME full name', 'FIXME email')
7
+ p.developer('Money Team', 'see@readme')
8
8
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
9
  p.rubyforge_name = p.name
10
10
  p.summary = "This library aids one in handling money and different currencies."
@@ -16,7 +16,7 @@ $hoe = Hoe.new('money', Money::VERSION) do |p|
16
16
  ['newgem', ">= #{::Newgem::VERSION}"]
17
17
  ]
18
18
 
19
- p.clean_globs |= %w[**/.DS_Store tmp *.log]
19
+ p.clean_globs |= %w[**/.DS_Store *.log]
20
20
  path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
21
21
  p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
22
22
  p.rsync_args = '-av --delete --ignore-errors'
data/lib/money.rb CHANGED
@@ -25,5 +25,5 @@ require 'money/money'
25
25
  require 'money/core_extensions'
26
26
 
27
27
  class Money
28
- VERSION = "2.2.2"
28
+ VERSION = "2.3.1"
29
29
  end
@@ -12,25 +12,26 @@ module ActsAsMoney #:nodoc:
12
12
  # end
13
13
  #
14
14
  # @product.value.class #=> "Money"
15
- # @product.value_in_cents #=> "1000"
15
+ # @product.value_cents #=> "1000"
16
16
  # @product.tax_currency #=> "USD"
17
17
  #
18
18
  # Opts:
19
19
  # :cents => "pennys" #=> @product.pennys
20
20
  # :currency => "currency" #=> @product.currency
21
21
  # :allow_nil => true
22
- # :with_currency => true
22
+ # :with_currency => false
23
+ # :with_cents => true #=> 1000.to_money #=> #<Money @cents=1000>
23
24
  #
24
25
  def has_money(*attributes)
25
- config = {:with_currency => true, :converter => lambda { |m| m.to_money },
26
- :allow_nil => false }.update(attributes.extract_options!)
26
+ config = {:with_currency => true, :with_cents => false,
27
+ :allow_nil => true }.update(attributes.extract_options!)
27
28
 
28
- attributes.each do |attr|
29
- mapping = [[config[:cents] || "#{attr}_cents", 'cents']]
30
- mapping << [config[:currency] || "#{attr}_currency", 'currency'] if config[:with_currency]
29
+ for attribute in attributes do
30
+ mapping = [[config[:cents] || "#{attribute}_cents", 'cents']]
31
+ mapping << [config[:currency] || "#{attribute}_currency", 'currency'] if config[:with_currency]
31
32
 
32
- composed_of attr, :class_name => 'Money',:allow_nil => config[:allow_nil],
33
- :mapping => mapping, :converter => config[:converter]
33
+ composed_of attribute, :class_name => 'Money', :allow_nil => config[:allow_nil],
34
+ :mapping => mapping, :converter => lambda { |m| (m||0).to_money(config[:with_cents]) }
34
35
  end
35
36
 
36
37
  end
@@ -1,11 +1,20 @@
1
1
  class Numeric
2
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.
3
+ # multiplies the numeric value by 100 and treats that as cents if receive false.
4
4
  #
5
- # 100.to_money => #<Money @cents=10000>
5
+ # 100.to_money => #<Money @cents=100>
6
6
  # 100.37.to_money => #<Money @cents=10037>
7
- def to_money
8
- Money.new(self * 100)
7
+ # 100.to_money(false) => #<Money @cents=10000>
8
+ def to_money(cents = false)
9
+ if cents
10
+ if self.is_a? Integer
11
+ Money.new(self)
12
+ else
13
+ Money.new(self.to_s.gsub(/\./,'').to_i)
14
+ end
15
+ else
16
+ Money.new(self * 100)
17
+ end
9
18
  end
10
19
  end
11
20
 
@@ -13,27 +22,118 @@ class String
13
22
  # Parses the current string and converts it to a Money object.
14
23
  # Excess characters will be discarded.
15
24
  #
16
- # '100'.to_money # => #<Money @cents=10000>
25
+ # '100'.to_money # => #<Money @cents=100>
17
26
  # '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
- def to_money
27
+ # '100 USD'.to_money # => #<Money @cents=100, @currency="USD">
28
+ # 'USD 100'.to_money # => #<Money @cents=100, @currency="USD">
29
+ # '$100 USD'.to_money # => #<Money @cents=100, @currency="USD">
30
+ # '$100 USD'.to_money(false) # => #<Money @cents=10000, @currency="USD">
31
+ def to_money(with_cents = false)
22
32
  # Get the currency.
23
33
  matches = scan /([A-Z]{2,3})/
24
34
  currency = matches[0] ? matches[0][0] : Money.default_currency
35
+ cents = calculate_cents(self, with_cents)
36
+ Money.new(cents, currency)
37
+ end
38
+
39
+ private
40
+
41
+ def calculate_cents(number, with_cents = true)
42
+ # remove anything that's not a number, potential delimiter, or minus sign
43
+ num = number.gsub(/[^\d|\.|,|\'|\s|\-]/, '').strip
44
+
45
+ # set a boolean flag for if the number is negative or not
46
+ negative = num.split(//).first == "-"
47
+
48
+ # if negative, remove the minus sign from the number
49
+ num = num.gsub(/^-/, '') if negative
50
+
51
+ # gather all separators within the result number
52
+ used_separators = num.scan /[^\d]/
53
+
54
+ # determine the number of unique separators within the number
55
+ #
56
+ # e.g.
57
+ # $1,234,567.89 would return 2 (, and .)
58
+ # $125,00 would return 1
59
+ # $199 would return 0
60
+ # $1 234,567.89 would raise an error (separators are space, comma, and period)
61
+ case used_separators.uniq.length
62
+ # no separator or delimiter; major (dollars) is the number, and minor (cents) is 0
63
+ when 0 then major, minor = num, 0
64
+
65
+ # two separators, so we know the last item in this array is the
66
+ # major/minor delimiter and the rest are separators
67
+ when 2
68
+ separator, delimiter = used_separators.uniq
69
+ # remove all separators, split on the delimiter
70
+ major, minor = num.gsub(separator, '').split(delimiter)
71
+ min = 0 unless min
72
+ when 1
73
+ # we can't determine if the comma or period is supposed to be a separator or a delimiter
74
+ # e.g.
75
+ # 1,00 - comma is a delimiter
76
+ # 1.000 - period is a delimiter
77
+ # 1,000 - comma is a separator
78
+ # 1,000,000 - comma is a separator
79
+ # 10000,00 - comma is a delimiter
80
+ # 1000,000 - comma is a delimiter
25
81
 
26
- # Get the cents amount
27
- sans_spaces = gsub(/\s+/, '')
28
- matches = sans_spaces.scan /(\-?\d+(?:[\.,]\d+)?)/
29
- cents = if matches[0]
30
- value = matches[0][0].gsub(/,/, '.')
31
- value.to_f * 100
82
+ # assign first separator for reusability
83
+ separator = used_separators.first
84
+
85
+ # separator is used as a separator when there are multiple instances, always
86
+ if num.scan(separator).length > 1 # multiple matches; treat as separator
87
+ major, minor = num.gsub(separator, ''), 0
88
+ else
89
+ # ex: 1,000 - 1.0000 - 10001.000
90
+ # split number into possible major (dollars) and minor (cents) values
91
+ possible_major, possible_minor = num.split(separator)
92
+
93
+ # if the minor (cents) length isn't 3, assign major/minor from the possibles
94
+ # e.g.
95
+ # 1,00 => 1.00
96
+ # 1.0000 => 1.00
97
+ # 1.2 => 1.20
98
+ if possible_minor.length != 3 # delimiter
99
+ major, minor = possible_major, possible_minor
100
+ else
101
+ # minor length is three
102
+ # let's try to figure out intent of the delimiter
103
+
104
+ # the major length is greater than three, which means
105
+ # the comma or period is used as a delimiter
106
+ # e.g.
107
+ # 1000,000
108
+ # 100000,000
109
+ if possible_major.length > 3
110
+ major, minor = possible_major, possible_minor
111
+ else
112
+ # number is in format ###{sep}### or ##{sep}### or #{sep}###
113
+ # handle as , is sep, . is delimiter
114
+ if separator == '.'
115
+ major, minor = possible_major, possible_minor
32
116
  else
33
- 0
117
+ major, minor = "#{possible_major}#{possible_minor}", 0
34
118
  end
119
+ end
120
+ end
121
+ end
122
+ else
123
+ raise ArgumentError, "Invalid currency amount"
124
+ end
35
125
 
36
- Money.new(cents, currency)
126
+ # build the string based on major/minor since separator/delimiters have been removed
127
+ # transform to a float, multiply by 100 to convert to cents
128
+ if with_cents and minor == 0
129
+ cents = "#{major}.#{minor}".to_f
130
+ else
131
+ cents = "#{major}.#{minor}".to_f * 100
132
+ end
133
+
134
+
135
+ # if negative, multiply by -1; otherwise, return positive cents
136
+ negative ? cents * -1 : cents
37
137
  end
38
- end
39
138
 
139
+ end
data/lib/money/money.rb CHANGED
@@ -28,6 +28,16 @@ class Money
28
28
  attr_accessor :default_currency
29
29
  end
30
30
 
31
+ CURRENCIES = {
32
+ "USD" => { :delimiter => ",", :separator => ".", :symbol => "$" },
33
+ "CAD" => { :delimiter => ",", :separator => ".", :symbol => "$" },
34
+ "HKD" => { :delimiter => ",", :separator => ".", :symbol => "$" },
35
+ "SGD" => { :delimiter => ",", :separator => ".", :symbol => "$" },
36
+ "BRL" => { :delimiter => ".", :separator => ",", :symbol => "R$" },
37
+ "EUR" => { :delimiter => ",", :separator => ".", :symbol => '€', :html => '&euro;' },
38
+ "GBP" => { :delimiter => ",", :separator => ".", :symbol => '£', :html => '&pound;' },
39
+ "JPY" => { :delimiter => ".", :separator => ".", :symbol => '¥', :html => '&yen;' },
40
+ }
31
41
  self.default_bank = VariableExchangeBank.instance
32
42
  self.default_currency = "USD"
33
43
 
@@ -52,7 +62,7 @@ class Money
52
62
  Money.new(cents, "EUR")
53
63
  end
54
64
 
55
- # Creates a new Money object of the given value, using the Euro currency.
65
+ # Creates a new Money object of the given value, using the Brazilian Real currency.
56
66
  def self.real(cents)
57
67
  Money.new(cents, "BRL")
58
68
  end
@@ -67,7 +77,7 @@ class Money
67
77
  # Alternativly you can use the convinience methods like
68
78
  # Money.ca_dollar and Money.us_dollar
69
79
  def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
70
- @cents = cents.round # ? cents.round : 0
80
+ @cents = cents.round
71
81
  @currency = currency
72
82
  @bank = bank
73
83
  end
@@ -129,7 +139,6 @@ class Money
129
139
  # Calculates compound interest
130
140
  # Returns a money object with the sum of self + it
131
141
  def compound_interest(rate,count=1)
132
-
133
142
  Money.new(cents * ((1 + rate / 100.0 / 12) ** count - 1))
134
143
  end
135
144
 
@@ -138,11 +147,11 @@ class Money
138
147
  Money.new(rate/100/12*cents*count)
139
148
  end
140
149
 
141
- def with_simple_interest(rate,count=1)
142
- end
143
-
144
- # Split money in installments
145
- # So US$ 10.00 == [ 3.34, 3.33, 3.33 ]
150
+ # Split money in number of installments
151
+ #
152
+ # Money.new(10_00).split_in_installments(3)
153
+ # => [ 3.34, 3.33, 3.33 ] (All Money instances)
154
+ #
146
155
  def split_in_installments(fixnum,extra=nil,*opts)
147
156
  wallet = Wallet.new(fixnum, Money.new(cents/fixnum,currency))
148
157
  to_add = cents % fixnum
@@ -151,13 +160,17 @@ class Money
151
160
  end
152
161
 
153
162
  # Split money in installments based on payment value
163
+ #
164
+ # Money.new(1000_00).split_in_installments(Money.new(300_00))
165
+ # => [ 334_00, 333_00, 333_00 ] (All Money instances)
166
+ #
154
167
  def in_installments_of(other_money,first=false)
155
168
  split_in_installments(cents/other_money.cents,first)
156
169
  end
157
170
 
158
171
  # Just a helper if you got tax inputs in percentage.
159
- # Ie. with_tax(20) => cents * 1.20
160
- def with_tax(tax)
172
+ # Ie. add_tax(20) => cents * 1.20
173
+ def add_tax(tax)
161
174
  Money.new(cents + cents / 100 * tax)
162
175
  end
163
176
 
@@ -186,15 +199,35 @@ class Money
186
199
  # html:
187
200
  #
188
201
  # Money.ca_dollar(570).format(:html => true, :with_currency => true) => "$5.70 <span class=\"currency\">CAD</span>"
189
- def format(rules = {})
190
- return "free" if cents == 0
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
191
213
 
192
- rules = rules.flatten
214
+ if rules.has_key?(:symbol)
215
+ if rules[:symbol]
216
+ symbol = rules[:symbol]
217
+ else
218
+ symbol = ""
219
+ end
220
+ else
221
+ symbol = CURRENCIES[currency][:symbol]
222
+ end
193
223
 
194
- if rules.include?(:no_cents)
195
- formatted = sprintf("$%d", cents.to_f / 100 )
224
+ if rules[:no_cents]
225
+ formatted = sprintf("#{symbol}%d", cents.to_f / 100)
226
+ formatted.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{CURRENCIES[currency][:delimiter]}")
196
227
  else
197
- formatted = sprintf("$%.2f", cents.to_f / 100 )
228
+ formatted = sprintf("#{symbol}%.2f", cents.to_f / 100).split('.')
229
+ formatted[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{CURRENCIES[currency][:delimiter]}")
230
+ formatted = formatted.join(CURRENCIES[currency][:separator])
198
231
  end
199
232
 
200
233
  if rules[:with_currency]
@@ -206,6 +239,20 @@ class Money
206
239
  formatted
207
240
  end
208
241
 
242
+ def normalize_formatting_rules(rules)
243
+ if rules.size == 1
244
+ rules = rules.pop
245
+ rules = { rules => true } if rules.is_a?(Symbol)
246
+ else
247
+ rules = rules.inject({}) do |h,s|
248
+ h[s] = true
249
+ h
250
+ end
251
+ end
252
+ rules
253
+ end
254
+
255
+
209
256
  # Money.ca_dollar(100).to_s => "1.00"
210
257
  def to_s
211
258
  sprintf("%.2f", cents / 100.0)
@@ -221,34 +268,18 @@ class Money
221
268
  Money.new(@bank.exchange(self.cents, currency, other_currency), other_currency)
222
269
  end
223
270
 
224
- # Recieve a money object with the same amount as the current Money object
225
- # in american dollar
226
- def as_us_dollar
227
- exchange_to("USD")
228
- end
229
-
230
- # Recieve a money object with the same amount as the current Money object
231
- # in canadian dollar
232
- def as_ca_dollar
233
- exchange_to("CAD")
234
- end
235
-
236
- # Recieve a money object with the same amount as the current Money object
237
- # in euro
238
- def as_euro
239
- exchange_to("EUR")
240
- end
241
-
242
- # Recieve a money object with the same amount as the current Money object
243
- # in real
244
- def as_real
245
- exchange_to("BRL")
246
- end
247
-
248
271
  # Conversation to self
249
272
  def to_money
250
273
  self
251
274
  end
275
+
276
+ def method_missing(m,*x)
277
+ if m.to_s =~ /^as/
278
+ exchange_to(m.to_s.split("_").last.upcase)
279
+ else
280
+ super
281
+ end
282
+ end
252
283
  end
253
284
 
254
285
  #
data/money.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{money}
5
- s.version = "2.2.2"
5
+ s.version = "2.3.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = ["FIXME full name"]
9
- s.date = %q{2009-02-12}
8
+ s.authors = ["Money Team"]
9
+ s.date = %q{2009-03-15}
10
10
  s.description = %q{This library aids one in handling money and different currencies.}
11
- s.email = ["FIXME email"]
11
+ s.email = ["see@readme"]
12
12
  s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
13
- s.files = ["History.txt", "MIT-LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "lib/money.rb", "lib/money/acts_as_money.rb", "lib/money/core_extensions.rb", "lib/money/errors.rb", "lib/money/money.rb", "lib/money/variable_exchange_bank.rb", "money.gemspec", "rails/init.rb", "script/console", "script/destroy", "script/generate", "spec/db/acts_as_money.sqlite3", "spec/db/database.yml", "spec/db/schema.rb", "spec/money/acts_as_money_spec.rb", "spec/money/core_extensions_spec.rb", "spec/money/exchange_bank_spec.rb", "spec/money/money_spec.rb", "spec/spec_helper.rb"]
13
+ s.files = ["History.txt", "MIT-LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "lib/money.rb", "lib/money/acts_as_money.rb", "lib/money/core_extensions.rb", "lib/money/errors.rb", "lib/money/money.rb", "lib/money/variable_exchange_bank.rb", "money.gemspec", "rails/init.rb", "script/console", "script/destroy", "script/generate", "spec/db/database.yml", "spec/db/schema.rb", "spec/money/acts_as_money_spec.rb", "spec/money/core_extensions_spec.rb", "spec/money/exchange_bank_spec.rb", "spec/money/money_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tmp/acts_as_money.sqlite3"]
14
14
  s.has_rdoc = true
15
15
  s.homepage = %q{http://github.com/nofxx/money}
16
16
  s.rdoc_options = ["--main", "README.rdoc"]
data/spec/db/database.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  adapter: sqlite3
2
- database: spec/db/acts_as_money.sqlite3
2
+ database: tmp/acts_as_money.sqlite3
3
3
  pool: 5
4
4
  timeout: 5000
data/spec/db/schema.rb CHANGED
@@ -1,14 +1,12 @@
1
- require File.dirname(__FILE__) + '/../spec_helper.rb'
2
-
3
1
  ActiveRecord::Schema.define() do
4
2
 
5
3
  create_table :accounts, :force => true do |t|
6
- t.integer :value_in_cents, :total_in_cents
4
+ t.integer :value_cents, :total_cents
7
5
  t.string :value_currency, :total_currency
8
6
  end
9
7
 
10
8
  create_table :products, :force => true do |t|
11
- t.integer :value_in_cents, :tax_pennys
9
+ t.integer :value_cents, :tax_pennys
12
10
  t.string :value_currency
13
11
  end
14
12
 
@@ -2,43 +2,63 @@ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
2
  require File.dirname(__FILE__) + '/../../rails/init.rb'
3
3
 
4
4
  # Uncomment this once to create the db
5
- load_schema
5
+ # load_schema
6
6
 
7
7
  class Account < ActiveRecord::Base
8
8
  has_money :value, :total, :allow_nil => true
9
9
  end
10
10
 
11
11
  class Product < ActiveRecord::Base
12
- has_money :value
12
+ has_money :value, :allow_nil => false
13
13
  has_money :tax, :cents => "pennys", :with_currency => false
14
14
 
15
- validates_presence_of :value
15
+ validates_numericality_of :value_cents, :greater_than => 0
16
16
  end
17
17
 
18
18
  describe "Acts as Money" do
19
19
 
20
- it "should require money" do
21
- @account = Account.create(:value => nil)
22
- @account.value_in_cents.should eql(0)
23
- end
20
+ it "should accept nil" do
21
+ @account = Account.create(:value => nil)
22
+ @account.should be_valid
23
+ @account.value.should be_nil
24
+ end
25
+
26
+ it "should require money" do
27
+ @product = Product.create(:value => nil)
28
+ @product.should have(1).errors
29
+ @product.value.should == Money.new(0)
30
+ end
31
+
32
+ it "should require money" do
33
+ @product_fake = Product.create(:value => nil)
34
+ @product_fake.value_cents.should eql(0)
35
+ end
36
+
37
+ it "should create" do
38
+ @account = Account.create!(:value => 10, :total => "20 BRL")
39
+ @account.should be_valid
40
+ end
41
+
42
+ it "should write to the db" do
43
+ lambda do
44
+ @account = Account.create!(:value => 10, :total => "20 BRL")
45
+ end.should change(Account, :count).by(1)
46
+ Account.last.total.format.should eql("R$20,00")
47
+ end
24
48
 
25
- it "should require money" do
26
- @product_fake = Product.create(:value => nil)
27
- @product_fake.value_in_cents.should eql(0)
28
- end
29
49
 
30
50
  describe "Account" do
31
51
 
32
52
  before(:each) do
33
- @account = Account.create(:value => 10, :total => "20 BRL")
53
+ @account = Account.create!(:value => 10, :total => "20 BRL")
34
54
  end
35
55
 
36
56
  it "should return an instance of Money" do
37
57
  @account.value.should be_instance_of(Money)
38
58
  end
39
59
 
40
- it "should write to the db" do
41
- Account.first.value.to_s.should eql("10.00")
60
+ it "should format out nicely" do
61
+ @account.value.format.should eql("$10.00")
42
62
  end
43
63
 
44
64
  it "should include nicely" do
@@ -47,7 +67,7 @@ describe "Acts as Money" do
47
67
  end
48
68
 
49
69
  it "should map cents" do
50
- @account.value_in_cents.to_s.should eql("1000")
70
+ @account.value_cents.to_s.should eql("1000")
51
71
  end
52
72
 
53
73
  it "should map currency" do
@@ -71,8 +91,6 @@ describe "Acts as Money" do
71
91
  @product.should_not respond_to(:tax_currency)
72
92
  end
73
93
 
74
-
75
-
76
94
  end
77
95
 
78
96
  end
@@ -20,6 +20,8 @@ describe "Money core extensions" do
20
20
  it { "100.37".to_money.should == Money.new(100_37) }
21
21
  it { "100,37".to_money.should == Money.new(100_37) }
22
22
  it { "100 000".to_money.should == Money.new(100_000_00) }
23
+ it { "100.000,45".to_money.should == Money.new(100_000_45) }
24
+ it { "-100.100,45".to_money.should == Money.new(-100_100_45) }
23
25
 
24
26
  it { "100 USD".to_money.should == Money.new(100_00, "USD") }
25
27
  it { "-100 USD".to_money.should == Money.new(-100_00, "USD") }
@@ -34,6 +36,9 @@ describe "Money core extensions" do
34
36
  it { "EUR 100,37".to_money.should == Money.new(100_37, "EUR") }
35
37
  it { "EUR -100,37".to_money.should == Money.new(-100_37, "EUR") }
36
38
 
39
+ it { "BRL 100,37".to_money.should == Money.new(100_37, "BRL") }
40
+ it { "BRL -100,37".to_money.should == Money.new(-100_37, "BRL") }
41
+
37
42
  it {"$100 USD".to_money.should == Money.new(100_00, "USD") }
38
43
  end
39
44
  end
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
3
 
3
4
  describe Money do
@@ -75,8 +76,8 @@ describe Money do
75
76
  end
76
77
 
77
78
  it "should calculate tax" do
78
- Money.new(100).with_tax(20).cents.should eql(120)
79
- Money.new(100).with_tax(-20).cents.should eql(80)
79
+ Money.new(100).add_tax(20).cents.should eql(120)
80
+ Money.new(100).add_tax(-20).cents.should eql(80)
80
81
  end
81
82
 
82
83
  it "should calculate compound tax" do
@@ -95,17 +96,13 @@ describe Money do
95
96
  end
96
97
 
97
98
  it "shuld sum array" do
98
- @money = Money.new(10_00).with_tax(10)
99
+ @money = Money.new(10_00).add_tax(10)
99
100
  @money.split_in_installments(3).sum.cents.should eql(1100)
100
101
  end
101
102
 
102
- it "should output as float" do
103
- Money.new(10_00).to_f.should eql(10.0)
104
- end
103
+ it { Money.new(10_00).to_f.should eql(10.0) }
104
+ it { Money.new(10_00).to_s.should eql("10.00") }
105
105
 
106
- it "should output as string" do
107
- Money.new(10_00).to_s.should eql("10.00")
108
- end
109
106
 
110
107
  it "should create a new Money object of 0 cents if empty" do
111
108
  Money.empty.should == Money.new(0)
@@ -131,50 +128,89 @@ describe Money do
131
128
  Money.add_rate("EUR", "USD", 10)
132
129
  Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
133
130
  end
134
- end
135
-
136
- describe "Actions involving two Money objects" do
137
- describe "if the other Money object has the same currency" do
138
- it "#<=> compares the two objects' amounts" do
139
- (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
140
- (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
141
- (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
142
- end
143
-
144
- it "#+ adds the other object's amount to the current object's amount while retaining the currency" do
145
- (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
146
- end
147
131
 
148
- it "#- substracts the other object's amount from the current object's amount while retaining the currency" do
149
- (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
150
- end
132
+ it "Money method missing exchange" do
133
+ Money.add_rate("EUR", "BRL", 10)
134
+ Money.new(10_00, "EUR").as_brl.should == Money.new(100_00, "BRL")
151
135
  end
152
136
 
153
- describe "if the other Money object has a different currency" do
154
- it "#<=> compares the two objects' amount after converting the other object's amount to its own currency" do
155
- target = Money.new(200_00, "EUR")
156
- target.should_receive(:exchange_to).with("USD").and_return(Money.new(300_00, "USD"))
157
- (Money.new(100_00, "USD") <=> target).should < 0
137
+ describe "Format out " do
158
138
 
159
- target = Money.new(200_00, "EUR")
160
- target.should_receive(:exchange_to).with("USD").and_return(Money.new(100_00, "USD"))
161
- (Money.new(100_00, "USD") <=> target).should == 0
139
+ describe "Options" do
140
+ before(:each) do
141
+ @cash = Money.new(200)
142
+ end
162
143
 
163
- target = Money.new(200_00, "EUR")
164
- target.should_receive(:exchange_to).with("USD").and_return(Money.new(99_00, "USD"))
165
- (Money.new(100_00, "USD") <=> target).should > 0
144
+ it { @cash.format.should eql("$2.00") }
145
+ it { @cash.format(:symbol => "R$ ").should eql("R$ 2.00") }
146
+ it { @cash.format(:no_cents => true).should eql("$2") }
147
+ it { @cash.format(:no_cents => true, :symbol => "R$ ").should eql("R$ 2") }
166
148
  end
167
149
 
168
- it "#+ adds the other object's amount, converted to this object's currency, to this object's amount while retaining its currency" do
169
- other = Money.new(90, "EUR")
170
- other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
171
- (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
150
+ it { Money.new(0).format.should eql("$0.00") }
151
+ it { Money.new(0).format(:display_free => true).should eql("free") }
152
+ it { Money.new(0).format(:display_free => "GRATIS").should eql("GRATIS") }
153
+
154
+ it { Money.new(9).format.should eql("$0.09") }
155
+ it { Money.new(99).format.should eql("$0.99") }
156
+ it { Money.new(800).format.should eql("$8.00") }
157
+ it { Money.new(-8000).format(:no_cents => true).should eql("$-80") }
158
+ it { Money.new(80000).format.should eql("$800.00") }
159
+ it { Money.new(800000).format.should eql("$8,000.00") }
160
+ it { Money.new(-8000000, "JPY").format(:no_cents => true).should eql("¥-80.000") }
161
+ it { Money.new(87654321, "BRL").format.should eql("R$876.543,21") }
162
+ it { Money.new(800000000, "BRL").format.should eql("R$8.000.000,00") }
163
+ it { Money.new(8000000000, "BRL").format.should eql("R$80.000.000,00") }
164
+ it { Money.new(80000000000, "CAD").format.should eql("$800,000,000.00") }
165
+ it { Money.new(880000000000, "GBP").format(:no_cents => true).should eql("£8,800,000,000") }
166
+ it { Money.new(8800000000088, "EUR").format.should eql("€88,000,000,000.88") }
167
+
168
+ end
169
+
170
+
171
+ describe "Actions involving two Money objects" do
172
+ describe "if the other Money object has the same currency" do
173
+ it "#<=> compares the two objects' amounts" do
174
+ (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
175
+ (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
176
+ (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
177
+ end
178
+
179
+ it "#+ adds the other object's amount to the current object's amount while retaining the currency" do
180
+ (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
181
+ end
182
+
183
+ it "#- substracts the other object's amount from the current object's amount while retaining the currency" do
184
+ (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
185
+ end
172
186
  end
173
187
 
174
- it "#- substracts the other object's amount, converted to this object's currency, from this object's amount while retaining its currency" do
175
- other = Money.new(90, "EUR")
176
- other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
177
- (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
188
+ describe "if the other Money object has a different currency" do
189
+ it "#<=> compares the two objects' amount after converting the other object's amount to its own currency" do
190
+ target = Money.new(200_00, "EUR")
191
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(300_00, "USD"))
192
+ (Money.new(100_00, "USD") <=> target).should < 0
193
+
194
+ target = Money.new(200_00, "EUR")
195
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(100_00, "USD"))
196
+ (Money.new(100_00, "USD") <=> target).should == 0
197
+
198
+ target = Money.new(200_00, "EUR")
199
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(99_00, "USD"))
200
+ (Money.new(100_00, "USD") <=> target).should > 0
201
+ end
202
+
203
+ it "#+ adds the other object's amount, converted to this object's currency, to this object's amount while retaining its currency" do
204
+ other = Money.new(90, "EUR")
205
+ other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
206
+ (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
207
+ end
208
+
209
+ it "#- substracts the other object's amount, converted to this object's currency, from this object's amount while retaining its currency" do
210
+ other = Money.new(90, "EUR")
211
+ other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
212
+ (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
213
+ end
178
214
  end
179
215
  end
180
216
  end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
data/spec/spec_helper.rb CHANGED
@@ -11,12 +11,10 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
11
11
  require 'money'
12
12
 
13
13
  config = YAML.load_file(File.dirname(__FILE__) + '/db/database.yml')
14
- ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
14
+ ActiveRecord::Base.logger = Logger.new("/tmp/money-debug.log")
15
15
  ActiveRecord::Base.establish_connection(config)
16
16
 
17
17
 
18
18
  def load_schema
19
19
  load(File.dirname(__FILE__) + "/db/schema.rb")
20
20
  end
21
-
22
-
metadata CHANGED
@@ -1,19 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nofxx-money
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
- - FIXME full name
7
+ - Money Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-12 00:00:00 -08:00
12
+ date: 2009-03-15 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: newgem
17
+ type: :development
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -23,6 +24,7 @@ dependencies:
23
24
  version:
24
25
  - !ruby/object:Gem::Dependency
25
26
  name: hoe
27
+ type: :development
26
28
  version_requirement:
27
29
  version_requirements: !ruby/object:Gem::Requirement
28
30
  requirements:
@@ -32,7 +34,7 @@ dependencies:
32
34
  version:
33
35
  description: This library aids one in handling money and different currencies.
34
36
  email:
35
- - FIXME email
37
+ - see@readme
36
38
  executables: []
37
39
 
38
40
  extensions: []
@@ -58,14 +60,15 @@ files:
58
60
  - script/console
59
61
  - script/destroy
60
62
  - script/generate
61
- - spec/db/acts_as_money.sqlite3
62
63
  - spec/db/database.yml
63
64
  - spec/db/schema.rb
64
65
  - spec/money/acts_as_money_spec.rb
65
66
  - spec/money/core_extensions_spec.rb
66
67
  - spec/money/exchange_bank_spec.rb
67
68
  - spec/money/money_spec.rb
69
+ - spec/spec.opts
68
70
  - spec/spec_helper.rb
71
+ - tmp/acts_as_money.sqlite3
69
72
  has_rdoc: true
70
73
  homepage: http://github.com/nofxx/money
71
74
  post_install_message: