money 3.7.1 → 4.0.0

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.
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