activesupport 4.0.13 → 4.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +283 -508
- data/README.rdoc +1 -1
- data/lib/active_support.rb +7 -1
- data/lib/active_support/backtrace_cleaner.rb +5 -5
- data/lib/active_support/benchmarkable.rb +0 -10
- data/lib/active_support/cache.rb +62 -26
- data/lib/active_support/cache/file_store.rb +27 -22
- data/lib/active_support/cache/mem_cache_store.rb +2 -2
- data/lib/active_support/cache/memory_store.rb +1 -0
- data/lib/active_support/cache/strategy/local_cache.rb +3 -0
- data/lib/active_support/callbacks.rb +416 -245
- data/lib/active_support/concern.rb +13 -5
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/array/access.rb +2 -0
- data/lib/active_support/core_ext/array/conversions.rb +2 -17
- data/lib/active_support/core_ext/array/grouping.rb +24 -12
- data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -2
- data/lib/active_support/core_ext/class.rb +0 -1
- data/lib/active_support/core_ext/class/attribute.rb +1 -2
- data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
- data/lib/active_support/core_ext/date/calculations.rb +10 -0
- data/lib/active_support/core_ext/date/conversions.rb +5 -6
- data/lib/active_support/core_ext/date/zones.rb +2 -33
- data/lib/active_support/core_ext/date_and_time/calculations.rb +30 -11
- data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +12 -25
- data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
- data/lib/active_support/core_ext/date_time/zones.rb +3 -21
- data/lib/active_support/core_ext/hash.rb +0 -1
- data/lib/active_support/core_ext/hash/conversions.rb +6 -3
- data/lib/active_support/core_ext/hash/deep_merge.rb +11 -22
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -0
- data/lib/active_support/core_ext/hash/keys.rb +27 -47
- data/lib/active_support/core_ext/kernel/reporting.rb +2 -6
- data/lib/active_support/core_ext/module.rb +1 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +160 -14
- data/lib/active_support/core_ext/module/concerning.rb +135 -0
- data/lib/active_support/core_ext/module/delegation.rb +14 -4
- data/lib/active_support/core_ext/module/deprecation.rb +0 -2
- data/lib/active_support/core_ext/module/introspection.rb +0 -16
- data/lib/active_support/core_ext/module/method_transplanting.rb +11 -0
- data/lib/active_support/core_ext/numeric/time.rb +8 -0
- data/lib/active_support/core_ext/object.rb +1 -1
- data/lib/active_support/core_ext/object/blank.rb +1 -1
- data/lib/active_support/core_ext/object/deep_dup.rb +6 -6
- data/lib/active_support/core_ext/object/inclusion.rb +4 -15
- data/lib/active_support/core_ext/object/json.rb +197 -0
- data/lib/active_support/core_ext/object/to_json.rb +4 -26
- data/lib/active_support/core_ext/object/to_param.rb +58 -1
- data/lib/active_support/core_ext/object/to_query.rb +7 -56
- data/lib/active_support/core_ext/object/try.rb +1 -1
- data/lib/active_support/core_ext/range/each.rb +2 -1
- data/lib/active_support/core_ext/string/access.rb +31 -31
- data/lib/active_support/core_ext/string/conversions.rb +9 -8
- data/lib/active_support/core_ext/string/exclude.rb +3 -3
- data/lib/active_support/core_ext/string/filters.rb +14 -4
- data/lib/active_support/core_ext/string/inflections.rb +11 -9
- data/lib/active_support/core_ext/string/output_safety.rb +65 -24
- data/lib/active_support/core_ext/string/zones.rb +1 -0
- data/lib/active_support/core_ext/thread.rb +4 -4
- data/lib/active_support/core_ext/time/calculations.rb +10 -57
- data/lib/active_support/core_ext/time/conversions.rb +3 -1
- data/lib/active_support/core_ext/time/zones.rb +2 -21
- data/lib/active_support/dependencies.rb +29 -13
- data/lib/active_support/deprecation.rb +4 -4
- data/lib/active_support/deprecation/behaviors.rb +3 -3
- data/lib/active_support/duration.rb +5 -7
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/hash_with_indifferent_access.rb +4 -9
- data/lib/active_support/i18n.rb +4 -4
- data/lib/active_support/i18n_railtie.rb +2 -6
- data/lib/active_support/inflections.rb +0 -1
- data/lib/active_support/inflector/inflections.rb +17 -17
- data/lib/active_support/inflector/methods.rb +34 -17
- data/lib/active_support/json/decoding.rb +14 -21
- data/lib/active_support/json/encoding.rb +113 -285
- data/lib/active_support/key_generator.rb +1 -1
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber/test_helper.rb +1 -1
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/message_encryptor.rb +3 -3
- data/lib/active_support/message_verifier.rb +6 -1
- data/lib/active_support/multibyte/chars.rb +1 -2
- data/lib/active_support/multibyte/unicode.rb +27 -39
- data/lib/active_support/notifications.rb +3 -3
- data/lib/active_support/notifications/instrumenter.rb +2 -1
- data/lib/active_support/number_helper.rb +20 -311
- data/lib/active_support/number_helper/number_converter.rb +182 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +21 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +66 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +58 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +49 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +62 -0
- data/lib/active_support/option_merger.rb +1 -1
- data/lib/active_support/ordered_hash.rb +0 -8
- data/lib/active_support/ordered_options.rb +8 -0
- data/lib/active_support/per_thread_registry.rb +9 -8
- data/lib/active_support/subscriber.rb +26 -3
- data/lib/active_support/test_case.rb +9 -10
- data/lib/active_support/testing/assertions.rb +0 -30
- data/lib/active_support/testing/autorun.rb +2 -2
- data/lib/active_support/testing/declarative.rb +18 -8
- data/lib/active_support/testing/isolation.rb +13 -65
- data/lib/active_support/testing/setup_and_teardown.rb +17 -2
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +55 -0
- data/lib/active_support/time_with_zone.rb +4 -4
- data/lib/active_support/values/time_zone.rb +18 -15
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini.rb +2 -4
- metadata +71 -61
- data/lib/active_support/basic_object.rb +0 -11
- data/lib/active_support/buffered_logger.rb +0 -21
- data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
- data/lib/active_support/core_ext/hash/diff.rb +0 -14
- data/lib/active_support/core_ext/logger.rb +0 -67
- data/lib/active_support/core_ext/proc.rb +0 -17
- data/lib/active_support/core_ext/string/encoding.rb +0 -8
- data/lib/active_support/json/variable.rb +0 -18
- data/lib/active_support/testing/pending.rb +0 -14
@@ -4,7 +4,7 @@ require 'openssl'
|
|
4
4
|
module ActiveSupport
|
5
5
|
# KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2
|
6
6
|
# It can be used to derive a number of keys for various purposes from a given secret.
|
7
|
-
# This lets
|
7
|
+
# This lets Rails applications have a single secure secret, but avoid reusing that
|
8
8
|
# key in multiple incompatible contexts.
|
9
9
|
class KeyGenerator
|
10
10
|
def initialize(secret, options = {})
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module ActiveSupport
|
2
|
-
# lazy_load_hooks allows
|
2
|
+
# lazy_load_hooks allows Rails to lazily load a lot of components and thus
|
3
3
|
# making the app boot faster. Because of this feature now there is no need to
|
4
4
|
# require <tt>ActiveRecord::Base</tt> at boot time purely to apply
|
5
5
|
# configuration. Instead a hook is registered that applies configuration once
|
@@ -76,12 +76,12 @@ module ActiveSupport
|
|
76
76
|
encrypted_data = cipher.update(@serializer.dump(value))
|
77
77
|
encrypted_data << cipher.final
|
78
78
|
|
79
|
-
|
79
|
+
"#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
|
80
80
|
end
|
81
81
|
|
82
82
|
def _decrypt(encrypted_message)
|
83
83
|
cipher = new_cipher
|
84
|
-
encrypted_data, iv = encrypted_message.split("--").map {|v| ::Base64.
|
84
|
+
encrypted_data, iv = encrypted_message.split("--").map {|v| ::Base64.strict_decode64(v)}
|
85
85
|
|
86
86
|
cipher.decrypt
|
87
87
|
cipher.key = @secret
|
@@ -91,7 +91,7 @@ module ActiveSupport
|
|
91
91
|
decrypted_data << cipher.final
|
92
92
|
|
93
93
|
@serializer.load(decrypted_data)
|
94
|
-
rescue OpenSSLCipherError, TypeError
|
94
|
+
rescue OpenSSLCipherError, TypeError, ArgumentError
|
95
95
|
raise InvalidMessage
|
96
96
|
end
|
97
97
|
|
@@ -37,7 +37,12 @@ module ActiveSupport
|
|
37
37
|
|
38
38
|
data, digest = signed_message.split("--")
|
39
39
|
if data.present? && digest.present? && secure_compare(digest, generate_digest(data))
|
40
|
-
|
40
|
+
begin
|
41
|
+
@serializer.load(::Base64.strict_decode64(data))
|
42
|
+
rescue ArgumentError => argument_error
|
43
|
+
raise InvalidSignature if argument_error.message =~ %r{invalid base64}
|
44
|
+
raise
|
45
|
+
end
|
41
46
|
else
|
42
47
|
raise InvalidSignature
|
43
48
|
end
|
@@ -56,11 +56,10 @@ module ActiveSupport #:nodoc:
|
|
56
56
|
|
57
57
|
# Forward all undefined methods to the wrapped string.
|
58
58
|
def method_missing(method, *args, &block)
|
59
|
+
result = @wrapped_string.__send__(method, *args, &block)
|
59
60
|
if method.to_s =~ /!$/
|
60
|
-
result = @wrapped_string.__send__(method, *args, &block)
|
61
61
|
self if result
|
62
62
|
else
|
63
|
-
result = @wrapped_string.__send__(method, *args, &block)
|
64
63
|
result.kind_of?(String) ? chars(result) : result
|
65
64
|
end
|
66
65
|
end
|
@@ -42,6 +42,7 @@ module ActiveSupport
|
|
42
42
|
0x0085, # White_Space # Cc <control-0085>
|
43
43
|
0x00A0, # White_Space # Zs NO-BREAK SPACE
|
44
44
|
0x1680, # White_Space # Zs OGHAM SPACE MARK
|
45
|
+
0x180E, # White_Space # Zs MONGOLIAN VOWEL SEPARATOR
|
45
46
|
(0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE
|
46
47
|
0x2028, # White_Space # Zl LINE SEPARATOR
|
47
48
|
0x2029, # White_Space # Zp PARAGRAPH SEPARATOR
|
@@ -217,51 +218,31 @@ module ActiveSupport
|
|
217
218
|
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
|
218
219
|
# encoding is entirely CP1252 or ISO-8859-1.
|
219
220
|
def tidy_bytes(string, force = false)
|
221
|
+
return string if string.empty?
|
222
|
+
|
220
223
|
if force
|
221
|
-
return string.
|
222
|
-
tidy_byte(b)
|
223
|
-
end.flatten.compact.pack("C*").unpack("U*").pack("U*")
|
224
|
+
return string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
|
224
225
|
end
|
225
226
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
227
|
+
# We can't transcode to the same format, so we choose a nearly-identical encoding.
|
228
|
+
# We're going to 'transcode' bytes from UTF-8 when possible, then fall back to
|
229
|
+
# CP1252 when we get errors. The final string will be 'converted' back to UTF-8
|
230
|
+
# before returning.
|
231
|
+
reader = Encoding::Converter.new(Encoding::UTF_8, Encoding::UTF_8_MAC)
|
231
232
|
|
232
|
-
|
233
|
-
|
234
|
-
is_lead = byte > 191 && byte < 245
|
235
|
-
is_unused = byte > 240
|
236
|
-
is_restricted = byte > 244
|
233
|
+
source = string.dup
|
234
|
+
out = ''.force_encoding(Encoding::UTF_8_MAC)
|
237
235
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
conts_expected == 0 ? bytes[i] = tidy_byte(byte) : conts_expected -= 1
|
244
|
-
else
|
245
|
-
if conts_expected > 0
|
246
|
-
# Expected continuation, but got ASCII or leading? Clean backwards up to
|
247
|
-
# the leading byte.
|
248
|
-
(1..(i - last_lead)).each {|j| bytes[i - j] = tidy_byte(bytes[i - j])}
|
249
|
-
conts_expected = 0
|
250
|
-
end
|
251
|
-
if is_lead
|
252
|
-
# Final byte is leading? Clean it.
|
253
|
-
if i == bytes.length - 1
|
254
|
-
bytes[i] = tidy_byte(bytes.last)
|
255
|
-
else
|
256
|
-
# Valid leading byte? Expect continuations determined by position of
|
257
|
-
# first zero bit, with max of 3.
|
258
|
-
conts_expected = byte < 224 ? 1 : byte < 240 ? 2 : 3
|
259
|
-
last_lead = i
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
236
|
+
loop do
|
237
|
+
reader.primitive_convert(source, out)
|
238
|
+
_, _, _, error_bytes, _ = reader.primitive_errinfo
|
239
|
+
break if error_bytes.nil?
|
240
|
+
out << error_bytes.encode(Encoding::UTF_8_MAC, Encoding::Windows_1252, invalid: :replace, undef: :replace)
|
263
241
|
end
|
264
|
-
|
242
|
+
|
243
|
+
reader.finish
|
244
|
+
|
245
|
+
out.encode!(Encoding::UTF_8)
|
265
246
|
end
|
266
247
|
|
267
248
|
# Returns the KC normalization of the string by default. NFKC is
|
@@ -306,6 +287,13 @@ module ActiveSupport
|
|
306
287
|
class Codepoint
|
307
288
|
attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
|
308
289
|
|
290
|
+
# Initializing Codepoint object with default values
|
291
|
+
def initialize
|
292
|
+
@combining_class = 0
|
293
|
+
@uppercase_mapping = 0
|
294
|
+
@lowercase_mapping = 0
|
295
|
+
end
|
296
|
+
|
309
297
|
def swapcase_mapping
|
310
298
|
uppercase_mapping > 0 ? uppercase_mapping : lowercase_mapping
|
311
299
|
end
|
@@ -143,8 +143,8 @@ module ActiveSupport
|
|
143
143
|
#
|
144
144
|
# == Default Queue
|
145
145
|
#
|
146
|
-
# Notifications ships with a queue implementation that consumes and
|
147
|
-
# to log subscribers
|
146
|
+
# Notifications ships with a queue implementation that consumes and publishes events
|
147
|
+
# to all log subscribers. You can use any queue implementation you want.
|
148
148
|
#
|
149
149
|
module Notifications
|
150
150
|
class << self
|
@@ -178,7 +178,7 @@ module ActiveSupport
|
|
178
178
|
end
|
179
179
|
|
180
180
|
def instrumenter
|
181
|
-
InstrumentationRegistry.instrumenter_for(notifier)
|
181
|
+
InstrumentationRegistry.instance.instrumenter_for(notifier)
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
@@ -1,115 +1,19 @@
|
|
1
|
-
require 'active_support/core_ext/big_decimal/conversions'
|
2
|
-
require 'active_support/core_ext/object/blank'
|
3
|
-
require 'active_support/core_ext/hash/keys'
|
4
|
-
require 'active_support/i18n'
|
5
|
-
|
6
1
|
module ActiveSupport
|
7
2
|
module NumberHelper
|
8
|
-
extend
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# If set to true, precision will mean the number of significant digits instead
|
21
|
-
# of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
|
22
|
-
significant: false,
|
23
|
-
# If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2)
|
24
|
-
strip_insignificant_zeros: false
|
25
|
-
},
|
26
|
-
|
27
|
-
# Used in number_to_currency
|
28
|
-
currency: {
|
29
|
-
format: {
|
30
|
-
format: "%u%n",
|
31
|
-
negative_format: "-%u%n",
|
32
|
-
unit: "$",
|
33
|
-
# These five are to override number.format and are optional
|
34
|
-
separator: ".",
|
35
|
-
delimiter: ",",
|
36
|
-
precision: 2,
|
37
|
-
significant: false,
|
38
|
-
strip_insignificant_zeros: false
|
39
|
-
}
|
40
|
-
},
|
41
|
-
|
42
|
-
# Used in number_to_percentage
|
43
|
-
percentage: {
|
44
|
-
format: {
|
45
|
-
delimiter: "",
|
46
|
-
format: "%n%"
|
47
|
-
}
|
48
|
-
},
|
49
|
-
|
50
|
-
# Used in number_to_rounded
|
51
|
-
precision: {
|
52
|
-
format: {
|
53
|
-
delimiter: ""
|
54
|
-
}
|
55
|
-
},
|
56
|
-
|
57
|
-
# Used in number_to_human_size and number_to_human
|
58
|
-
human: {
|
59
|
-
format: {
|
60
|
-
# These five are to override number.format and are optional
|
61
|
-
delimiter: "",
|
62
|
-
precision: 3,
|
63
|
-
significant: true,
|
64
|
-
strip_insignificant_zeros: true
|
65
|
-
},
|
66
|
-
# Used in number_to_human_size
|
67
|
-
storage_units: {
|
68
|
-
# Storage units output formatting.
|
69
|
-
# %u is the storage unit, %n is the number (default: 2 MB)
|
70
|
-
format: "%n %u",
|
71
|
-
units: {
|
72
|
-
byte: "Bytes",
|
73
|
-
kb: "KB",
|
74
|
-
mb: "MB",
|
75
|
-
gb: "GB",
|
76
|
-
tb: "TB"
|
77
|
-
}
|
78
|
-
},
|
79
|
-
# Used in number_to_human
|
80
|
-
decimal_units: {
|
81
|
-
format: "%n %u",
|
82
|
-
# Decimal units output formatting
|
83
|
-
# By default we will only quantify some of the exponents
|
84
|
-
# but the commented ones might be defined or overridden
|
85
|
-
# by the user.
|
86
|
-
units: {
|
87
|
-
# femto: Quadrillionth
|
88
|
-
# pico: Trillionth
|
89
|
-
# nano: Billionth
|
90
|
-
# micro: Millionth
|
91
|
-
# mili: Thousandth
|
92
|
-
# centi: Hundredth
|
93
|
-
# deci: Tenth
|
94
|
-
unit: "",
|
95
|
-
# ten:
|
96
|
-
# one: Ten
|
97
|
-
# other: Tens
|
98
|
-
# hundred: Hundred
|
99
|
-
thousand: "Thousand",
|
100
|
-
million: "Million",
|
101
|
-
billion: "Billion",
|
102
|
-
trillion: "Trillion",
|
103
|
-
quadrillion: "Quadrillion"
|
104
|
-
}
|
105
|
-
}
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
DECIMAL_UNITS = { 0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
|
110
|
-
-1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto }
|
3
|
+
extend ActiveSupport::Autoload
|
4
|
+
|
5
|
+
eager_autoload do
|
6
|
+
autoload :NumberConverter
|
7
|
+
autoload :NumberToRoundedConverter
|
8
|
+
autoload :NumberToDelimitedConverter
|
9
|
+
autoload :NumberToHumanConverter
|
10
|
+
autoload :NumberToHumanSizeConverter
|
11
|
+
autoload :NumberToPhoneConverter
|
12
|
+
autoload :NumberToCurrencyConverter
|
13
|
+
autoload :NumberToPercentageConverter
|
14
|
+
end
|
111
15
|
|
112
|
-
|
16
|
+
extend self
|
113
17
|
|
114
18
|
# Formats a +number+ into a US phone number (e.g., (555)
|
115
19
|
# 123-9876). You can customize the format in the +options+ hash.
|
@@ -137,27 +41,7 @@ module ActiveSupport
|
|
137
41
|
# number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: '.')
|
138
42
|
# # => +1.123.555.1234 x 1343
|
139
43
|
def number_to_phone(number, options = {})
|
140
|
-
|
141
|
-
options = options.symbolize_keys
|
142
|
-
|
143
|
-
number = number.to_s.strip
|
144
|
-
area_code = options[:area_code]
|
145
|
-
delimiter = options[:delimiter] || "-"
|
146
|
-
extension = options[:extension]
|
147
|
-
country_code = options[:country_code]
|
148
|
-
|
149
|
-
if area_code
|
150
|
-
number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
|
151
|
-
else
|
152
|
-
number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
|
153
|
-
number.slice!(0, 1) if number.start_with?(delimiter) && !delimiter.blank?
|
154
|
-
end
|
155
|
-
|
156
|
-
str = ''
|
157
|
-
str << "+#{country_code}#{delimiter}" unless country_code.blank?
|
158
|
-
str << number
|
159
|
-
str << " x #{extension}" unless extension.blank?
|
160
|
-
str
|
44
|
+
NumberToPhoneConverter.convert(number, options)
|
161
45
|
end
|
162
46
|
|
163
47
|
# Formats a +number+ into a currency string (e.g., $13.65). You
|
@@ -199,25 +83,7 @@ module ActiveSupport
|
|
199
83
|
# number_to_currency(1234567890.50, unit: '£', separator: ',', delimiter: '', format: '%n %u')
|
200
84
|
# # => 1234567890,50 £
|
201
85
|
def number_to_currency(number, options = {})
|
202
|
-
|
203
|
-
options = options.symbolize_keys
|
204
|
-
|
205
|
-
currency = i18n_format_options(options[:locale], :currency)
|
206
|
-
currency[:negative_format] ||= "-" + currency[:format] if currency[:format]
|
207
|
-
|
208
|
-
defaults = default_format_options(:currency).merge!(currency)
|
209
|
-
defaults[:negative_format] = "-" + options[:format] if options[:format]
|
210
|
-
options = defaults.merge!(options)
|
211
|
-
|
212
|
-
unit = options.delete(:unit)
|
213
|
-
format = options.delete(:format)
|
214
|
-
|
215
|
-
if number.to_f.phase != 0
|
216
|
-
format = options.delete(:negative_format)
|
217
|
-
number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '')
|
218
|
-
end
|
219
|
-
|
220
|
-
format.gsub('%n', self.number_to_rounded(number, options)).gsub('%u', unit)
|
86
|
+
NumberToCurrencyConverter.convert(number, options)
|
221
87
|
end
|
222
88
|
|
223
89
|
# Formats a +number+ as a percentage string (e.g., 65%). You can
|
@@ -253,14 +119,7 @@ module ActiveSupport
|
|
253
119
|
# number_to_percentage('98a') # => 98a%
|
254
120
|
# number_to_percentage(100, format: '%n %') # => 100 %
|
255
121
|
def number_to_percentage(number, options = {})
|
256
|
-
|
257
|
-
options = options.symbolize_keys
|
258
|
-
|
259
|
-
defaults = format_options(options[:locale], :percentage)
|
260
|
-
options = defaults.merge!(options)
|
261
|
-
|
262
|
-
format = options[:format] || "%n%"
|
263
|
-
format.gsub('%n', self.number_to_rounded(number, options))
|
122
|
+
NumberToPercentageConverter.convert(number, options)
|
264
123
|
end
|
265
124
|
|
266
125
|
# Formats a +number+ with grouped thousands using +delimiter+
|
@@ -289,15 +148,7 @@ module ActiveSupport
|
|
289
148
|
# number_to_delimited(98765432.98, delimiter: ' ', separator: ',')
|
290
149
|
# # => 98 765 432,98
|
291
150
|
def number_to_delimited(number, options = {})
|
292
|
-
|
293
|
-
|
294
|
-
return number unless valid_float?(number)
|
295
|
-
|
296
|
-
options = format_options(options[:locale]).merge!(options)
|
297
|
-
|
298
|
-
parts = number.to_s.split('.')
|
299
|
-
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
|
300
|
-
parts.join(options[:separator])
|
151
|
+
NumberToDelimitedConverter.convert(number, options)
|
301
152
|
end
|
302
153
|
|
303
154
|
# Formats a +number+ with the specified level of
|
@@ -340,39 +191,7 @@ module ActiveSupport
|
|
340
191
|
# number_to_rounded(1111.2345, precision: 2, separator: ',', delimiter: '.')
|
341
192
|
# # => 1.111,23
|
342
193
|
def number_to_rounded(number, options = {})
|
343
|
-
|
344
|
-
number = Float(number)
|
345
|
-
options = options.symbolize_keys
|
346
|
-
|
347
|
-
defaults = format_options(options[:locale], :precision)
|
348
|
-
options = defaults.merge!(options)
|
349
|
-
|
350
|
-
precision = options.delete :precision
|
351
|
-
significant = options.delete :significant
|
352
|
-
strip_insignificant_zeros = options.delete :strip_insignificant_zeros
|
353
|
-
|
354
|
-
if significant && precision > 0
|
355
|
-
if number == 0
|
356
|
-
digits, rounded_number = 1, 0
|
357
|
-
else
|
358
|
-
digits = (Math.log10(number.abs) + 1).floor
|
359
|
-
multiplier = 10 ** (digits - precision)
|
360
|
-
rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new(multiplier.to_f.to_s)).round.to_f * multiplier
|
361
|
-
digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
|
362
|
-
end
|
363
|
-
precision -= digits
|
364
|
-
precision = 0 if precision < 0 # don't let it be negative
|
365
|
-
else
|
366
|
-
rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
|
367
|
-
rounded_number = rounded_number.abs if rounded_number.zero? # prevent showing negative zeros
|
368
|
-
end
|
369
|
-
formatted_number = self.number_to_delimited("%01.#{precision}f" % rounded_number, options)
|
370
|
-
if strip_insignificant_zeros
|
371
|
-
escaped_separator = Regexp.escape(options[:separator])
|
372
|
-
formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
|
373
|
-
else
|
374
|
-
formatted_number
|
375
|
-
end
|
194
|
+
NumberToRoundedConverter.convert(number, options)
|
376
195
|
end
|
377
196
|
|
378
197
|
# Formats the bytes in +number+ into a more understandable
|
@@ -420,36 +239,7 @@ module ActiveSupport
|
|
420
239
|
# number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB"
|
421
240
|
# number_to_human_size(524288000, precision: 5) # => "500 MB"
|
422
241
|
def number_to_human_size(number, options = {})
|
423
|
-
|
424
|
-
|
425
|
-
return number unless valid_float?(number)
|
426
|
-
number = Float(number)
|
427
|
-
|
428
|
-
defaults = format_options(options[:locale], :human)
|
429
|
-
options = defaults.merge!(options)
|
430
|
-
|
431
|
-
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
|
432
|
-
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
|
433
|
-
|
434
|
-
storage_units_format = translate_number_value_with_default('human.storage_units.format', :locale => options[:locale], :raise => true)
|
435
|
-
|
436
|
-
base = options[:prefix] == :si ? 1000 : 1024
|
437
|
-
|
438
|
-
if number.to_i < base
|
439
|
-
unit = translate_number_value_with_default('human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
|
440
|
-
storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
|
441
|
-
else
|
442
|
-
max_exp = STORAGE_UNITS.size - 1
|
443
|
-
exponent = (Math.log(number) / Math.log(base)).to_i # Convert to base
|
444
|
-
exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
|
445
|
-
number /= base ** exponent
|
446
|
-
|
447
|
-
unit_key = STORAGE_UNITS[exponent]
|
448
|
-
unit = translate_number_value_with_default("human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
|
449
|
-
|
450
|
-
formatted_number = self.number_to_rounded(number, options)
|
451
|
-
storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
|
452
|
-
end
|
242
|
+
NumberToHumanSizeConverter.convert(number, options)
|
453
243
|
end
|
454
244
|
|
455
245
|
# Pretty prints (formats and approximates) a number in a way it
|
@@ -550,88 +340,7 @@ module ActiveSupport
|
|
550
340
|
# number_to_human(1, units: :distance) # => "1 meter"
|
551
341
|
# number_to_human(0.34, units: :distance) # => "34 centimeters"
|
552
342
|
def number_to_human(number, options = {})
|
553
|
-
|
554
|
-
|
555
|
-
return number unless valid_float?(number)
|
556
|
-
number = Float(number)
|
557
|
-
|
558
|
-
defaults = format_options(options[:locale], :human)
|
559
|
-
options = defaults.merge!(options)
|
560
|
-
|
561
|
-
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
|
562
|
-
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
|
563
|
-
|
564
|
-
inverted_du = DECIMAL_UNITS.invert
|
565
|
-
|
566
|
-
units = options.delete :units
|
567
|
-
unit_exponents = case units
|
568
|
-
when Hash
|
569
|
-
units
|
570
|
-
when String, Symbol
|
571
|
-
I18n.translate(:"#{units}", :locale => options[:locale], :raise => true)
|
572
|
-
when nil
|
573
|
-
translate_number_value_with_default("human.decimal_units.units", :locale => options[:locale], :raise => true)
|
574
|
-
else
|
575
|
-
raise ArgumentError, ":units must be a Hash or String translation scope."
|
576
|
-
end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e}
|
577
|
-
|
578
|
-
number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
|
579
|
-
display_exponent = unit_exponents.find{ |e| number_exponent >= e } || 0
|
580
|
-
number /= 10 ** display_exponent
|
581
|
-
|
582
|
-
unit = case units
|
583
|
-
when Hash
|
584
|
-
units[DECIMAL_UNITS[display_exponent]] || ''
|
585
|
-
when String, Symbol
|
586
|
-
I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
|
587
|
-
else
|
588
|
-
translate_number_value_with_default("human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
|
589
|
-
end
|
590
|
-
|
591
|
-
decimal_format = options[:format] || translate_number_value_with_default('human.decimal_units.format', :locale => options[:locale])
|
592
|
-
formatted_number = self.number_to_rounded(number, options)
|
593
|
-
decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip
|
594
|
-
end
|
595
|
-
|
596
|
-
def self.private_module_and_instance_method(method_name) #:nodoc:
|
597
|
-
private method_name
|
598
|
-
private_class_method method_name
|
599
|
-
end
|
600
|
-
private_class_method :private_module_and_instance_method
|
601
|
-
|
602
|
-
def format_options(locale, namespace = nil) #:nodoc:
|
603
|
-
default_format_options(namespace).merge!(i18n_format_options(locale, namespace))
|
604
|
-
end
|
605
|
-
private_module_and_instance_method :format_options
|
606
|
-
|
607
|
-
def default_format_options(namespace = nil) #:nodoc:
|
608
|
-
options = DEFAULTS[:format].dup
|
609
|
-
options.merge!(DEFAULTS[namespace][:format]) if namespace
|
610
|
-
options
|
611
|
-
end
|
612
|
-
private_module_and_instance_method :default_format_options
|
613
|
-
|
614
|
-
def i18n_format_options(locale, namespace = nil) #:nodoc:
|
615
|
-
options = I18n.translate(:'number.format', locale: locale, default: {}).dup
|
616
|
-
if namespace
|
617
|
-
options.merge!(I18n.translate(:"number.#{namespace}.format", locale: locale, default: {}))
|
618
|
-
end
|
619
|
-
options
|
620
|
-
end
|
621
|
-
private_module_and_instance_method :i18n_format_options
|
622
|
-
|
623
|
-
def translate_number_value_with_default(key, i18n_options = {}) #:nodoc:
|
624
|
-
default = key.split('.').reduce(DEFAULTS) { |defaults, k| defaults[k.to_sym] }
|
625
|
-
|
626
|
-
I18n.translate(key, { default: default, scope: :number }.merge!(i18n_options))
|
627
|
-
end
|
628
|
-
private_module_and_instance_method :translate_number_value_with_default
|
629
|
-
|
630
|
-
def valid_float?(number) #:nodoc:
|
631
|
-
Float(number)
|
632
|
-
rescue ArgumentError, TypeError
|
633
|
-
false
|
343
|
+
NumberToHumanConverter.convert(number, options)
|
634
344
|
end
|
635
|
-
private_module_and_instance_method :valid_float?
|
636
345
|
end
|
637
346
|
end
|