money 3.7.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/CHANGELOG.md +384 -351
  2. data/LICENSE +21 -21
  3. data/README.md +243 -214
  4. data/Rakefile +49 -49
  5. data/lib/money.rb +28 -27
  6. data/lib/money/bank/base.rb +131 -131
  7. data/lib/money/bank/variable_exchange.rb +252 -252
  8. data/lib/money/core_extensions.rb +82 -82
  9. data/lib/money/currency.rb +263 -422
  10. data/lib/money/currency_loader.rb +19 -0
  11. data/lib/money/money.rb +405 -405
  12. data/lib/money/money/arithmetic.rb +246 -246
  13. data/lib/money/money/formatting.rb +260 -244
  14. data/lib/money/money/parsing.rb +350 -350
  15. data/money.gemspec +29 -35
  16. data/spec/bank/base_spec.rb +72 -72
  17. data/spec/bank/variable_exchange_spec.rb +238 -238
  18. data/spec/core_extensions_spec.rb +158 -158
  19. data/spec/currency_spec.rb +120 -133
  20. data/spec/money/arithmetic_spec.rb +479 -479
  21. data/spec/money/formatting_spec.rb +383 -375
  22. data/spec/money/parsing_spec.rb +197 -197
  23. data/spec/money_spec.rb +292 -292
  24. data/spec/spec_helper.rb +28 -28
  25. metadata +54 -126
  26. data/lib/money.rbc +0 -184
  27. data/lib/money/bank/base.rbc +0 -818
  28. data/lib/money/bank/variable_exchange.rbc +0 -2550
  29. data/lib/money/core_extensions.rbc +0 -664
  30. data/lib/money/currency.rbc +0 -22708
  31. data/lib/money/money.rbc +0 -3861
  32. data/lib/money/money/arithmetic.rbc +0 -2778
  33. data/lib/money/money/formatting.rbc +0 -2265
  34. data/lib/money/money/parsing.rbc +0 -2737
  35. data/spec/bank/base_spec.rbc +0 -2461
  36. data/spec/bank/variable_exchange_spec.rbc +0 -7541
  37. data/spec/core_extensions_spec.rbc +0 -5921
  38. data/spec/currency_spec.rbc +0 -4535
  39. data/spec/money/arithmetic_spec.rbc +0 -25140
  40. data/spec/money/formatting_spec.rbc +0 -12545
  41. data/spec/money/parsing_spec.rbc +0 -6511
  42. data/spec/money_spec.rbc +0 -9824
  43. data/spec/spec_helper.rbc +0 -575
