money 4.0.1 → 4.0.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.
- data/CHANGELOG.md +405 -391
- data/LICENSE +21 -21
- data/README.md +249 -243
- data/Rakefile +52 -49
- data/config/currency.json +2068 -2068
- data/config/currency_bc.json +41 -41
- data/lib/money.rb +28 -28
- data/lib/money/bank/base.rb +130 -131
- data/lib/money/bank/variable_exchange.rb +253 -252
- data/lib/money/core_extensions.rb +82 -82
- data/lib/money/currency.rb +280 -263
- data/lib/money/currency_loader.rb +21 -19
- data/lib/money/money.rb +411 -405
- data/lib/money/money/arithmetic.rb +257 -246
- data/lib/money/money/formatting.rb +251 -260
- data/lib/money/money/parsing.rb +350 -350
- data/money.gemspec +29 -29
- data/spec/bank/base_spec.rb +69 -72
- data/spec/bank/variable_exchange_spec.rb +233 -238
- data/spec/core_extensions_spec.rb +160 -158
- data/spec/currency_spec.rb +139 -120
- data/spec/money/arithmetic_spec.rb +482 -479
- data/spec/money/formatting_spec.rb +402 -383
- data/spec/money/parsing_spec.rb +210 -197
- data/spec/money_spec.rb +312 -292
- data/spec/spec_helper.rb +32 -28
- metadata +14 -14
data/spec/money/parsing_spec.rb
CHANGED
@@ -1,197 +1,210 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Money do
|
6
|
-
|
7
|
-
|
8
|
-
it "
|
9
|
-
five_ninety_five = Money.new(595, 'EUR')
|
10
|
-
|
11
|
-
Money.parse('EUR 5,95').should == five_ninety_five
|
12
|
-
#TODO: try and handle these
|
13
|
-
#Money.parse('€5,95').should == five_ninety_five
|
14
|
-
#Money.parse('$5.95').should == five_ninety_five
|
15
|
-
end
|
16
|
-
|
17
|
-
it "
|
18
|
-
Money.parse('EUR 1.234.567,89').should == Money.new(123456789, 'EUR')
|
19
|
-
Money.parse('EUR 1.111.234.567,89').should == Money.new(111123456789, 'EUR')
|
20
|
-
end
|
21
|
-
|
22
|
-
it "
|
23
|
-
five_ninety_five = Money.new(595, 'USD')
|
24
|
-
|
25
|
-
Money.parse(5.95).should == five_ninety_five
|
26
|
-
Money.parse('5.95').should == five_ninety_five
|
27
|
-
Money.parse('$5.95').should == five_ninety_five
|
28
|
-
Money.parse("\n $5.95 \n").should == five_ninety_five
|
29
|
-
Money.parse('$ 5.95').should == five_ninety_five
|
30
|
-
Money.parse('$5.95 ea.').should == five_ninety_five
|
31
|
-
Money.parse('$5.95, each').should == five_ninety_five
|
32
|
-
end
|
33
|
-
|
34
|
-
it "
|
35
|
-
Money.parse('1,234,567.89').should == Money.new(123456789, 'USD')
|
36
|
-
Money.parse('1,111,234,567.89').should == Money.new(111123456789, 'USD')
|
37
|
-
end
|
38
|
-
|
39
|
-
it "
|
40
|
-
lambda {Money.parse('$5.95-10.95')}.should raise_error ArgumentError
|
41
|
-
lambda {Money.parse('$5.95 - 10.95')}.should raise_error ArgumentError
|
42
|
-
lambda {Money.parse('$5.95 - $10.95')}.should raise_error ArgumentError
|
43
|
-
end
|
44
|
-
|
45
|
-
it "
|
46
|
-
# TODO: shouldn't these throw an error instead of being considered
|
47
|
-
# equal to $0.0?
|
48
|
-
empty_price = Money.new(0, 'USD')
|
49
|
-
|
50
|
-
Money.parse(nil).should == empty_price
|
51
|
-
Money.parse('hellothere').should == empty_price
|
52
|
-
Money.parse('').should == empty_price
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
Money.
|
59
|
-
Money.
|
60
|
-
Money.
|
61
|
-
end
|
62
|
-
|
63
|
-
it "
|
64
|
-
Money.
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
it "
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
Money.
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
it "
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
Money.
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
it "
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
Money.
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
it "
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
Money.
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
Money.
|
171
|
-
Money.from_numeric(1.0
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
Money.from_numeric(
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
Money.from_numeric(1).should == Money.new(1_00)
|
182
|
-
Money.
|
183
|
-
Money.from_numeric(1, "
|
184
|
-
end
|
185
|
-
|
186
|
-
it "
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Money, "parsing" do
|
6
|
+
|
7
|
+
describe ".parse" do
|
8
|
+
it "parses european-formatted inputs under 10EUR" do
|
9
|
+
five_ninety_five = Money.new(595, 'EUR')
|
10
|
+
|
11
|
+
Money.parse('EUR 5,95').should == five_ninety_five
|
12
|
+
#TODO: try and handle these
|
13
|
+
#Money.parse('€5,95').should == five_ninety_five
|
14
|
+
#Money.parse('$5.95').should == five_ninety_five
|
15
|
+
end
|
16
|
+
|
17
|
+
it "parses european-formatted inputs with multiple thousands-seperators" do
|
18
|
+
Money.parse('EUR 1.234.567,89').should == Money.new(123456789, 'EUR')
|
19
|
+
Money.parse('EUR 1.111.234.567,89').should == Money.new(111123456789, 'EUR')
|
20
|
+
end
|
21
|
+
|
22
|
+
it "parses USD-formatted inputs under $10" do
|
23
|
+
five_ninety_five = Money.new(595, 'USD')
|
24
|
+
|
25
|
+
Money.parse(5.95).should == five_ninety_five
|
26
|
+
Money.parse('5.95').should == five_ninety_five
|
27
|
+
Money.parse('$5.95').should == five_ninety_five
|
28
|
+
Money.parse("\n $5.95 \n").should == five_ninety_five
|
29
|
+
Money.parse('$ 5.95').should == five_ninety_five
|
30
|
+
Money.parse('$5.95 ea.').should == five_ninety_five
|
31
|
+
Money.parse('$5.95, each').should == five_ninety_five
|
32
|
+
end
|
33
|
+
|
34
|
+
it "parses USD-formatted inputs with multiple thousands-seperators" do
|
35
|
+
Money.parse('1,234,567.89').should == Money.new(123456789, 'USD')
|
36
|
+
Money.parse('1,111,234,567.89').should == Money.new(111123456789, 'USD')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "does not return a price if there is a price range" do
|
40
|
+
lambda { Money.parse('$5.95-10.95') }.should raise_error ArgumentError
|
41
|
+
lambda { Money.parse('$5.95 - 10.95') }.should raise_error ArgumentError
|
42
|
+
lambda { Money.parse('$5.95 - $10.95') }.should raise_error ArgumentError
|
43
|
+
end
|
44
|
+
|
45
|
+
it "does not return a price for completely invalid input" do
|
46
|
+
# TODO: shouldn't these throw an error instead of being considered
|
47
|
+
# equal to $0.0?
|
48
|
+
empty_price = Money.new(0, 'USD')
|
49
|
+
|
50
|
+
Money.parse(nil).should == empty_price
|
51
|
+
Money.parse('hellothere').should == empty_price
|
52
|
+
Money.parse('').should == empty_price
|
53
|
+
end
|
54
|
+
|
55
|
+
it "handles negative inputs" do
|
56
|
+
five_ninety_five = Money.new(595, 'USD')
|
57
|
+
|
58
|
+
Money.parse("$-5.95").should == -five_ninety_five
|
59
|
+
Money.parse("-$5.95").should == -five_ninety_five
|
60
|
+
Money.parse("$5.95-").should == -five_ninety_five
|
61
|
+
end
|
62
|
+
|
63
|
+
it "raises ArgumentError when unable to detect polarity" do
|
64
|
+
lambda { Money.parse('-$5.95-') }.should raise_error ArgumentError
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe ".from_string" do
|
69
|
+
it "converts given amount to cents" do
|
70
|
+
Money.from_string("1").should == Money.new(1_00)
|
71
|
+
Money.from_string("1").should == Money.new(1_00, "USD")
|
72
|
+
Money.from_string("1", "EUR").should == Money.new(1_00, "EUR")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "respects :subunit_to_unit currency property" do
|
76
|
+
Money.from_string("1", "USD").should == Money.new(1_00, "USD")
|
77
|
+
Money.from_string("1", "TND").should == Money.new(1_000, "TND")
|
78
|
+
Money.from_string("1", "CLP").should == Money.new(1, "CLP")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "accepts a currency options" do
|
82
|
+
m = Money.from_string("1")
|
83
|
+
m.currency.should == Money.default_currency
|
84
|
+
|
85
|
+
m = Money.from_string("1", Money::Currency.wrap("EUR"))
|
86
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
87
|
+
|
88
|
+
m = Money.from_string("1", "EUR")
|
89
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe ".from_fixnum" do
|
94
|
+
it "converts given amount to cents" do
|
95
|
+
Money.from_fixnum(1).should == Money.new(1_00)
|
96
|
+
Money.from_fixnum(1).should == Money.new(1_00, "USD")
|
97
|
+
Money.from_fixnum(1, "EUR").should == Money.new(1_00, "EUR")
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should respect :subunit_to_unit currency property" do
|
101
|
+
Money.from_fixnum(1, "USD").should == Money.new(1_00, "USD")
|
102
|
+
Money.from_fixnum(1, "TND").should == Money.new(1_000, "TND")
|
103
|
+
Money.from_fixnum(1, "CLP").should == Money.new(1, "CLP")
|
104
|
+
end
|
105
|
+
|
106
|
+
it "accepts a currency options" do
|
107
|
+
m = Money.from_fixnum(1)
|
108
|
+
m.currency.should == Money.default_currency
|
109
|
+
|
110
|
+
m = Money.from_fixnum(1, Money::Currency.wrap("EUR"))
|
111
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
112
|
+
|
113
|
+
m = Money.from_fixnum(1, "EUR")
|
114
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe ".from_float" do
|
119
|
+
it "converts given amount to cents" do
|
120
|
+
Money.from_float(1.2).should == Money.new(1_20)
|
121
|
+
Money.from_float(1.2).should == Money.new(1_20, "USD")
|
122
|
+
Money.from_float(1.2, "EUR").should == Money.new(1_20, "EUR")
|
123
|
+
end
|
124
|
+
|
125
|
+
it "respects :subunit_to_unit currency property" do
|
126
|
+
Money.from_float(1.2, "USD").should == Money.new(1_20, "USD")
|
127
|
+
Money.from_float(1.2, "TND").should == Money.new(1_200, "TND")
|
128
|
+
Money.from_float(1.2, "CLP").should == Money.new(1, "CLP")
|
129
|
+
end
|
130
|
+
|
131
|
+
it "accepts a currency options" do
|
132
|
+
m = Money.from_float(1.2)
|
133
|
+
m.currency.should == Money.default_currency
|
134
|
+
|
135
|
+
m = Money.from_float(1.2, Money::Currency.wrap("EUR"))
|
136
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
137
|
+
|
138
|
+
m = Money.from_float(1.2, "EUR")
|
139
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe ".from_bigdecimal" do
|
144
|
+
it "converts given amount to cents" do
|
145
|
+
Money.from_bigdecimal(BigDecimal.new("1")).should == Money.new(1_00)
|
146
|
+
Money.from_bigdecimal(BigDecimal.new("1")).should == Money.new(1_00, "USD")
|
147
|
+
Money.from_bigdecimal(BigDecimal.new("1"), "EUR").should == Money.new(1_00, "EUR")
|
148
|
+
end
|
149
|
+
|
150
|
+
it "respects :subunit_to_unit currency property" do
|
151
|
+
Money.from_bigdecimal(BigDecimal.new("1"), "USD").should == Money.new(1_00, "USD")
|
152
|
+
Money.from_bigdecimal(BigDecimal.new("1"), "TND").should == Money.new(1_000, "TND")
|
153
|
+
Money.from_bigdecimal(BigDecimal.new("1"), "CLP").should == Money.new(1, "CLP")
|
154
|
+
end
|
155
|
+
|
156
|
+
it "accepts a currency options" do
|
157
|
+
m = Money.from_bigdecimal(BigDecimal.new("1"))
|
158
|
+
m.currency.should == Money.default_currency
|
159
|
+
|
160
|
+
m = Money.from_bigdecimal(BigDecimal.new("1"), Money::Currency.wrap("EUR"))
|
161
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
162
|
+
|
163
|
+
m = Money.from_bigdecimal(BigDecimal.new("1"), "EUR")
|
164
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe ".from_numeric" do
|
169
|
+
it "converts given amount to cents" do
|
170
|
+
Money.from_numeric(1).should == Money.new(1_00)
|
171
|
+
Money.from_numeric(1.0).should == Money.new(1_00)
|
172
|
+
Money.from_numeric(BigDecimal.new("1")).should == Money.new(1_00)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "raises ArgumentError with unsupported argument" do
|
176
|
+
lambda { Money.from_numeric("100") }.should raise_error(ArgumentError)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "optimizes workload" do
|
180
|
+
Money.should_receive(:from_fixnum).with(1, "USD").and_return(Money.new(1_00, "USD"))
|
181
|
+
Money.from_numeric(1, "USD").should == Money.new(1_00, "USD")
|
182
|
+
Money.should_receive(:from_bigdecimal).with(BigDecimal.new("1.0"), "USD").and_return(Money.new(1_00, "USD"))
|
183
|
+
Money.from_numeric(1.0, "USD").should == Money.new(1_00, "USD")
|
184
|
+
end
|
185
|
+
|
186
|
+
it "respects :subunit_to_unit currency property" do
|
187
|
+
Money.from_numeric(1, "USD").should == Money.new(1_00, "USD")
|
188
|
+
Money.from_numeric(1, "TND").should == Money.new(1_000, "TND")
|
189
|
+
Money.from_numeric(1, "CLP").should == Money.new(1, "CLP")
|
190
|
+
end
|
191
|
+
|
192
|
+
it "accepts a bank option" do
|
193
|
+
Money.from_numeric(1).should == Money.new(1_00)
|
194
|
+
Money.from_numeric(1).should == Money.new(1_00, "USD")
|
195
|
+
Money.from_numeric(1, "EUR").should == Money.new(1_00, "EUR")
|
196
|
+
end
|
197
|
+
|
198
|
+
it "accepts a currency options" do
|
199
|
+
m = Money.from_numeric(1)
|
200
|
+
m.currency.should == Money.default_currency
|
201
|
+
|
202
|
+
m = Money.from_numeric(1, Money::Currency.wrap("EUR"))
|
203
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
204
|
+
|
205
|
+
m = Money.from_numeric(1, "EUR")
|
206
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
data/spec/money_spec.rb
CHANGED
@@ -1,292 +1,312 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Money do
|
6
|
-
|
7
|
-
describe "
|
8
|
-
it "rounds the given cents to an integer" do
|
9
|
-
Money.new(1.00, "USD").cents.should == 1
|
10
|
-
Money.new(1.01, "USD").cents.should == 1
|
11
|
-
Money.new(1.50, "USD").cents.should == 2
|
12
|
-
end
|
13
|
-
|
14
|
-
it "is associated to the singleton instance of Bank::VariableExchange by default" do
|
15
|
-
Money.new(0).bank.should
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
Money.
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
Money.new_with_dollars(
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
Money.
|
43
|
-
Money.
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
it "
|
189
|
-
Money.
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
Money.
|
198
|
-
end
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
Money.
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
it "
|
226
|
-
Money.
|
227
|
-
end
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
moneys
|
269
|
-
moneys[
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
moneys[0
|
275
|
-
moneys[
|
276
|
-
moneys[
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
Money.
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Money do
|
6
|
+
|
7
|
+
describe ".new" do
|
8
|
+
it "rounds the given cents to an integer" do
|
9
|
+
Money.new(1.00, "USD").cents.should == 1
|
10
|
+
Money.new(1.01, "USD").cents.should == 1
|
11
|
+
Money.new(1.50, "USD").cents.should == 2
|
12
|
+
end
|
13
|
+
|
14
|
+
it "is associated to the singleton instance of Bank::VariableExchange by default" do
|
15
|
+
Money.new(0).bank.should be(Money::Bank::VariableExchange.instance)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".new_with_dollars" do
|
20
|
+
it "converts given amount to cents" do
|
21
|
+
Money.new_with_dollars(1).should == Money.new(100)
|
22
|
+
Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
|
23
|
+
Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "respects :subunit_to_unit currency property" do
|
27
|
+
Money.new_with_dollars(1, "USD").should == Money.new(1_00, "USD")
|
28
|
+
Money.new_with_dollars(1, "TND").should == Money.new(1_000, "TND")
|
29
|
+
Money.new_with_dollars(1, "CLP").should == Money.new(1, "CLP")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "does not loose precision" do
|
33
|
+
Money.new_with_dollars(1234).cents.should == 1234_00
|
34
|
+
Money.new_with_dollars(100.37).cents.should == 100_37
|
35
|
+
Money.new_with_dollars(BigDecimal.new('1234')).cents.should == 1234_00
|
36
|
+
end
|
37
|
+
|
38
|
+
it "accepts optional currency" do
|
39
|
+
m = Money.new_with_dollars(1)
|
40
|
+
m.currency.should == Money.default_currency
|
41
|
+
|
42
|
+
m = Money.new_with_dollars(1, Money::Currency.wrap("EUR"))
|
43
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
44
|
+
|
45
|
+
m = Money.new_with_dollars(1, "EUR")
|
46
|
+
m.currency.should == Money::Currency.wrap("EUR")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "accepts optional bank" do
|
50
|
+
m = Money.new_with_dollars(1)
|
51
|
+
m.bank.should == Money.default_bank
|
52
|
+
|
53
|
+
m = Money.new_with_dollars(1, "EUR", bank = Object.new)
|
54
|
+
m.bank.should == bank
|
55
|
+
end
|
56
|
+
|
57
|
+
it "is associated to the singleton instance of Bank::VariableExchange by default" do
|
58
|
+
Money.new_with_dollars(0).bank.should be(Money::Bank::VariableExchange.instance)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe ".empty" do
|
63
|
+
it "creates a new Money object of 0 cents" do
|
64
|
+
Money.empty.should == Money.new(0)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe ".ca_dollar" do
|
69
|
+
it "creates a new Money object of the given value in CAD" do
|
70
|
+
Money.ca_dollar(50).should == Money.new(50, "CAD")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe ".us_dollar" do
|
75
|
+
it "creates a new Money object of the given value in USD" do
|
76
|
+
Money.us_dollar(50).should == Money.new(50, "USD")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe ".euro" do
|
81
|
+
it "creates a new Money object of the given value in EUR" do
|
82
|
+
Money.euro(50).should == Money.new(50, "EUR")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe ".add_rate" do
|
87
|
+
it "saves rate into current bank" do
|
88
|
+
Money.add_rate("EUR", "USD", 10)
|
89
|
+
Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
describe "#cents" do
|
95
|
+
it "returns the amount of cents" do
|
96
|
+
Money.new(1_00).cents.should == 1_00
|
97
|
+
Money.new_with_dollars(1).cents.should == 1_00
|
98
|
+
end
|
99
|
+
|
100
|
+
it "stores cents as an integer regardless of what is passed into the constructor" do
|
101
|
+
[ Money.new(100), 1.to_money, 1.00.to_money, BigDecimal('1.00').to_money ].each do |m|
|
102
|
+
m.cents.should == 100
|
103
|
+
m.cents.should be_a(Fixnum)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "#dollars" do
|
109
|
+
it "returns the amount of cents as dollars" do
|
110
|
+
Money.new(1_00).dollars.should == 1
|
111
|
+
Money.new_with_dollars(1).dollars.should == 1
|
112
|
+
end
|
113
|
+
|
114
|
+
it "respects :subunit_to_unit currency property" do
|
115
|
+
Money.new(1_00, "USD").dollars.should == 1
|
116
|
+
Money.new(1_000, "TND").dollars.should == 1
|
117
|
+
Money.new(1, "CLP").dollars.should == 1
|
118
|
+
end
|
119
|
+
|
120
|
+
it "does not loose precision" do
|
121
|
+
Money.new(100_37).dollars.should == 100.37
|
122
|
+
Money.new_with_dollars(100.37).dollars.should == 100.37
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#currency" do
|
127
|
+
it "returns the currency object" do
|
128
|
+
Money.new(1_00, "USD").currency.should == Money::Currency.new("USD")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "#currency_as_string" do
|
133
|
+
it "returns the iso_code of the currency object" do
|
134
|
+
Money.new(1_00, "USD").currency_as_string.should == "USD"
|
135
|
+
Money.new(1_00, "EUR").currency_as_string.should == "EUR"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "#currency_as_string=" do
|
140
|
+
it "sets the currency object using the provided string" do
|
141
|
+
money = Money.new(100_00, "USD")
|
142
|
+
money.currency_as_string = "EUR"
|
143
|
+
money.currency.should == Money::Currency.new("EUR")
|
144
|
+
money.currency_as_string = "YEN"
|
145
|
+
money.currency.should == Money::Currency.new("YEN")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "#hash=" do
|
150
|
+
it "returns the same value for equal objects" do
|
151
|
+
Money.new(1_00, "EUR").hash.should == Money.new(1_00, "EUR").hash
|
152
|
+
Money.new(2_00, "USD").hash.should == Money.new(2_00, "USD").hash
|
153
|
+
Money.new(1_00, "EUR").hash.should_not == Money.new(2_00, "EUR").hash
|
154
|
+
Money.new(1_00, "EUR").hash.should_not == Money.new(1_00, "USD").hash
|
155
|
+
Money.new(1_00, "EUR").hash.should_not == Money.new(2_00, "USD").hash
|
156
|
+
end
|
157
|
+
|
158
|
+
it "can be used to return the intersection of Money object arrays" do
|
159
|
+
intersection = [Money.new(1_00, "EUR"), Money.new(1_00, "USD")] & [Money.new(1_00, "EUR")]
|
160
|
+
intersection.should == [Money.new(1_00, "EUR")]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "#symbol" do
|
165
|
+
it "works as documented" do
|
166
|
+
currency = Money::Currency.new("EUR")
|
167
|
+
currency.should_receive(:symbol).and_return("€")
|
168
|
+
Money.empty(currency).symbol.should == "€"
|
169
|
+
|
170
|
+
currency = Money::Currency.new("EUR")
|
171
|
+
currency.should_receive(:symbol).and_return(nil)
|
172
|
+
Money.empty(currency).symbol.should == "¤"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "#to_s" do
|
177
|
+
it "works as documented" do
|
178
|
+
Money.new(10_00).to_s.should == "10.00"
|
179
|
+
Money.new(400_08).to_s.should == "400.08"
|
180
|
+
Money.new(-237_43).to_s.should == "-237.43"
|
181
|
+
end
|
182
|
+
|
183
|
+
it "respects :subunit_to_unit currency property" do
|
184
|
+
Money.new(10_00, "BHD").to_s.should == "1.000"
|
185
|
+
Money.new(10_00, "CNY").to_s.should == "10.00"
|
186
|
+
end
|
187
|
+
|
188
|
+
it "does not have decimal when :subunit_to_unit == 1" do
|
189
|
+
Money.new(10_00, "CLP").to_s.should == "1000"
|
190
|
+
end
|
191
|
+
|
192
|
+
it "does not work when :subunit_to_unit == 5" do
|
193
|
+
Money.new(10_00, "MGA").to_s.should == "200.0"
|
194
|
+
end
|
195
|
+
|
196
|
+
it "respects :decimal_mark" do
|
197
|
+
Money.new(10_00, "BRL").to_s.should == "10,00"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "#to_d" do
|
202
|
+
it "works as documented" do
|
203
|
+
decimal = Money.new(10_00).to_d
|
204
|
+
decimal.should be_a(BigDecimal)
|
205
|
+
decimal.should == 10.0
|
206
|
+
end
|
207
|
+
|
208
|
+
it "respects :subunit_to_unit currency property" do
|
209
|
+
decimal = Money.new(10_00, "BHD").to_d
|
210
|
+
decimal.should be_a(BigDecimal)
|
211
|
+
decimal.should == 1.0
|
212
|
+
end
|
213
|
+
|
214
|
+
it "works with float :subunit_to_unit currency property" do
|
215
|
+
money = Money.new(10_00, "BHD")
|
216
|
+
money.currency.stub(:subunit_to_unit).and_return(1000.0)
|
217
|
+
|
218
|
+
decimal = money.to_d
|
219
|
+
decimal.should be_a(BigDecimal)
|
220
|
+
decimal.should == 1.0
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe "#to_f" do
|
225
|
+
it "works as documented" do
|
226
|
+
Money.new(10_00).to_f.should == 10.0
|
227
|
+
end
|
228
|
+
|
229
|
+
it "respects :subunit_to_unit currency property" do
|
230
|
+
Money.new(10_00, "BHD").to_f.should == 1.0
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
describe "#to_money" do
|
235
|
+
it "works as documented" do
|
236
|
+
money = Money.new(10_00, "DKK")
|
237
|
+
money.should == money.to_money
|
238
|
+
money.should == money.to_money("DKK")
|
239
|
+
money.bank.should_receive(:exchange_with).with(Money.new(10_00, Money::Currency.new("DKK")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
|
240
|
+
money.to_money("EUR").should == Money.new(200_00, "EUR")
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "#exchange_to" do
|
245
|
+
it "exchanges the amount via its exchange bank" do
|
246
|
+
money = Money.new(100_00, "USD")
|
247
|
+
money.bank.should_receive(:exchange_with).with(Money.new(100_00, Money::Currency.new("USD")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
|
248
|
+
money.exchange_to("EUR")
|
249
|
+
end
|
250
|
+
|
251
|
+
it "exchanges the amount properly" do
|
252
|
+
money = Money.new(100_00, "USD")
|
253
|
+
money.bank.should_receive(:exchange_with).with(Money.new(100_00, Money::Currency.new("USD")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
|
254
|
+
money.exchange_to("EUR").should == Money.new(200_00, "EUR")
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
describe "#allocate" do
|
259
|
+
it "takes no action when one gets all" do
|
260
|
+
Money.us_dollar(005).allocate([1.0]).should == [Money.us_dollar(5)]
|
261
|
+
end
|
262
|
+
|
263
|
+
it "keeps currencies intact" do
|
264
|
+
Money.ca_dollar(005).allocate([1]).should == [Money.ca_dollar(5)]
|
265
|
+
end
|
266
|
+
|
267
|
+
it "does not loose pennies" do
|
268
|
+
moneys = Money.us_dollar(5).allocate([0.3, 0.7])
|
269
|
+
moneys[0].should == Money.us_dollar(2)
|
270
|
+
moneys[1].should == Money.us_dollar(3)
|
271
|
+
end
|
272
|
+
|
273
|
+
it "does not loose pennies" do
|
274
|
+
moneys = Money.us_dollar(100).allocate([0.333, 0.333, 0.333])
|
275
|
+
moneys[0].cents.should == 34
|
276
|
+
moneys[1].cents.should == 33
|
277
|
+
moneys[2].cents.should == 33
|
278
|
+
end
|
279
|
+
|
280
|
+
it "requires total to be less then 1" do
|
281
|
+
expect { Money.us_dollar(0.05).allocate([0.5, 0.6]) }.to raise_error(ArgumentError)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "#split" do
|
286
|
+
it "needs at least one party" do
|
287
|
+
expect { Money.us_dollar(1).split(0) }.to raise_error(ArgumentError)
|
288
|
+
expect { Money.us_dollar(1).split(-1) }.to raise_error(ArgumentError)
|
289
|
+
end
|
290
|
+
|
291
|
+
it "gives 1 cent to both people if we start with 2" do
|
292
|
+
Money.us_dollar(2).split(2).should == [Money.us_dollar(1), Money.us_dollar(1)]
|
293
|
+
end
|
294
|
+
|
295
|
+
it "may distribute no money to some parties if there isnt enough to go around" do
|
296
|
+
Money.us_dollar(2).split(3).should == [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)]
|
297
|
+
end
|
298
|
+
|
299
|
+
it "does not lose pennies" do
|
300
|
+
Money.us_dollar(5).split(2).should == [Money.us_dollar(3), Money.us_dollar(2)]
|
301
|
+
end
|
302
|
+
|
303
|
+
it "splits a dollar" do
|
304
|
+
moneys = Money.us_dollar(100).split(3)
|
305
|
+
moneys[0].cents.should == 34
|
306
|
+
moneys[1].cents.should == 33
|
307
|
+
moneys[2].cents.should == 33
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|