activesupport 6.1.0 → 7.0.4.1
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 +263 -352
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/backtrace_cleaner.rb +2 -2
- data/lib/active_support/benchmarkable.rb +2 -2
- data/lib/active_support/cache/file_store.rb +16 -10
- data/lib/active_support/cache/mem_cache_store.rb +154 -39
- data/lib/active_support/cache/memory_store.rb +24 -16
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +59 -78
- data/lib/active_support/cache/strategy/local_cache.rb +38 -61
- data/lib/active_support/cache.rb +306 -148
- data/lib/active_support/callbacks.rb +184 -85
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +5 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +8 -5
- data/lib/active_support/configuration_file.rb +7 -2
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +13 -12
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +25 -17
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +9 -9
- data/lib/active_support/core_ext/date/conversions.rb +14 -14
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +4 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +101 -32
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +0 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
- data/lib/active_support/core_ext/module/delegation.rb +2 -8
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/conversions.rb +80 -77
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +37 -25
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +91 -39
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +9 -7
- data/lib/active_support/core_ext/time/conversions.rb +14 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -27
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes.rb +32 -14
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +8 -5
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
- data/lib/active_support/deprecation.rb +2 -2
- data/lib/active_support/descendants_tracker.rb +174 -68
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -1
- data/lib/active_support/duration.rb +81 -51
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +13 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +3 -5
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +43 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +19 -10
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/hash_with_indifferent_access.rb +9 -2
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +1 -1
- data/lib/active_support/inflector/inflections.rb +23 -7
- data/lib/active_support/inflector/methods.rb +24 -48
- data/lib/active_support/inflector/transliterate.rb +1 -1
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +22 -5
- data/lib/active_support/lazy_load_hooks.rb +28 -4
- data/lib/active_support/locale/en.yml +2 -2
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +15 -5
- data/lib/active_support/logger_thread_safe_level.rb +4 -13
- data/lib/active_support/message_encryptor.rb +12 -6
- data/lib/active_support/message_verifier.rb +46 -14
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte/unicode.rb +0 -12
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +91 -65
- data/lib/active_support/notifications/instrumenter.rb +32 -15
- data/lib/active_support/notifications.rb +24 -24
- data/lib/active_support/number_helper/number_converter.rb +1 -3
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
- data/lib/active_support/number_helper/rounding_helper.rb +2 -6
- data/lib/active_support/number_helper.rb +0 -2
- data/lib/active_support/option_merger.rb +10 -18
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +1 -1
- data/lib/active_support/parameter_filter.rb +6 -1
- data/lib/active_support/per_thread_registry.rb +5 -0
- data/lib/active_support/railtie.rb +69 -19
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +16 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +2 -2
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +7 -18
- data/lib/active_support/tagged_logging.rb +2 -2
- data/lib/active_support/test_case.rb +13 -21
- data/lib/active_support/testing/assertions.rb +36 -6
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +13 -2
- data/lib/active_support/time_with_zone.rb +60 -20
- data/lib/active_support/values/time_zone.rb +36 -15
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +17 -1
- metadata +29 -26
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -1,8 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module ActiveSupport
|
4
|
+
module EnumerableCoreExt # :nodoc:
|
5
|
+
module Constants
|
6
|
+
private
|
7
|
+
def const_missing(name)
|
8
|
+
if name == :SoleItemExpectedError
|
9
|
+
::ActiveSupport::EnumerableCoreExt::SoleItemExpectedError
|
10
|
+
else
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
3
18
|
module Enumerable
|
4
|
-
|
5
|
-
|
19
|
+
# Error generated by +sole+ when called on an enumerable that doesn't have
|
20
|
+
# exactly one item.
|
21
|
+
class SoleItemExpectedError < StandardError; end
|
22
|
+
|
23
|
+
# HACK: For performance reasons, Enumerable shouldn't have any constants of its own.
|
24
|
+
# So we move SoleItemExpectedError into ActiveSupport::EnumerableCoreExt.
|
25
|
+
ActiveSupport::EnumerableCoreExt::SoleItemExpectedError = remove_const(:SoleItemExpectedError)
|
26
|
+
singleton_class.prepend(ActiveSupport::EnumerableCoreExt::Constants)
|
6
27
|
|
7
28
|
# Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
|
8
29
|
# when we omit an identity.
|
@@ -16,6 +37,22 @@ module Enumerable
|
|
16
37
|
|
17
38
|
# :startdoc:
|
18
39
|
|
40
|
+
# Calculates the minimum from the extracted elements.
|
41
|
+
#
|
42
|
+
# payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
|
43
|
+
# payments.minimum(:price) # => 5
|
44
|
+
def minimum(key)
|
45
|
+
map(&key).min
|
46
|
+
end
|
47
|
+
|
48
|
+
# Calculates the maximum from the extracted elements.
|
49
|
+
#
|
50
|
+
# payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
|
51
|
+
# payments.maximum(:price) # => 15
|
52
|
+
def maximum(key)
|
53
|
+
map(&key).max
|
54
|
+
end
|
55
|
+
|
19
56
|
# Calculates a sum from the elements.
|
20
57
|
#
|
21
58
|
# payments.sum { |p| p.price * p.tax_rate }
|
@@ -27,19 +64,30 @@ module Enumerable
|
|
27
64
|
#
|
28
65
|
# It can also calculate the sum without the use of a block.
|
29
66
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
67
|
+
# [5, 15, 10].sum # => 30
|
68
|
+
# ['foo', 'bar'].sum('') # => "foobar"
|
69
|
+
# [[1, 2], [3, 1, 5]].sum([]) # => [1, 2, 3, 1, 5]
|
33
70
|
#
|
34
71
|
# The default sum of an empty list is zero. You can override this default:
|
35
72
|
#
|
36
|
-
#
|
73
|
+
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
|
37
74
|
def sum(identity = nil, &block)
|
38
75
|
if identity
|
39
76
|
_original_sum_with_required_identity(identity, &block)
|
40
77
|
elsif block_given?
|
41
|
-
map(&block).sum
|
78
|
+
map(&block).sum
|
79
|
+
# we check `first(1) == []` to check if we have an
|
80
|
+
# empty Enumerable; checking `empty?` would return
|
81
|
+
# true for `[nil]`, which we want to deprecate to
|
82
|
+
# keep consistent with Ruby
|
83
|
+
elsif first.is_a?(Numeric) || first(1) == []
|
84
|
+
identity ||= 0
|
85
|
+
_original_sum_with_required_identity(identity, &block)
|
42
86
|
else
|
87
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
88
|
+
Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4.
|
89
|
+
Sum of non-numeric elements requires an initial argument.
|
90
|
+
MSG
|
43
91
|
inject(:+) || 0
|
44
92
|
end
|
45
93
|
end
|
@@ -75,17 +123,17 @@ module Enumerable
|
|
75
123
|
#
|
76
124
|
# %i( created_at updated_at ).index_with(Time.now)
|
77
125
|
# # => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
|
78
|
-
def index_with(default =
|
126
|
+
def index_with(default = (no_default = true))
|
79
127
|
if block_given?
|
80
128
|
result = {}
|
81
129
|
each { |elem| result[elem] = yield(elem) }
|
82
130
|
result
|
83
|
-
elsif
|
131
|
+
elsif no_default
|
132
|
+
to_enum(:index_with) { size if respond_to?(:size) }
|
133
|
+
else
|
84
134
|
result = {}
|
85
135
|
each { |elem| result[elem] = default }
|
86
136
|
result
|
87
|
-
else
|
88
|
-
to_enum(:index_with) { size if respond_to?(:size) }
|
89
137
|
end
|
90
138
|
end
|
91
139
|
|
@@ -136,11 +184,7 @@ module Enumerable
|
|
136
184
|
elements.flatten!(1)
|
137
185
|
reject { |element| elements.include?(element) }
|
138
186
|
end
|
139
|
-
|
140
|
-
# Alias for #excluding.
|
141
|
-
def without(*elements)
|
142
|
-
excluding(*elements)
|
143
|
-
end
|
187
|
+
alias :without :excluding
|
144
188
|
|
145
189
|
# Extract the given key from each element in the enumerable.
|
146
190
|
#
|
@@ -178,40 +222,66 @@ module Enumerable
|
|
178
222
|
# Returns a new +Array+ without the blank items.
|
179
223
|
# Uses Object#blank? for determining if an item is blank.
|
180
224
|
#
|
181
|
-
#
|
182
|
-
#
|
225
|
+
# [1, "", nil, 2, " ", [], {}, false, true].compact_blank
|
226
|
+
# # => [1, 2, true]
|
183
227
|
#
|
184
|
-
#
|
185
|
-
#
|
228
|
+
# Set.new([nil, "", 1, 2])
|
229
|
+
# # => [2, 1] (or [1, 2])
|
186
230
|
#
|
187
231
|
# When called on a +Hash+, returns a new +Hash+ without the blank values.
|
188
232
|
#
|
189
|
-
#
|
190
|
-
#
|
233
|
+
# { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
|
234
|
+
# # => { b: 1, f: true }
|
191
235
|
def compact_blank
|
192
236
|
reject(&:blank?)
|
193
237
|
end
|
238
|
+
|
239
|
+
# Returns a new +Array+ where the order has been set to that provided in the +series+, based on the +key+ of the
|
240
|
+
# objects in the original enumerable.
|
241
|
+
#
|
242
|
+
# [ Person.find(5), Person.find(3), Person.find(1) ].in_order_of(:id, [ 1, 5, 3 ])
|
243
|
+
# # => [ Person.find(1), Person.find(5), Person.find(3) ]
|
244
|
+
#
|
245
|
+
# If the +series+ include keys that have no corresponding element in the Enumerable, these are ignored.
|
246
|
+
# If the Enumerable has additional elements that aren't named in the +series+, these are not included in the result.
|
247
|
+
def in_order_of(key, series)
|
248
|
+
index_by(&key).values_at(*series).compact
|
249
|
+
end
|
250
|
+
|
251
|
+
# Returns the sole item in the enumerable. If there are no items, or more
|
252
|
+
# than one item, raises +Enumerable::SoleItemExpectedError+.
|
253
|
+
#
|
254
|
+
# ["x"].sole # => "x"
|
255
|
+
# Set.new.sole # => Enumerable::SoleItemExpectedError: no item found
|
256
|
+
# { a: 1, b: 2 }.sole # => Enumerable::SoleItemExpectedError: multiple items found
|
257
|
+
def sole
|
258
|
+
case count
|
259
|
+
when 1 then return first # rubocop:disable Style/RedundantReturn
|
260
|
+
when 0 then raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "no item found"
|
261
|
+
when 2.. then raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "multiple items found"
|
262
|
+
end
|
263
|
+
end
|
194
264
|
end
|
195
265
|
|
196
266
|
class Hash
|
197
267
|
# Hash#reject has its own definition, so this needs one too.
|
198
|
-
def compact_blank
|
268
|
+
def compact_blank # :nodoc:
|
199
269
|
reject { |_k, v| v.blank? }
|
200
270
|
end
|
201
271
|
|
202
272
|
# Removes all blank values from the +Hash+ in place and returns self.
|
203
273
|
# Uses Object#blank? for determining if a value is blank.
|
204
274
|
#
|
205
|
-
#
|
206
|
-
#
|
207
|
-
#
|
275
|
+
# h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
|
276
|
+
# h.compact_blank!
|
277
|
+
# # => { b: 1, f: true }
|
208
278
|
def compact_blank!
|
209
279
|
# use delete_if rather than reject! because it always returns self even if nothing changed
|
210
280
|
delete_if { |_k, v| v.blank? }
|
211
281
|
end
|
212
282
|
end
|
213
283
|
|
214
|
-
class Range
|
284
|
+
class Range # :nodoc:
|
215
285
|
# Optimize range sum to use arithmetic progression if a block is not given and
|
216
286
|
# we have a range of numeric values.
|
217
287
|
def sum(identity = nil)
|
@@ -236,8 +306,7 @@ using Module.new {
|
|
236
306
|
end
|
237
307
|
}
|
238
308
|
|
239
|
-
class Array
|
240
|
-
# Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
|
309
|
+
class Array # :nodoc:
|
241
310
|
def sum(init = nil, &block)
|
242
311
|
if init.is_a?(Numeric) || first.is_a?(Numeric)
|
243
312
|
init ||= 0
|
@@ -250,9 +319,9 @@ class Array #:nodoc:
|
|
250
319
|
# Removes all blank elements from the +Array+ in place and returns self.
|
251
320
|
# Uses Object#blank? for determining if an item is blank.
|
252
321
|
#
|
253
|
-
#
|
254
|
-
#
|
255
|
-
#
|
322
|
+
# a = [1, "", nil, 2, " ", [], {}, false, true]
|
323
|
+
# a.compact_blank!
|
324
|
+
# # => [1, 2, true]
|
256
325
|
def compact_blank!
|
257
326
|
# use delete_if rather than reject! because it always returns self even if nothing changed
|
258
327
|
delete_if(&:blank?)
|
@@ -53,7 +53,7 @@ class File
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# Private utility method.
|
56
|
-
def self.probe_stat_in(dir)
|
56
|
+
def self.probe_stat_in(dir) # :nodoc:
|
57
57
|
basename = [
|
58
58
|
".permissions_check",
|
59
59
|
Thread.current.object_id,
|
@@ -64,6 +64,8 @@ class File
|
|
64
64
|
file_name = join(dir, basename)
|
65
65
|
FileUtils.touch(file_name)
|
66
66
|
stat(file_name)
|
67
|
+
rescue Errno::ENOENT
|
68
|
+
file_name = nil
|
67
69
|
ensure
|
68
70
|
FileUtils.rm_f(file_name) if file_name
|
69
71
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/hash_with_indifferent_access"
|
4
4
|
|
5
5
|
class Hash
|
6
|
-
# Returns an
|
6
|
+
# Returns an ActiveSupport::HashWithIndifferentAccess out of its receiver:
|
7
7
|
#
|
8
8
|
# { a: 1 }.with_indifferent_access['a'] # => 1
|
9
9
|
def with_indifferent_access
|
@@ -13,8 +13,8 @@ class Hash
|
|
13
13
|
# Called when object is nested under an object that receives
|
14
14
|
# #with_indifferent_access. This method will be called on the current object
|
15
15
|
# by the enclosing object and is aliased to #with_indifferent_access by
|
16
|
-
# default. Subclasses of Hash may
|
17
|
-
# converting to an
|
16
|
+
# default. Subclasses of Hash may override this method to return +self+ if
|
17
|
+
# converting to an ActiveSupport::HashWithIndifferentAccess would not be
|
18
18
|
# desirable.
|
19
19
|
#
|
20
20
|
# b = { b: 1 }
|
@@ -116,7 +116,7 @@ class Hash
|
|
116
116
|
def _deep_transform_keys_in_object(object, &block)
|
117
117
|
case object
|
118
118
|
when Hash
|
119
|
-
object.each_with_object(
|
119
|
+
object.each_with_object(self.class.new) do |(key, value), result|
|
120
120
|
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
121
121
|
end
|
122
122
|
when Array
|
@@ -11,14 +11,14 @@ module Kernel
|
|
11
11
|
# end
|
12
12
|
#
|
13
13
|
# noisy_call # warning voiced
|
14
|
-
def silence_warnings
|
15
|
-
with_warnings(nil)
|
14
|
+
def silence_warnings(&block)
|
15
|
+
with_warnings(nil, &block)
|
16
16
|
end
|
17
17
|
|
18
18
|
# Sets $VERBOSE to +true+ for the duration of the block and back to its
|
19
19
|
# original value afterwards.
|
20
|
-
def enable_warnings
|
21
|
-
with_warnings(true)
|
20
|
+
def enable_warnings(&block)
|
21
|
+
with_warnings(true, &block)
|
22
22
|
end
|
23
23
|
|
24
24
|
# Sets $VERBOSE for the duration of the block and back to its original
|
@@ -1,11 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Attribute Accessors per Thread
|
4
|
+
#
|
3
5
|
# Extends the module object with class/module and instance accessors for
|
4
6
|
# class/module attributes, just like the native attr* accessors for instance
|
5
7
|
# attributes, but does so on a per-thread basis.
|
6
8
|
#
|
7
9
|
# So the values are scoped within the Thread.current space under the class name
|
8
10
|
# of the module.
|
11
|
+
#
|
12
|
+
# Note that it can also be scoped per-fiber if +Rails.application.config.active_support.isolation_level+
|
13
|
+
# is set to +:fiber+.
|
9
14
|
class Module
|
10
15
|
# Defines a per-thread class attribute and creates class and instance reader methods.
|
11
16
|
# The underlying per-thread class variable is set to +nil+, if it is not previously defined.
|
@@ -14,9 +19,9 @@ class Module
|
|
14
19
|
# thread_mattr_reader :user
|
15
20
|
# end
|
16
21
|
#
|
17
|
-
# Current.user
|
18
|
-
# Thread.current[:attr_Current_user] = "DHH"
|
22
|
+
# Current.user = "DHH"
|
19
23
|
# Current.user # => "DHH"
|
24
|
+
# Thread.new { Current.user }.value # => nil
|
20
25
|
#
|
21
26
|
# The attribute name must be a valid method name in Ruby.
|
22
27
|
#
|
@@ -41,7 +46,8 @@ class Module
|
|
41
46
|
# to work with inheritance via polymorphism.
|
42
47
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
43
48
|
def self.#{sym}
|
44
|
-
|
49
|
+
@__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
|
50
|
+
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}]
|
45
51
|
end
|
46
52
|
EOS
|
47
53
|
|
@@ -53,7 +59,7 @@ class Module
|
|
53
59
|
EOS
|
54
60
|
end
|
55
61
|
|
56
|
-
|
62
|
+
::ActiveSupport::IsolatedExecutionState["attr_#{name}_#{sym}"] = default unless default.nil?
|
57
63
|
end
|
58
64
|
end
|
59
65
|
alias :thread_cattr_reader :thread_mattr_reader
|
@@ -84,7 +90,8 @@ class Module
|
|
84
90
|
# to work with inheritance via polymorphism.
|
85
91
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
86
92
|
def self.#{sym}=(obj)
|
87
|
-
|
93
|
+
@__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
|
94
|
+
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}] = obj
|
88
95
|
end
|
89
96
|
EOS
|
90
97
|
|
@@ -111,16 +118,18 @@ class Module
|
|
111
118
|
# Account.user # => "DHH"
|
112
119
|
# Account.new.user # => "DHH"
|
113
120
|
#
|
121
|
+
# Unlike +mattr_accessor+, values are *not* shared with subclasses or parent classes.
|
114
122
|
# If a subclass changes the value, the parent class' value is not changed.
|
115
|
-
#
|
116
|
-
# is not changed.
|
123
|
+
# If the parent class changes the value, the value of subclasses is not changed.
|
117
124
|
#
|
118
125
|
# class Customer < Account
|
119
126
|
# end
|
120
127
|
#
|
121
|
-
#
|
122
|
-
# Customer.user
|
123
|
-
#
|
128
|
+
# Account.user # => "DHH"
|
129
|
+
# Customer.user # => nil
|
130
|
+
# Customer.user = "Rafael"
|
131
|
+
# Customer.user # => "Rafael"
|
132
|
+
# Account.user # => "DHH"
|
124
133
|
#
|
125
134
|
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
126
135
|
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
@@ -199,13 +199,7 @@ class Module
|
|
199
199
|
|
200
200
|
# Attribute writer methods only accept one argument. Makes sure []=
|
201
201
|
# methods still accept two arguments.
|
202
|
-
definition =
|
203
|
-
"arg"
|
204
|
-
elsif RUBY_VERSION >= "2.7"
|
205
|
-
"..."
|
206
|
-
else
|
207
|
-
"*args, &block"
|
208
|
-
end
|
202
|
+
definition = /[^\]]=\z/.match?(method) ? "arg" : "..."
|
209
203
|
|
210
204
|
# The following generated method calls the target exactly once, storing
|
211
205
|
# the returned value in a dummy variable.
|
@@ -324,7 +318,7 @@ class Module
|
|
324
318
|
end
|
325
319
|
end
|
326
320
|
end
|
327
|
-
ruby2_keywords(:method_missing)
|
321
|
+
ruby2_keywords(:method_missing)
|
328
322
|
RUBY
|
329
323
|
end
|
330
324
|
end
|
@@ -53,13 +53,7 @@ class NameError
|
|
53
53
|
UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
|
54
54
|
private_constant :UNBOUND_METHOD_MODULE_NAME
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
UNBOUND_METHOD_MODULE_NAME.bind_call(mod)
|
59
|
-
end
|
60
|
-
else
|
61
|
-
def real_mod_name(mod)
|
62
|
-
UNBOUND_METHOD_MODULE_NAME.bind(mod).call
|
63
|
-
end
|
56
|
+
def real_mod_name(mod)
|
57
|
+
UNBOUND_METHOD_MODULE_NAME.bind_call(mod)
|
64
58
|
end
|
65
59
|
end
|
@@ -7,7 +7,9 @@ module ActiveSupport
|
|
7
7
|
module NumericWithFormat
|
8
8
|
# Provides options for converting numbers into formatted strings.
|
9
9
|
# Options are provided for phone numbers, currency, percentage,
|
10
|
-
# precision, positional notation, file size and pretty printing.
|
10
|
+
# precision, positional notation, file size, and pretty printing.
|
11
|
+
#
|
12
|
+
# This method is aliased to <tt>to_formatted_s</tt>.
|
11
13
|
#
|
12
14
|
# ==== Options
|
13
15
|
#
|
@@ -16,102 +18,102 @@ module ActiveSupport
|
|
16
18
|
# ==== Examples
|
17
19
|
#
|
18
20
|
# Phone Numbers:
|
19
|
-
# 5551234.
|
20
|
-
# 1235551234.
|
21
|
-
# 1235551234.
|
22
|
-
# 1235551234.
|
23
|
-
# 1235551234.
|
24
|
-
# 1235551234.
|
25
|
-
# 1235551234.
|
21
|
+
# 5551234.to_fs(:phone) # => "555-1234"
|
22
|
+
# 1235551234.to_fs(:phone) # => "123-555-1234"
|
23
|
+
# 1235551234.to_fs(:phone, area_code: true) # => "(123) 555-1234"
|
24
|
+
# 1235551234.to_fs(:phone, delimiter: ' ') # => "123 555 1234"
|
25
|
+
# 1235551234.to_fs(:phone, area_code: true, extension: 555) # => "(123) 555-1234 x 555"
|
26
|
+
# 1235551234.to_fs(:phone, country_code: 1) # => "+1-123-555-1234"
|
27
|
+
# 1235551234.to_fs(:phone, country_code: 1, extension: 1343, delimiter: '.')
|
26
28
|
# # => "+1.123.555.1234 x 1343"
|
27
29
|
#
|
28
30
|
# Currency:
|
29
|
-
# 1234567890.50.
|
30
|
-
# 1234567890.506.
|
31
|
-
# 1234567890.506.
|
32
|
-
# 1234567890.506.
|
33
|
-
# 1234567890.506.
|
34
|
-
# -1234567890.50.
|
31
|
+
# 1234567890.50.to_fs(:currency) # => "$1,234,567,890.50"
|
32
|
+
# 1234567890.506.to_fs(:currency) # => "$1,234,567,890.51"
|
33
|
+
# 1234567890.506.to_fs(:currency, precision: 3) # => "$1,234,567,890.506"
|
34
|
+
# 1234567890.506.to_fs(:currency, round_mode: :down) # => "$1,234,567,890.50"
|
35
|
+
# 1234567890.506.to_fs(:currency, locale: :fr) # => "1 234 567 890,51 €"
|
36
|
+
# -1234567890.50.to_fs(:currency, negative_format: '(%u%n)')
|
35
37
|
# # => "($1,234,567,890.50)"
|
36
|
-
# 1234567890.50.
|
38
|
+
# 1234567890.50.to_fs(:currency, unit: '£', separator: ',', delimiter: '')
|
37
39
|
# # => "£1234567890,50"
|
38
|
-
# 1234567890.50.
|
40
|
+
# 1234567890.50.to_fs(:currency, unit: '£', separator: ',', delimiter: '', format: '%n %u')
|
39
41
|
# # => "1234567890,50 £"
|
40
42
|
#
|
41
43
|
# Percentage:
|
42
|
-
# 100.
|
43
|
-
# 100.
|
44
|
-
# 1000.
|
45
|
-
# 302.24398923423.
|
46
|
-
# 302.24398923423.
|
47
|
-
# 1000.
|
48
|
-
# 100.
|
44
|
+
# 100.to_fs(:percentage) # => "100.000%"
|
45
|
+
# 100.to_fs(:percentage, precision: 0) # => "100%"
|
46
|
+
# 1000.to_fs(:percentage, delimiter: '.', separator: ',') # => "1.000,000%"
|
47
|
+
# 302.24398923423.to_fs(:percentage, precision: 5) # => "302.24399%"
|
48
|
+
# 302.24398923423.to_fs(:percentage, round_mode: :down) # => "302.243%"
|
49
|
+
# 1000.to_fs(:percentage, locale: :fr) # => "1 000,000%"
|
50
|
+
# 100.to_fs(:percentage, format: '%n %') # => "100.000 %"
|
49
51
|
#
|
50
52
|
# Delimited:
|
51
|
-
# 12345678.
|
52
|
-
# 12345678.05.
|
53
|
-
# 12345678.
|
54
|
-
# 12345678.
|
55
|
-
# 12345678.05.
|
56
|
-
# 12345678.05.
|
57
|
-
# 98765432.98.
|
53
|
+
# 12345678.to_fs(:delimited) # => "12,345,678"
|
54
|
+
# 12345678.05.to_fs(:delimited) # => "12,345,678.05"
|
55
|
+
# 12345678.to_fs(:delimited, delimiter: '.') # => "12.345.678"
|
56
|
+
# 12345678.to_fs(:delimited, delimiter: ',') # => "12,345,678"
|
57
|
+
# 12345678.05.to_fs(:delimited, separator: ' ') # => "12,345,678 05"
|
58
|
+
# 12345678.05.to_fs(:delimited, locale: :fr) # => "12 345 678,05"
|
59
|
+
# 98765432.98.to_fs(:delimited, delimiter: ' ', separator: ',')
|
58
60
|
# # => "98 765 432,98"
|
59
61
|
#
|
60
62
|
# Rounded:
|
61
|
-
# 111.2345.
|
62
|
-
# 111.2345.
|
63
|
-
# 111.2345.
|
64
|
-
# 13.
|
65
|
-
# 389.32314.
|
66
|
-
# 111.2345.
|
67
|
-
# 111.2345.
|
68
|
-
# 13.
|
69
|
-
# 111.234.
|
70
|
-
# 13.
|
63
|
+
# 111.2345.to_fs(:rounded) # => "111.235"
|
64
|
+
# 111.2345.to_fs(:rounded, precision: 2) # => "111.23"
|
65
|
+
# 111.2345.to_fs(:rounded, precision: 2, round_mode: :up) # => "111.24"
|
66
|
+
# 13.to_fs(:rounded, precision: 5) # => "13.00000"
|
67
|
+
# 389.32314.to_fs(:rounded, precision: 0) # => "389"
|
68
|
+
# 111.2345.to_fs(:rounded, significant: true) # => "111"
|
69
|
+
# 111.2345.to_fs(:rounded, precision: 1, significant: true) # => "100"
|
70
|
+
# 13.to_fs(:rounded, precision: 5, significant: true) # => "13.000"
|
71
|
+
# 111.234.to_fs(:rounded, locale: :fr) # => "111,234"
|
72
|
+
# 13.to_fs(:rounded, precision: 5, significant: true, strip_insignificant_zeros: true)
|
71
73
|
# # => "13"
|
72
|
-
# 389.32314.
|
73
|
-
# 1111.2345.
|
74
|
+
# 389.32314.to_fs(:rounded, precision: 4, significant: true) # => "389.3"
|
75
|
+
# 1111.2345.to_fs(:rounded, precision: 2, separator: ',', delimiter: '.')
|
74
76
|
# # => "1.111,23"
|
75
77
|
#
|
76
78
|
# Human-friendly size in Bytes:
|
77
|
-
# 123.
|
78
|
-
# 1234.
|
79
|
-
# 12345.
|
80
|
-
# 1234567.
|
81
|
-
# 1234567890.
|
82
|
-
# 1234567890123.
|
83
|
-
# 1234567890123456.
|
84
|
-
# 1234567890123456789.
|
85
|
-
# 1234567.
|
86
|
-
# 1234567.
|
87
|
-
# 483989.
|
88
|
-
# 1234567.
|
89
|
-
# 1234567890123.
|
90
|
-
# 524288000.
|
79
|
+
# 123.to_fs(:human_size) # => "123 Bytes"
|
80
|
+
# 1234.to_fs(:human_size) # => "1.21 KB"
|
81
|
+
# 12345.to_fs(:human_size) # => "12.1 KB"
|
82
|
+
# 1234567.to_fs(:human_size) # => "1.18 MB"
|
83
|
+
# 1234567890.to_fs(:human_size) # => "1.15 GB"
|
84
|
+
# 1234567890123.to_fs(:human_size) # => "1.12 TB"
|
85
|
+
# 1234567890123456.to_fs(:human_size) # => "1.1 PB"
|
86
|
+
# 1234567890123456789.to_fs(:human_size) # => "1.07 EB"
|
87
|
+
# 1234567.to_fs(:human_size, precision: 2) # => "1.2 MB"
|
88
|
+
# 1234567.to_fs(:human_size, precision: 2, round_mode: :up) # => "1.3 MB"
|
89
|
+
# 483989.to_fs(:human_size, precision: 2) # => "470 KB"
|
90
|
+
# 1234567.to_fs(:human_size, precision: 2, separator: ',') # => "1,2 MB"
|
91
|
+
# 1234567890123.to_fs(:human_size, precision: 5) # => "1.1228 TB"
|
92
|
+
# 524288000.to_fs(:human_size, precision: 5) # => "500 MB"
|
91
93
|
#
|
92
94
|
# Human-friendly format:
|
93
|
-
# 123.
|
94
|
-
# 1234.
|
95
|
-
# 12345.
|
96
|
-
# 1234567.
|
97
|
-
# 1234567890.
|
98
|
-
# 1234567890123.
|
99
|
-
# 1234567890123456.
|
100
|
-
# 1234567890123456789.
|
101
|
-
# 489939.
|
102
|
-
# 489939.
|
103
|
-
# 489939.
|
104
|
-
# 1234567.
|
105
|
-
# significant: false)
|
106
|
-
# 1234567.
|
95
|
+
# 123.to_fs(:human) # => "123"
|
96
|
+
# 1234.to_fs(:human) # => "1.23 Thousand"
|
97
|
+
# 12345.to_fs(:human) # => "12.3 Thousand"
|
98
|
+
# 1234567.to_fs(:human) # => "1.23 Million"
|
99
|
+
# 1234567890.to_fs(:human) # => "1.23 Billion"
|
100
|
+
# 1234567890123.to_fs(:human) # => "1.23 Trillion"
|
101
|
+
# 1234567890123456.to_fs(:human) # => "1.23 Quadrillion"
|
102
|
+
# 1234567890123456789.to_fs(:human) # => "1230 Quadrillion"
|
103
|
+
# 489939.to_fs(:human, precision: 2) # => "490 Thousand"
|
104
|
+
# 489939.to_fs(:human, precision: 2, round_mode: :down) # => "480 Thousand"
|
105
|
+
# 489939.to_fs(:human, precision: 4) # => "489.9 Thousand"
|
106
|
+
# 1234567.to_fs(:human, precision: 4,
|
107
|
+
# significant: false) # => "1.2346 Million"
|
108
|
+
# 1234567.to_fs(:human, precision: 1,
|
107
109
|
# separator: ',',
|
108
|
-
# significant: false)
|
109
|
-
def
|
110
|
+
# significant: false) # => "1,2 Million"
|
111
|
+
def to_fs(format = nil, options = nil)
|
112
|
+
return to_s if format.nil?
|
113
|
+
|
110
114
|
case format
|
111
|
-
when nil
|
112
|
-
super()
|
113
115
|
when Integer, String
|
114
|
-
|
116
|
+
to_s(format)
|
115
117
|
when :phone
|
116
118
|
ActiveSupport::NumberHelper.number_to_phone(self, options || {})
|
117
119
|
when :currency
|
@@ -127,11 +129,12 @@ module ActiveSupport
|
|
127
129
|
when :human_size
|
128
130
|
ActiveSupport::NumberHelper.number_to_human_size(self, options || {})
|
129
131
|
when Symbol
|
130
|
-
|
132
|
+
to_s
|
131
133
|
else
|
132
|
-
|
134
|
+
to_s(format)
|
133
135
|
end
|
134
136
|
end
|
137
|
+
alias_method :to_formatted_s, :to_fs
|
135
138
|
end
|
136
139
|
end
|
137
140
|
|