money 2.1.1 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,19 +20,105 @@ class String
20
20
  # '$100 USD'.to_money # => #<Money @cents=10000, @currency="USD">
21
21
  def to_money
22
22
  # Get the currency.
23
- matches = scan /([A-Z]{2,3})/
23
+ matches = scan /([A-Z]{2,3})/
24
24
  currency = matches[0] ? matches[0][0] : Money.default_currency
25
+ cents = calculate_cents(self)
26
+ Money.new(cents, currency)
27
+ end
28
+
29
+ private
30
+
31
+ def calculate_cents(number)
32
+ # remove anything that's not a number, potential delimiter, or minus sign
33
+ num = number.gsub(/[^\d|\.|,|\'|\s|\-]/, '').strip
34
+
35
+ # set a boolean flag for if the number is negative or not
36
+ negative = num.split(//).first == "-"
37
+
38
+ # if negative, remove the minus sign from the number
39
+ num = num.gsub(/^-/, '') if negative
25
40
 
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
41
+ # gather all separators within the result number
42
+ used_separators = num.scan /[^\d]/
43
+
44
+ # determine the number of unique separators within the number
45
+ #
46
+ # e.g.
47
+ # $1,234,567.89 would return 2 (, and .)
48
+ # $125,00 would return 1
49
+ # $199 would return 0
50
+ # $1 234,567.89 would raise an error (separators are space, comma, and period)
51
+ case used_separators.uniq.length
52
+ # no separator or delimiter; major (dollars) is the number, and minor (cents) is 0
53
+ when 0 then major, minor = num, 0
54
+
55
+ # two separators, so we know the last item in this array is the
56
+ # major/minor delimiter and the rest are separators
57
+ when 2
58
+ separator, delimiter = used_separators.uniq
59
+ # remove all separators, split on the delimiter
60
+ major, minor = num.gsub(separator, '').split(delimiter)
61
+ min = 0 unless min
62
+ when 1
63
+ # we can't determine if the comma or period is supposed to be a separator or a delimiter
64
+ # e.g.
65
+ # 1,00 - comma is a delimiter
66
+ # 1.000 - period is a delimiter
67
+ # 1,000 - comma is a separator
68
+ # 1,000,000 - comma is a separator
69
+ # 10000,00 - comma is a delimiter
70
+ # 1000,000 - comma is a delimiter
71
+
72
+ # assign first separator for reusability
73
+ separator = used_separators.first
74
+
75
+ # separator is used as a separator when there are multiple instances, always
76
+ if num.scan(separator).length > 1 # multiple matches; treat as separator
77
+ major, minor = num.gsub(separator, ''), 0
78
+ else
79
+ # ex: 1,000 - 1.0000 - 10001.000
80
+ # split number into possible major (dollars) and minor (cents) values
81
+ possible_major, possible_minor = num.split(separator)
82
+
83
+ # if the minor (cents) length isn't 3, assign major/minor from the possibles
84
+ # e.g.
85
+ # 1,00 => 1.00
86
+ # 1.0000 => 1.00
87
+ # 1.2 => 1.20
88
+ if possible_minor.length != 3 # delimiter
89
+ major, minor = possible_major, possible_minor
90
+ else
91
+ # minor length is three
92
+ # let's try to figure out intent of the delimiter
93
+
94
+ # the major length is greater than three, which means
95
+ # the comma or period is used as a delimiter
96
+ # e.g.
97
+ # 1000,000
98
+ # 100000,000
99
+ if possible_major.length > 3
100
+ major, minor = possible_major, possible_minor
101
+ else
102
+ # number is in format ###{sep}### or ##{sep}### or #{sep}###
103
+ # handle as , is sep, . is delimiter
104
+ if separator == '.'
105
+ major, minor = possible_major, possible_minor
32
106
  else
33
- 0
107
+ major, minor = "#{possible_major}#{possible_minor}", 0
34
108
  end
109
+ end
110
+ end
111
+ end
112
+ else
113
+ raise ArgumentError, "Invalid currency amount"
114
+ end
35
115
 
36
- Money.new(cents, currency)
116
+ # build the string based on major/minor since separator/delimiters have been removed
117
+ # transform to a float, multiply by 100 to convert to cents
118
+ cents = "#{major}.#{minor}".to_f * 100
119
+
120
+ # if negative, multiply by -1; otherwise, return positive cents
121
+ negative ? cents * -1 : cents
37
122
  end
123
+
38
124
  end
data/lib/money/money.rb CHANGED
@@ -95,7 +95,7 @@ class Money
95
95
  Money.new(cents + other_money.cents, other_money.currency)
96
96
  else
97
97
  Money.new(cents + other_money.exchange_to(currency).cents,currency)
98
- end
98
+ end
99
99
  end
100
100
 
101
101
  def -(other_money)
@@ -103,7 +103,7 @@ class Money
103
103
  Money.new(cents - other_money.cents, other_money.currency)
104
104
  else
105
105
  Money.new(cents - other_money.exchange_to(currency).cents, currency)
106
- end
106
+ end
107
107
  end
108
108
 
109
109
  # get the cents value of the object
@@ -113,17 +113,17 @@ class Money
113
113
 
114
114
  # multiply money by fixnum
115
115
  def *(fixnum)
116
- Money.new(cents * fixnum, currency)
116
+ Money.new(cents * fixnum, currency)
117
117
  end
118
118
 
119
119
  # divide money by fixnum
120
120
  def /(fixnum)
121
- Money.new(cents / fixnum, currency)
121
+ Money.new(cents / fixnum, currency)
122
122
  end
123
123
 
124
124
  # Test if the money amount is zero
125
125
  def zero?
126
- cents == 0
126
+ cents == 0
127
127
  end
128
128
 
129
129
 
@@ -220,7 +220,7 @@ class Money
220
220
  # Conversation to self
221
221
  def to_money
222
222
  self
223
- end
223
+ end
224
224
 
225
225
  private
226
226
 
data/money.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "money"
3
- s.version = "2.1.1"
3
+ s.version = "2.1.2"
4
4
  s.summary = "Money and currency exchange support library"
5
5
  s.email = "hongli@phusion.nl"
6
6
  s.homepage = "http://money.rubyforge.org/"
@@ -17,12 +17,25 @@ describe "Money core extensions" do
17
17
  "100.37".to_money.should == Money.new(100_37)
18
18
  "100,37".to_money.should == Money.new(100_37)
19
19
  "100 000".to_money.should == Money.new(100_000_00)
20
+ "100,000.00".to_money.should == Money.new(100_000_00)
21
+ "1,000".to_money.should == Money.new(1_000_00)
22
+ "-1,000".to_money.should == Money.new(-1_000_00)
23
+ "1,000.0000".to_money.should == Money.new(1_000_00)
24
+ "1,000.5000".to_money.should == Money.new(1_000_50)
25
+ "1.550".to_money.should == Money.new(1_55)
20
26
 
21
27
  "100 USD".to_money.should == Money.new(100_00, "USD")
22
28
  "-100 USD".to_money.should == Money.new(-100_00, "USD")
23
29
  "100 EUR".to_money.should == Money.new(100_00, "EUR")
24
30
  "100.37 EUR".to_money.should == Money.new(100_37, "EUR")
25
31
  "100,37 EUR".to_money.should == Money.new(100_37, "EUR")
32
+ "100,000.00 USD".to_money.should == Money.new(100_000_00, "USD")
33
+ "100.000,00 EUR".to_money.should == Money.new(100_000_00, "EUR")
34
+ "1,000 USD".to_money.should == Money.new(1_000_00, "USD")
35
+ "-1,000 USD".to_money.should == Money.new(-1_000_00, "USD")
36
+ "1,000.5500 USD".to_money.should == Money.new(1_000_55, "USD")
37
+ "-1,000.6500 USD".to_money.should == Money.new(-1_000_65, "USD")
38
+ "1.550 USD".to_money.should == Money.new(1_55, "USD")
26
39
 
27
40
  "USD 100".to_money.should == Money.new(100_00, "USD")
28
41
  "EUR 100".to_money.should == Money.new(100_00, "EUR")
@@ -30,7 +43,19 @@ describe "Money core extensions" do
30
43
  "CAD -100.37".to_money.should == Money.new(-100_37, "CAD")
31
44
  "EUR 100,37".to_money.should == Money.new(100_37, "EUR")
32
45
  "EUR -100,37".to_money.should == Money.new(-100_37, "EUR")
46
+ "USD 100,000.00".to_money.should == Money.new(100_000_00, "USD")
47
+ "EUR 100.000,00".to_money.should == Money.new(100_000_00, "EUR")
48
+ "USD 1,000".to_money.should == Money.new(1_000_00, "USD")
49
+ "USD -1,000".to_money.should == Money.new(-1_000_00, "USD")
50
+ "USD 1,000.9000".to_money.should == Money.new(1_000_90, "USD")
51
+ "USD -1,000.090".to_money.should == Money.new(-1_000_09, "USD")
52
+ "USD 1.5500".to_money.should == Money.new(1_55, "USD")
33
53
 
34
54
  "$100 USD".to_money.should == Money.new(100_00, "USD")
55
+ "$1,194.59 USD".to_money.should == Money.new(1_194_59, "USD")
56
+ "$-1,955 USD".to_money.should == Money.new(-1_955_00, "USD")
57
+ "$1,194.5900 USD".to_money.should == Money.new(1_194_59, "USD")
58
+ "$-1,955.000 USD".to_money.should == Money.new(-1_955_00, "USD")
59
+ "$1.99000 USD".to_money.should == Money.new(1_99, "USD")
35
60
  end
36
61
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2009-02-19 00:00:00 +01:00
14
+ date: 2009-02-21 00:00:00 +01:00
15
15
  default_executable:
16
16
  dependencies: []
17
17