money 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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