activesupport 4.0.13 → 4.2.11.3
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 +5 -5
- data/CHANGELOG.md +406 -418
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -2
- data/lib/active_support/backtrace_cleaner.rb +8 -8
- data/lib/active_support/benchmarkable.rb +0 -10
- data/lib/active_support/cache/file_store.rb +32 -22
- data/lib/active_support/cache/mem_cache_store.rb +5 -7
- data/lib/active_support/cache/memory_store.rb +1 -0
- data/lib/active_support/cache/strategy/local_cache.rb +11 -30
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
- data/lib/active_support/cache.rb +75 -41
- data/lib/active_support/callbacks.rb +482 -261
- data/lib/active_support/concern.rb +23 -7
- data/lib/active_support/configurable.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +11 -1
- data/lib/active_support/core_ext/array/conversions.rb +2 -17
- data/lib/active_support/core_ext/array/grouping.rb +29 -12
- data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -2
- data/lib/active_support/core_ext/array.rb +0 -1
- data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -15
- data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +16 -0
- data/lib/active_support/core_ext/class/attribute.rb +1 -2
- data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -170
- data/lib/active_support/core_ext/class/delegating_attributes.rb +13 -8
- data/lib/active_support/core_ext/class/subclasses.rb +0 -2
- data/lib/active_support/core_ext/class.rb +0 -1
- data/lib/active_support/core_ext/date/calculations.rb +10 -0
- data/lib/active_support/core_ext/date/conversions.rb +9 -1
- data/lib/active_support/core_ext/date/zones.rb +2 -33
- data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -11
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +45 -22
- data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
- data/lib/active_support/core_ext/date_time/zones.rb +3 -21
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +51 -0
- data/lib/active_support/core_ext/enumerable.rb +17 -1
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/compact.rb +24 -0
- data/lib/active_support/core_ext/hash/conversions.rb +9 -8
- data/lib/active_support/core_ext/hash/except.rb +8 -2
- data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -0
- data/lib/active_support/core_ext/hash/keys.rb +25 -19
- data/lib/active_support/core_ext/hash/slice.rb +8 -2
- data/lib/active_support/core_ext/hash/transform_values.rb +23 -0
- data/lib/active_support/core_ext/hash.rb +2 -1
- data/lib/active_support/core_ext/integer/time.rb +0 -15
- data/lib/active_support/core_ext/kernel/concern.rb +10 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +13 -2
- data/lib/active_support/core_ext/kernel.rb +3 -2
- data/lib/active_support/core_ext/load_error.rb +4 -1
- data/lib/active_support/core_ext/marshal.rb +8 -5
- data/lib/active_support/core_ext/module/aliasing.rb +2 -2
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -1
- 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 +53 -25
- 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 +13 -0
- data/lib/active_support/core_ext/module.rb +1 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
- data/lib/active_support/core_ext/numeric/time.rb +4 -29
- data/lib/active_support/core_ext/object/blank.rb +44 -18
- data/lib/active_support/core_ext/object/deep_dup.rb +6 -6
- data/lib/active_support/core_ext/object/duplicable.rb +72 -33
- data/lib/active_support/core_ext/object/inclusion.rb +16 -15
- data/lib/active_support/core_ext/object/itself.rb +15 -0
- data/lib/active_support/core_ext/object/json.rb +197 -0
- data/lib/active_support/core_ext/object/to_query.rb +14 -6
- data/lib/active_support/core_ext/object/try.rb +36 -14
- data/lib/active_support/core_ext/object/with_options.rb +30 -3
- data/lib/active_support/core_ext/object.rb +2 -1
- data/lib/active_support/core_ext/string/access.rb +35 -35
- data/lib/active_support/core_ext/string/conversions.rb +10 -9
- data/lib/active_support/core_ext/string/exclude.rb +3 -3
- data/lib/active_support/core_ext/string/filters.rb +51 -3
- data/lib/active_support/core_ext/string/inflections.rb +15 -10
- data/lib/active_support/core_ext/string/output_safety.rb +97 -33
- data/lib/active_support/core_ext/string/zones.rb +1 -0
- data/lib/active_support/core_ext/thread.rb +12 -5
- data/lib/active_support/core_ext/time/calculations.rb +47 -68
- data/lib/active_support/core_ext/time/compatibility.rb +14 -0
- data/lib/active_support/core_ext/time/conversions.rb +4 -2
- data/lib/active_support/core_ext/time/zones.rb +2 -20
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext.rb +0 -1
- data/lib/active_support/dependencies/autoload.rb +1 -1
- data/lib/active_support/dependencies.rb +64 -25
- data/lib/active_support/deprecation/behaviors.rb +4 -4
- data/lib/active_support/deprecation.rb +4 -4
- data/lib/active_support/duration.rb +55 -11
- data/lib/active_support/file_update_checker.rb +1 -1
- data/lib/active_support/gem_version.rb +15 -0
- data/lib/active_support/hash_with_indifferent_access.rb +39 -11
- data/lib/active_support/i18n.rb +4 -4
- data/lib/active_support/i18n_railtie.rb +1 -7
- data/lib/active_support/inflections.rb +6 -1
- data/lib/active_support/inflector/inflections.rb +19 -19
- data/lib/active_support/inflector/methods.rb +66 -25
- data/lib/active_support/json/decoding.rb +15 -22
- data/lib/active_support/json/encoding.rb +125 -286
- data/lib/active_support/key_generator.rb +8 -10
- 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 +51 -1
- data/lib/active_support/logger_silence.rb +7 -4
- data/lib/active_support/logger_thread_safe_level.rb +32 -0
- data/lib/active_support/message_encryptor.rb +14 -6
- data/lib/active_support/message_verifier.rb +16 -12
- data/lib/active_support/multibyte/chars.rb +2 -3
- data/lib/active_support/multibyte/unicode.rb +46 -58
- data/lib/active_support/notifications/fanout.rb +12 -7
- data/lib/active_support/notifications/instrumenter.rb +2 -1
- data/lib/active_support/notifications.rb +11 -6
- 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 +23 -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 +87 -0
- data/lib/active_support/number_helper.rb +32 -324
- data/lib/active_support/ordered_options.rb +8 -0
- data/lib/active_support/per_thread_registry.rb +13 -10
- data/lib/active_support/security_utils.rb +27 -0
- data/lib/active_support/subscriber.rb +35 -3
- data/lib/active_support/test_case.rb +52 -19
- data/lib/active_support/testing/assertions.rb +1 -31
- data/lib/active_support/testing/autorun.rb +2 -2
- data/lib/active_support/testing/constant_lookup.rb +1 -5
- data/lib/active_support/testing/declarative.rb +7 -21
- data/lib/active_support/testing/isolation.rb +29 -69
- data/lib/active_support/testing/setup_and_teardown.rb +17 -2
- data/lib/active_support/testing/tagged_logging.rb +2 -2
- data/lib/active_support/testing/time_helpers.rb +134 -0
- data/lib/active_support/time.rb +0 -2
- data/lib/active_support/time_with_zone.rb +60 -40
- data/lib/active_support/values/time_zone.rb +101 -101
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +4 -7
- data/lib/active_support/xml_mini/jdom.rb +6 -5
- data/lib/active_support/xml_mini/libxml.rb +1 -3
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
- data/lib/active_support/xml_mini/nokogiri.rb +1 -3
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
- data/lib/active_support/xml_mini/rexml.rb +7 -8
- data/lib/active_support/xml_mini.rb +33 -15
- data/lib/active_support.rb +27 -2
- metadata +43 -43
- 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/object/to_json.rb +0 -27
- 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/file_watcher.rb +0 -36
- data/lib/active_support/json/variable.rb +0 -18
- data/lib/active_support/testing/pending.rb +0 -14
@@ -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
|
@@ -413,43 +232,10 @@ module ActiveSupport
|
|
413
232
|
# number_to_human_size(1234567, precision: 2) # => 1.2 MB
|
414
233
|
# number_to_human_size(483989, precision: 2) # => 470 KB
|
415
234
|
# number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
|
416
|
-
#
|
417
|
-
#
|
418
|
-
# default (set <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
|
419
|
-
#
|
420
|
-
# number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB"
|
421
|
-
# number_to_human_size(524288000, precision: 5) # => "500 MB"
|
235
|
+
# number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
|
236
|
+
# number_to_human_size(524288000, precision: 5) # => "500 MB"
|
422
237
|
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
|
238
|
+
NumberToHumanSizeConverter.convert(number, options)
|
453
239
|
end
|
454
240
|
|
455
241
|
# Pretty prints (formats and approximates) a number in a way it
|
@@ -486,12 +272,12 @@ module ActiveSupport
|
|
486
272
|
# string containing an i18n scope where to find this hash. It
|
487
273
|
# might have the following keys:
|
488
274
|
# * *integers*: <tt>:unit</tt>, <tt>:ten</tt>,
|
489
|
-
#
|
490
|
-
#
|
491
|
-
#
|
275
|
+
# <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
|
276
|
+
# <tt>:billion</tt>, <tt>:trillion</tt>,
|
277
|
+
# <tt>:quadrillion</tt>
|
492
278
|
# * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>,
|
493
|
-
#
|
494
|
-
#
|
279
|
+
# <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
|
280
|
+
# <tt>:pico</tt>, <tt>:femto</tt>
|
495
281
|
# * <tt>:format</tt> - Sets the format of the output string
|
496
282
|
# (defaults to "%n %u"). The field types are:
|
497
283
|
# * %u - The quantifier (ex.: 'thousand')
|
@@ -515,12 +301,15 @@ module ActiveSupport
|
|
515
301
|
# separator: ',',
|
516
302
|
# significant: false) # => "1,2 Million"
|
517
303
|
#
|
304
|
+
# number_to_human(500000000, precision: 5) # => "500 Million"
|
305
|
+
# number_to_human(12345012345, significant: false) # => "12.345 Billion"
|
306
|
+
#
|
518
307
|
# Non-significant zeros after the decimal separator are stripped
|
519
308
|
# out by default (set <tt>:strip_insignificant_zeros</tt> to
|
520
309
|
# +false+ to change that):
|
521
310
|
#
|
522
|
-
#
|
523
|
-
#
|
311
|
+
# number_to_human(12.00001) # => "12"
|
312
|
+
# number_to_human(12.00001, strip_insignificant_zeros: false) # => "12.0"
|
524
313
|
#
|
525
314
|
# ==== Custom Unit Quantifiers
|
526
315
|
#
|
@@ -550,88 +339,7 @@ module ActiveSupport
|
|
550
339
|
# number_to_human(1, units: :distance) # => "1 meter"
|
551
340
|
# number_to_human(0.34, units: :distance) # => "34 centimeters"
|
552
341
|
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
|
342
|
+
NumberToHumanConverter.convert(number, options)
|
634
343
|
end
|
635
|
-
private_module_and_instance_method :valid_float?
|
636
344
|
end
|
637
345
|
end
|
@@ -40,6 +40,14 @@ module ActiveSupport
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
# +InheritableOptions+ provides a constructor to build an +OrderedOptions+
|
44
|
+
# hash inherited from another hash.
|
45
|
+
#
|
46
|
+
# Use this if you already have some hash and you want to create a new one based on it.
|
47
|
+
#
|
48
|
+
# h = ActiveSupport::InheritableOptions.new({ girl: 'Mary', boy: 'John' })
|
49
|
+
# h.girl # => 'Mary'
|
50
|
+
# h.boy # => 'John'
|
43
51
|
class InheritableOptions < OrderedOptions
|
44
52
|
def initialize(parent = nil)
|
45
53
|
if parent.kind_of?(OrderedOptions)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
4
|
# This module is used to encapsulate access to thread local variables.
|
3
5
|
#
|
@@ -32,21 +34,22 @@ module ActiveSupport
|
|
32
34
|
#
|
33
35
|
# If the class has an initializer, it must accept no arguments.
|
34
36
|
module PerThreadRegistry
|
35
|
-
|
37
|
+
def self.extended(object)
|
38
|
+
object.instance_variable_set '@per_thread_registry_key', object.name.freeze
|
39
|
+
end
|
36
40
|
|
41
|
+
def instance
|
42
|
+
Thread.current[@per_thread_registry_key] ||= new
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
37
46
|
def method_missing(name, *args, &block) # :nodoc:
|
38
47
|
# Caches the method definition as a singleton method of the receiver.
|
39
|
-
|
40
|
-
|
41
|
-
|
48
|
+
#
|
49
|
+
# By letting #delegate handle it, we avoid an enclosure that'll capture args.
|
50
|
+
singleton_class.delegate name, to: :instance
|
42
51
|
|
43
52
|
send(name, *args, &block)
|
44
53
|
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def per_thread_registry_instance
|
49
|
-
Thread.current[name] ||= new
|
50
|
-
end
|
51
54
|
end
|
52
55
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module ActiveSupport
|
4
|
+
module SecurityUtils
|
5
|
+
# Constant time string comparison.
|
6
|
+
#
|
7
|
+
# The values compared should be of fixed length, such as strings
|
8
|
+
# that have already been processed by HMAC. This should not be used
|
9
|
+
# on variable length plaintext strings because it could leak length info
|
10
|
+
# via timing attacks.
|
11
|
+
def secure_compare(a, b)
|
12
|
+
return false unless a.bytesize == b.bytesize
|
13
|
+
|
14
|
+
l = a.unpack "C#{a.bytesize}"
|
15
|
+
|
16
|
+
res = 0
|
17
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
18
|
+
res == 0
|
19
|
+
end
|
20
|
+
module_function :secure_compare
|
21
|
+
|
22
|
+
def variable_size_secure_compare(a, b) # :nodoc:
|
23
|
+
secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
|
24
|
+
end
|
25
|
+
module_function :variable_size_secure_compare
|
26
|
+
end
|
27
|
+
end
|
@@ -31,22 +31,54 @@ module ActiveSupport
|
|
31
31
|
|
32
32
|
# Attach the subscriber to a namespace.
|
33
33
|
def attach_to(namespace, subscriber=new, notifier=ActiveSupport::Notifications)
|
34
|
+
@namespace = namespace
|
35
|
+
@subscriber = subscriber
|
36
|
+
@notifier = notifier
|
37
|
+
|
34
38
|
subscribers << subscriber
|
35
39
|
|
40
|
+
# Add event subscribers for all existing methods on the class.
|
36
41
|
subscriber.public_methods(false).each do |event|
|
37
|
-
|
42
|
+
add_event_subscriber(event)
|
43
|
+
end
|
44
|
+
end
|
38
45
|
|
39
|
-
|
46
|
+
# Adds event subscribers for all new methods added to the class.
|
47
|
+
def method_added(event)
|
48
|
+
# Only public methods are added as subscribers, and only if a notifier
|
49
|
+
# has been set up. This means that subscribers will only be set up for
|
50
|
+
# classes that call #attach_to.
|
51
|
+
if public_method_defined?(event) && notifier
|
52
|
+
add_event_subscriber(event)
|
40
53
|
end
|
41
54
|
end
|
42
55
|
|
43
56
|
def subscribers
|
44
57
|
@@subscribers ||= []
|
45
58
|
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
attr_reader :subscriber, :notifier, :namespace
|
63
|
+
|
64
|
+
def add_event_subscriber(event)
|
65
|
+
return if %w{ start finish }.include?(event.to_s)
|
66
|
+
|
67
|
+
pattern = "#{event}.#{namespace}"
|
68
|
+
|
69
|
+
# don't add multiple subscribers (eg. if methods are redefined)
|
70
|
+
return if subscriber.patterns.include?(pattern)
|
71
|
+
|
72
|
+
subscriber.patterns << pattern
|
73
|
+
notifier.subscribe(pattern, subscriber)
|
74
|
+
end
|
46
75
|
end
|
47
76
|
|
77
|
+
attr_reader :patterns # :nodoc:
|
78
|
+
|
48
79
|
def initialize
|
49
80
|
@queue_key = [self.class.name, object_id].join "-"
|
81
|
+
@patterns = []
|
50
82
|
super
|
51
83
|
end
|
52
84
|
|
@@ -71,7 +103,7 @@ module ActiveSupport
|
|
71
103
|
private
|
72
104
|
|
73
105
|
def event_stack
|
74
|
-
SubscriberQueueRegistry.get_queue(@queue_key)
|
106
|
+
SubscriberQueueRegistry.instance.get_queue(@queue_key)
|
75
107
|
end
|
76
108
|
end
|
77
109
|
|
@@ -1,42 +1,75 @@
|
|
1
1
|
gem 'minitest' # make sure we get the gem, not stdlib
|
2
|
-
require 'minitest
|
2
|
+
require 'minitest'
|
3
3
|
require 'active_support/testing/tagged_logging'
|
4
4
|
require 'active_support/testing/setup_and_teardown'
|
5
5
|
require 'active_support/testing/assertions'
|
6
6
|
require 'active_support/testing/deprecation'
|
7
|
-
require 'active_support/testing/pending'
|
8
7
|
require 'active_support/testing/declarative'
|
9
8
|
require 'active_support/testing/isolation'
|
10
9
|
require 'active_support/testing/constant_lookup'
|
10
|
+
require 'active_support/testing/time_helpers'
|
11
11
|
require 'active_support/core_ext/kernel/reporting'
|
12
12
|
require 'active_support/deprecation'
|
13
13
|
|
14
|
-
begin
|
15
|
-
silence_warnings { require 'mocha/setup' }
|
16
|
-
rescue LoadError
|
17
|
-
end
|
18
|
-
|
19
14
|
module ActiveSupport
|
20
|
-
class TestCase < ::
|
21
|
-
Assertion =
|
22
|
-
alias_method :method_name, :__name__
|
15
|
+
class TestCase < ::Minitest::Test
|
16
|
+
Assertion = Minitest::Assertion
|
23
17
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
class << self
|
19
|
+
# Sets the order in which test cases are run.
|
20
|
+
#
|
21
|
+
# ActiveSupport::TestCase.test_order = :random # => :random
|
22
|
+
#
|
23
|
+
# Valid values are:
|
24
|
+
# * +:random+ (to run tests in random order)
|
25
|
+
# * +:parallel+ (to run tests in parallel)
|
26
|
+
# * +:sorted+ (to run tests alphabetically by method name)
|
27
|
+
# * +:alpha+ (equivalent to +:sorted+)
|
28
|
+
def test_order=(new_order)
|
29
|
+
ActiveSupport.test_order = new_order
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the order in which test cases are run.
|
33
|
+
#
|
34
|
+
# ActiveSupport::TestCase.test_order # => :sorted
|
35
|
+
#
|
36
|
+
# Possible values are +:random+, +:parallel+, +:alpha+, +:sorted+.
|
37
|
+
# Defaults to +:sorted+.
|
38
|
+
def test_order
|
39
|
+
test_order = ActiveSupport.test_order
|
28
40
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
41
|
+
if test_order.nil?
|
42
|
+
ActiveSupport::Deprecation.warn "You did not specify a value for the " \
|
43
|
+
"configuration option `active_support.test_order`. In Rails 5, " \
|
44
|
+
"the default value of this option will change from `:sorted` to " \
|
45
|
+
"`:random`.\n" \
|
46
|
+
"To disable this warning and keep the current behavior, you can add " \
|
47
|
+
"the following line to your `config/environments/test.rb`:\n" \
|
48
|
+
"\n" \
|
49
|
+
" Rails.application.configure do\n" \
|
50
|
+
" config.active_support.test_order = :sorted\n" \
|
51
|
+
" end\n" \
|
52
|
+
"\n" \
|
53
|
+
"Alternatively, you can opt into the future behavior by setting this " \
|
54
|
+
"option to `:random`."
|
55
|
+
|
56
|
+
test_order = :sorted
|
57
|
+
self.test_order = test_order
|
58
|
+
end
|
59
|
+
|
60
|
+
test_order
|
61
|
+
end
|
62
|
+
|
63
|
+
alias :my_tests_are_order_dependent! :i_suck_and_my_tests_are_order_dependent!
|
33
64
|
end
|
34
65
|
|
66
|
+
alias_method :method_name, :name
|
67
|
+
|
35
68
|
include ActiveSupport::Testing::TaggedLogging
|
36
69
|
include ActiveSupport::Testing::SetupAndTeardown
|
37
70
|
include ActiveSupport::Testing::Assertions
|
38
71
|
include ActiveSupport::Testing::Deprecation
|
39
|
-
include ActiveSupport::Testing::
|
72
|
+
include ActiveSupport::Testing::TimeHelpers
|
40
73
|
extend ActiveSupport::Testing::Declarative
|
41
74
|
|
42
75
|
# test/unit backwards compatibility methods
|