@@ -1,244 +1,260 @@
1
- class Money
2
- module Formatting
3
-
4
- if Object.const_defined?("I18n")
5
- def thousands_separator
6
- if self.class.use_i18n
7
- I18n.t(
8
- :"number.currency.format.delimiter",
9
- :default => I18n.t(
10
- :"number.format.delimiter",
11
- :default => (currency.thousands_separator || ",")
12
- )
13
- )
14
- else
15
- currency.thousands_separator || ","
16
- end
17
- end
18
- else
19
- def thousands_separator
20
- currency.thousands_separator || ","
21
- end
22
- end
23
- alias :delimiter :thousands_separator
24
-
25
-
26
- if Object.const_defined?("I18n")
27
- def decimal_mark
28
- if self.class.use_i18n
29
- I18n.t(
30
- :"number.currency.format.separator",
31
- :default => I18n.t(
32
- :"number.format.separator",
33
- :default => (currency.decimal_mark || ".")
34
- )
35
- )
36
- else
37
- currency.decimal_mark || "."
38
- end
39
- end
40
- else
41
- def decimal_mark
42
- currency.decimal_mark || "."
43
- end
44
- end
45
- alias :separator :decimal_mark
46
-
47
- # Creates a formatted price string according to several rules.
48
- #
49
- # @param [Hash] *rules The options used to format the string.
50
- #
51
- # @return [String]
52
- #
53
- # @option *rules [Boolean, String] :display_free (false) Whether a zero
54
- # amount of money should be formatted of "free" or as the supplied string.
55
- #
56
- # @example
57
- # Money.us_dollar(0).format(:display_free => true) #=> "free"
58
- # Money.us_dollar(0).format(:display_free => "gratis") #=> "gratis"
59
- # Money.us_dollar(0).format #=> "$0.00"
60
- #
61
- # @option *rules [Boolean] :with_currency (false) Whether the currency name
62
- # should be appended to the result string.
63
- #
64
- # @example
65
- # Money.ca_dollar(100).format => "$1.00"
66
- # Money.ca_dollar(100).format(:with_currency => true) #=> "$1.00 CAD"
67
- # Money.us_dollar(85).format(:with_currency => true) #=> "$0.85 USD"
68
- #
69
- # @option *rules [Boolean] :no_cents (false) Whether cents should be omitted.
70
- #
71
- # @example
72
- # Money.ca_dollar(100).format(:no_cents => true) #=> "$1"
73
- # Money.ca_dollar(599).format(:no_cents => true) #=> "$5"
74
- #
75
- # @option *rules [Boolean] :no_cents_if_whole (false) Whether cents should be
76
- # omitted if the cent value is zero
77
- #
78
- # @example
79
- # Money.ca_dollar(10000).format(:no_cents_if_whole => true) #=> "$100"
80
- # Money.ca_dollar(10034).format(:no_cents_if_whole => true) #=> "$100.34"
81
- #
82
- # @option *rules [Boolean, String, nil] :symbol (true) Whether a money symbol
83
- # should be prepended to the result string. The default is true. This method
84
- # attempts to pick a symbol that's suitable for the given currency.
85
- #
86
- # @example
87
- # Money.new(100, "USD") #=> "$1.00"
88
- # Money.new(100, "GBP") #=> "£1.00"
89
- # Money.new(100, "EUR") #=> "1.00"
90
- #
91
- # # Same thing.
92
- # Money.new(100, "USD").format(:symbol => true) #=> "$1.00"
93
- # Money.new(100, "GBP").format(:symbol => true) #=> "£1.00"
94
- # Money.new(100, "EUR").format(:symbol => true) #=> "1.00"
95
- #
96
- # # You can specify a false expression or an empty string to disable
97
- # # prepending a money symbol.§
98
- # Money.new(100, "USD").format(:symbol => false) #=> "1.00"
99
- # Money.new(100, "GBP").format(:symbol => nil) #=> "1.00"
100
- # Money.new(100, "EUR").format(:symbol => "") #=> "1.00"
101
- #
102
- # # If the symbol for the given currency isn't known, then it will default
103
- # # to "¤" as symbol.
104
- # Money.new(100, "AWG").format(:symbol => true) #=> "¤1.00"
105
- #
106
- # # You can specify a string as value to enforce using a particular symbol.
107
- # Money.new(100, "AWG").format(:symbol => "ƒ") #=> "ƒ1.00"
108
- #
109
- # @option *rules [Boolean, String, nil] :decimal_mark (true) Whether the
110
- # currency should be separated by the specified character or '.'
111
- #
112
- # @example
113
- # # If a string is specified, it's value is used.
114
- # Money.new(100, "USD").format(:decimal_mark => ",") #=> "$1,00"
115
- #
116
- # # If the decimal_mark for a given currency isn't known, then it will default
117
- # # to "." as decimal_mark.
118
- # Money.new(100, "FOO").format #=> "$1.00"
119
- #
120
- # @option *rules [Boolean, String, nil] :thousands_separator (true) Whether
121
- # the currency should be delimited by the specified character or ','
122
- #
123
- # @example
124
- # # If false is specified, no thousands_separator is used.
125
- # Money.new(100000, "USD").format(:thousands_separator => false) #=> "1000.00"
126
- # Money.new(100000, "USD").format(:thousands_separator => nil) #=> "1000.00"
127
- # Money.new(100000, "USD").format(:thousands_separator => "") #=> "1000.00"
128
- #
129
- # # If a string is specified, it's value is used.
130
- # Money.new(100000, "USD").format(:thousands_separator => ".") #=> "$1.000.00"
131
- #
132
- # # If the thousands_separator for a given currency isn't known, then it will
133
- # # default to "," as thousands_separator.
134
- # Money.new(100000, "FOO").format #=> "$1,000.00"
135
- #
136
- # @option *rules [Boolean] :html (false) Whether the currency should be
137
- # HTML-formatted. Only useful in combination with +:with_currency+.
138
- #
139
- # @example
140
- # s = Money.ca_dollar(570).format(:html => true, :with_currency => true)
141
- # s #=> "$5.70 <span class=\"currency\">CAD</span>"
142
- def format(*rules)
143
- # support for old format parameters
144
- rules = normalize_formatting_rules(rules)
145
-
146
- if cents == 0
147
- if rules[:display_free].respond_to?(:to_str)
148
- return rules[:display_free]
149
- elsif rules[:display_free]
150
- return "free"
151
- end
152
- end
153
-
154
- symbol_value =
155
- if rules.has_key?(:symbol)
156
- if rules[:symbol] === true
157
- symbol
158
- elsif rules[:symbol]
159
- rules[:symbol]
160
- else
161
- ""
162
- end
163
- elsif rules[:html]
164
- currency.html_entity
165
- else
166
- symbol
167
- end
168
-
169
- formatted = case rules[:no_cents]
170
- when true
171
- "#{self.to_s.to_i}"
172
- else
173
- "#{self.to_s}"
174
- end
175
-
176
- if rules[:no_cents_if_whole] && cents % currency.subunit_to_unit == 0
177
- formatted = "#{self.to_s.to_i}"
178
- end
179
-
180
- symbol_position =
181
- if rules.has_key?(:symbol_position)
182
- rules[:symbol_position]
183
- elsif currency.symbol_first?
184
- :before
185
- else
186
- :after
187
- end
188
-
189
- if symbol_value && !symbol_value.empty?
190
- formatted = (symbol_position == :before ? "#{symbol_value}#{formatted}" : "#{formatted} #{symbol_value}")
191
- end
192
-
193
- if rules.has_key?(:decimal_mark) and rules[:decimal_mark] and
194
- rules[:decimal_mark] != decimal_mark
195
- formatted.sub!(decimal_mark, rules[:decimal_mark])
196
- end
197
-
198
- thousands_separator_value = thousands_separator
199
- # Determine thousands_separator
200
- if rules.has_key?(:thousands_separator)
201
- if rules[:thousands_separator] === false or rules[:thousands_separator].nil?
202
- thousands_separator_value = ""
203
- elsif rules[:thousands_separator]
204
- thousands_separator_value = rules[:thousands_separator]
205
- end
206
- end
207
-
208
- # Apply thousands_separator
209
- formatted.gsub!(/(\d)(?=(?:\d{3})+(?:[^\d]|$))/, "\\1#{thousands_separator_value}")
210
-
211
- if rules[:with_currency]
212
- formatted << " "
213
- formatted << '<span class="currency">' if rules[:html]
214
- formatted << currency.to_s
215
- formatted << '</span>' if rules[:html]
216
- end
217
- formatted
218
- end
219
-
220
-
221
- private
222
-
223
- # Cleans up formatting rules.
224
- #
225
- # @param [Hash]
226
- #
227
- # @return [Hash]
228
- def normalize_formatting_rules(rules)
229
- if rules.size == 0
230
- rules = {}
231
- elsif rules.size == 1
232
- rules = rules.pop
233
- rules = { rules => true } if rules.is_a?(Symbol)
234
- end
235
- if not rules.include?(:decimal_mark) and rules.include?(:separator)
236
- rules[:decimal_mark] = rules[:separator]
237
- end
238
- if not rules.include?(:thousands_separator) and rules.include?(:delimiter)
239
- rules[:thousands_separator] = rules[:delimiter]
240
- end
241
- rules
242
- end
243
- end
244
- end
1
+ # encoding: UTF-8
2
+ class Money
3
+ module Formatting
4
+
5
+ if Object.const_defined?("I18n")
6
+ def thousands_separator
7
+ if self.class.use_i18n
8
+ I18n.t(
9
+ :"number.currency.format.delimiter",
10
+ :default => I18n.t(
11
+ :"number.format.delimiter",
12
+ :default => (currency.thousands_separator || ",")
13
+ )
14
+ )
15
+ else
16
+ currency.thousands_separator || ","
17
+ end
18
+ end
19
+ else
20
+ def thousands_separator
21
+ currency.thousands_separator || ","
22
+ end
23
+ end
24
+ alias :delimiter :thousands_separator
25
+
26
+
27
+ if Object.const_defined?("I18n")
28
+ def decimal_mark
29
+ if self.class.use_i18n
30
+ I18n.t(
31
+ :"number.currency.format.separator",
32
+ :default => I18n.t(
33
+ :"number.format.separator",
34
+ :default => (currency.decimal_mark || ".")
35
+ )
36
+ )
37
+ else
38
+ currency.decimal_mark || "."
39
+ end
40
+ end
41
+ else
42
+ def decimal_mark
43
+ currency.decimal_mark || "."
44
+ end
45
+ end
46
+ alias :separator :decimal_mark
47
+
48
+ # Creates a formatted price string according to several rules.
49
+ #
50
+ # @param [Hash] *rules The options used to format the string.
51
+ #
52
+ # @return [String]
53
+ #
54
+ # @option *rules [Boolean, String] :display_free (false) Whether a zero
55
+ # amount of money should be formatted of "free" or as the supplied string.
56
+ #
57
+ # @example
58
+ # Money.us_dollar(0).format(:display_free => true) #=> "free"
59
+ # Money.us_dollar(0).format(:display_free => "gratis") #=> "gratis"
60
+ # Money.us_dollar(0).format #=> "$0.00"
61
+ #
62
+ # @option *rules [Boolean] :with_currency (false) Whether the currency name
63
+ # should be appended to the result string.
64
+ #
65
+ # @example
66
+ # Money.ca_dollar(100).format => "$1.00"
67
+ # Money.ca_dollar(100).format(:with_currency => true) #=> "$1.00 CAD"
68
+ # Money.us_dollar(85).format(:with_currency => true) #=> "$0.85 USD"
69
+ #
70
+ # @option *rules [Boolean] :no_cents (false) Whether cents should be omitted.
71
+ #
72
+ # @example
73
+ # Money.ca_dollar(100).format(:no_cents => true) #=> "$1"
74
+ # Money.ca_dollar(599).format(:no_cents => true) #=> "$5"
75
+ #
76
+ # @option *rules [Boolean] :no_cents_if_whole (false) Whether cents should be
77
+ # omitted if the cent value is zero
78
+ #
79
+ # @example
80
+ # Money.ca_dollar(10000).format(:no_cents_if_whole => true) #=> "$100"
81
+ # Money.ca_dollar(10034).format(:no_cents_if_whole => true) #=> "$100.34"
82
+ #
83
+ # @option *rules [Boolean, String, nil] :symbol (true) Whether a money symbol
84
+ # should be prepended to the result string. The default is true. This method
85
+ # attempts to pick a symbol that's suitable for the given currency.
86
+ #
87
+ # @example
88
+ # Money.new(100, "USD") #=> "$1.00"
89
+ # Money.new(100, "GBP") #=> "£1.00"
90
+ # Money.new(100, "EUR") #=> "€1.00"
91
+ #
92
+ # # Same thing.
93
+ # Money.new(100, "USD").format(:symbol => true) #=> "$1.00"
94
+ # Money.new(100, "GBP").format(:symbol => true) #=> "£1.00"
95
+ # Money.new(100, "EUR").format(:symbol => true) #=> "€1.00"
96
+ #
97
+ # # You can specify a false expression or an empty string to disable
98
+ # # prepending a money symbol.§
99
+ # Money.new(100, "USD").format(:symbol => false) #=> "1.00"
100
+ # Money.new(100, "GBP").format(:symbol => nil) #=> "1.00"
101
+ # Money.new(100, "EUR").format(:symbol => "") #=> "1.00"
102
+ #
103
+ # # If the symbol for the given currency isn't known, then it will default
104
+ # # to "¤" as symbol.
105
+ # Money.new(100, "AWG").format(:symbol => true) #=> "¤1.00"
106
+ #
107
+ # # You can specify a string as value to enforce using a particular symbol.
108
+ # Money.new(100, "AWG").format(:symbol => "ƒ") #=> "ƒ1.00"
109
+ #
110
+ # @option *rules [Boolean, String, nil] :decimal_mark (true) Whether the
111
+ # currency should be separated by the specified character or '.'
112
+ #
113
+ # @example
114
+ # # If a string is specified, it's value is used.
115
+ # Money.new(100, "USD").format(:decimal_mark => ",") #=> "$1,00"
116
+ #
117
+ # # If the decimal_mark for a given currency isn't known, then it will default
118
+ # # to "." as decimal_mark.
119
+ # Money.new(100, "FOO").format #=> "$1.00"
120
+ #
121
+ # @option *rules [Boolean, String, nil] :thousands_separator (true) Whether
122
+ # the currency should be delimited by the specified character or ','
123
+ #
124
+ # @example
125
+ # # If false is specified, no thousands_separator is used.
126
+ # Money.new(100000, "USD").format(:thousands_separator => false) #=> "1000.00"
127
+ # Money.new(100000, "USD").format(:thousands_separator => nil) #=> "1000.00"
128
+ # Money.new(100000, "USD").format(:thousands_separator => "") #=> "1000.00"
129
+ #
130
+ # # If a string is specified, it's value is used.
131
+ # Money.new(100000, "USD").format(:thousands_separator => ".") #=> "$1.000.00"
132
+ #
133
+ # # If the thousands_separator for a given currency isn't known, then it will
134
+ # # default to "," as thousands_separator.
135
+ # Money.new(100000, "FOO").format #=> "$1,000.00"
136
+ #
137
+ # @option *rules [Boolean] :html (false) Whether the currency should be
138
+ # HTML-formatted. Only useful in combination with +:with_currency+.
139
+ #
140
+ # @example
141
+ # s = Money.ca_dollar(570).format(:html => true, :with_currency => true)
142
+ # s #=> "$5.70 <span class=\"currency\">CAD</span>"
143
+ def format(*rules)
144
+ # support for old format parameters
145
+ rules = normalize_formatting_rules(rules)
146
+ rules = localize_formatting_rules(rules)
147
+
148
+ if cents == 0
149
+ if rules[:display_free].respond_to?(:to_str)
150
+ return rules[:display_free]
151
+ elsif rules[:display_free]
152
+ return "free"
153
+ end
154
+ end
155
+
156
+ symbol_value =
157
+ if rules.has_key?(:symbol)
158
+ if rules[:symbol] === true
159
+ symbol
160
+ elsif rules[:symbol]
161
+ rules[:symbol]
162
+ else
163
+ ""
164
+ end
165
+ elsif rules[:html]
166
+ currency.html_entity
167
+ else
168
+ symbol
169
+ end
170
+
171
+ formatted = case rules[:no_cents]
172
+ when true
173
+ "#{self.to_s.to_i}"
174
+ else
175
+ "#{self.to_s}"
176
+ end
177
+
178
+ if rules[:no_cents_if_whole] && cents % currency.subunit_to_unit == 0
179
+ formatted = "#{self.to_s.to_i}"
180
+ end
181
+
182
+ symbol_position =
183
+ if rules.has_key?(:symbol_position)
184
+ rules[:symbol_position]
185
+ elsif currency.symbol_first?
186
+ :before
187
+ else
188
+ :after
189
+ end
190
+
191
+ if symbol_value && !symbol_value.empty?
192
+ formatted = if symbol_position == :before
193
+ "#{symbol_value}#{formatted}"
194
+ else
195
+ symbol_space = rules[:symbol_after_without_space] ? "" : " "
196
+ "#{formatted}#{symbol_space}#{symbol_value}"
197
+ end
198
+ end
199
+
200
+ if rules.has_key?(:decimal_mark) and rules[:decimal_mark] and
201
+ rules[:decimal_mark] != decimal_mark
202
+ formatted.sub!(decimal_mark, rules[:decimal_mark])
203
+ end
204
+
205
+ thousands_separator_value = thousands_separator
206
+ # Determine thousands_separator
207
+ if rules.has_key?(:thousands_separator)
208
+ if rules[:thousands_separator] === false or rules[:thousands_separator].nil?
209
+ thousands_separator_value = ""
210
+ elsif rules[:thousands_separator]
211
+ thousands_separator_value = rules[:thousands_separator]
212
+ end
213
+ end
214
+
215
+ # Apply thousands_separator
216
+ formatted.gsub!(/(\d)(?=(?:\d{3})+(?:[^\d]|$))/, "\\1#{thousands_separator_value}")
217
+
218
+ if rules[:with_currency]
219
+ formatted << " "
220
+ formatted << '<span class="currency">' if rules[:html]
221
+ formatted << currency.to_s
222
+ formatted << '</span>' if rules[:html]
223
+ end
224
+ formatted
225
+ end
226
+
227
+
228
+ private
229
+
230
+ # Cleans up formatting rules.
231
+ #
232
+ # @param [Hash]
233
+ #
234
+ # @return [Hash]
235
+ def normalize_formatting_rules(rules)
236
+ if rules.size == 0
237
+ rules = {}
238
+ elsif rules.size == 1
239
+ rules = rules.pop
240
+ rules = { rules => true } if rules.is_a?(Symbol)
241
+ end
242
+ if not rules.include?(:decimal_mark) and rules.include?(:separator)
243
+ rules[:decimal_mark] = rules[:separator]
244
+ end
245
+ if not rules.include?(:thousands_separator) and rules.include?(:delimiter)
246
+ rules[:thousands_separator] = rules[:delimiter]
247
+ end
248
+ rules
249
+ end
250
+ end
251
+
252
+ def localize_formatting_rules(rules)
253
+ if currency.iso_code == "JPY" && I18n.locale == :ja
254
+ rules[:symbol] = "円"
255
+ rules[:symbol_position] = :after
256
+ rules[:symbol_after_without_space] = true
257
+ end
258
+ rules
259
+ end
260
+ end