activesupport 5.2.7 → 6.0.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.

Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +182 -566
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/backtrace_cleaner.rb +23 -0
  6. data/lib/active_support/cache/file_store.rb +19 -12
  7. data/lib/active_support/cache/mem_cache_store.rb +16 -2
  8. data/lib/active_support/cache/memory_store.rb +5 -0
  9. data/lib/active_support/cache/null_store.rb +5 -0
  10. data/lib/active_support/cache/redis_cache_store.rb +39 -20
  11. data/lib/active_support/cache.rb +40 -18
  12. data/lib/active_support/callbacks.rb +16 -5
  13. data/lib/active_support/configurable.rb +4 -8
  14. data/lib/active_support/core_ext/array/extract.rb +21 -0
  15. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  16. data/lib/active_support/core_ext/array.rb +1 -1
  17. data/lib/active_support/core_ext/class/attribute.rb +1 -1
  18. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  19. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  20. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -17
  21. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  22. data/lib/active_support/core_ext/enumerable.rb +71 -67
  23. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  24. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  25. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  26. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  27. data/lib/active_support/core_ext/hash.rb +0 -2
  28. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  29. data/lib/active_support/core_ext/load_error.rb +1 -1
  30. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -5
  31. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -14
  32. data/lib/active_support/core_ext/module/delegation.rb +27 -7
  33. data/lib/active_support/core_ext/module/introspection.rb +37 -13
  34. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  35. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  36. data/lib/active_support/core_ext/module.rb +0 -1
  37. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  38. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  39. data/lib/active_support/core_ext/numeric.rb +0 -1
  40. data/lib/active_support/core_ext/object/blank.rb +1 -2
  41. data/lib/active_support/core_ext/object/duplicable.rb +5 -2
  42. data/lib/active_support/core_ext/object/json.rb +1 -0
  43. data/lib/active_support/core_ext/object/try.rb +15 -7
  44. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  45. data/lib/active_support/core_ext/range/compare_range.rb +1 -1
  46. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  47. data/lib/active_support/core_ext/range/include_range.rb +6 -0
  48. data/lib/active_support/core_ext/regexp.rb +0 -4
  49. data/lib/active_support/core_ext/securerandom.rb +23 -3
  50. data/lib/active_support/core_ext/string/access.rb +8 -0
  51. data/lib/active_support/core_ext/string/filters.rb +41 -0
  52. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  53. data/lib/active_support/core_ext/string/output_safety.rb +16 -5
  54. data/lib/active_support/core_ext/string/strip.rb +3 -1
  55. data/lib/active_support/core_ext/uri.rb +1 -0
  56. data/lib/active_support/current_attributes.rb +2 -0
  57. data/lib/active_support/dependencies.rb +28 -11
  58. data/lib/active_support/deprecation/behaviors.rb +1 -1
  59. data/lib/active_support/deprecation/method_wrappers.rb +4 -5
  60. data/lib/active_support/deprecation/proxy_wrappers.rb +0 -2
  61. data/lib/active_support/deprecation.rb +1 -1
  62. data/lib/active_support/descendants_tracker.rb +6 -5
  63. data/lib/active_support/duration/iso8601_parser.rb +2 -3
  64. data/lib/active_support/duration/iso8601_serializer.rb +3 -4
  65. data/lib/active_support/duration.rb +12 -14
  66. data/lib/active_support/encrypted_configuration.rb +0 -4
  67. data/lib/active_support/evented_file_update_checker.rb +25 -7
  68. data/lib/active_support/execution_wrapper.rb +14 -16
  69. data/lib/active_support/gem_version.rb +4 -4
  70. data/lib/active_support/hash_with_indifferent_access.rb +16 -28
  71. data/lib/active_support/i18n.rb +1 -0
  72. data/lib/active_support/i18n_railtie.rb +8 -1
  73. data/lib/active_support/inflector/inflections.rb +1 -4
  74. data/lib/active_support/inflector/methods.rb +15 -27
  75. data/lib/active_support/inflector/transliterate.rb +6 -6
  76. data/lib/active_support/json/decoding.rb +23 -23
  77. data/lib/active_support/json/encoding.rb +6 -2
  78. data/lib/active_support/key_generator.rb +0 -32
  79. data/lib/active_support/lazy_load_hooks.rb +5 -1
  80. data/lib/active_support/locale/en.rb +31 -0
  81. data/lib/active_support/log_subscriber.rb +31 -8
  82. data/lib/active_support/logger.rb +0 -15
  83. data/lib/active_support/logger_silence.rb +28 -12
  84. data/lib/active_support/logger_thread_safe_level.rb +27 -6
  85. data/lib/active_support/message_encryptor.rb +2 -4
  86. data/lib/active_support/message_verifier.rb +2 -2
  87. data/lib/active_support/multibyte/chars.rb +29 -48
  88. data/lib/active_support/multibyte/unicode.rb +44 -281
  89. data/lib/active_support/notifications/fanout.rb +42 -4
  90. data/lib/active_support/notifications/instrumenter.rb +73 -2
  91. data/lib/active_support/notifications.rb +32 -4
  92. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -2
  93. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -1
  94. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -1
  95. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -1
  96. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  97. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -0
  98. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -3
  99. data/lib/active_support/number_helper.rb +7 -0
  100. data/lib/active_support/ordered_options.rb +1 -1
  101. data/lib/active_support/parameter_filter.rb +124 -0
  102. data/lib/active_support/rails.rb +0 -6
  103. data/lib/active_support/reloader.rb +5 -6
  104. data/lib/active_support/subscriber.rb +16 -26
  105. data/lib/active_support/tagged_logging.rb +13 -4
  106. data/lib/active_support/test_case.rb +91 -0
  107. data/lib/active_support/testing/assertions.rb +15 -1
  108. data/lib/active_support/testing/deprecation.rb +0 -1
  109. data/lib/active_support/testing/file_fixtures.rb +2 -0
  110. data/lib/active_support/testing/isolation.rb +2 -2
  111. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  112. data/lib/active_support/testing/parallelization.rb +109 -0
  113. data/lib/active_support/testing/stream.rb +1 -1
  114. data/lib/active_support/testing/time_helpers.rb +7 -7
  115. data/lib/active_support/time_with_zone.rb +15 -5
  116. data/lib/active_support/values/time_zone.rb +12 -7
  117. data/lib/active_support/xml_mini/jdom.rb +2 -2
  118. data/lib/active_support/xml_mini/libxml.rb +2 -2
  119. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  120. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  121. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  122. data/lib/active_support/xml_mini/rexml.rb +2 -2
  123. data/lib/active_support/xml_mini.rb +2 -9
  124. data/lib/active_support.rb +1 -1
  125. metadata +12 -10
  126. data/lib/active_support/core_ext/digest.rb +0 -3
  127. data/lib/active_support/values/unicode_tables.dat +0 -0
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2018 David Heinemeier Hansson
1
+ Copyright (c) 2005-2019 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -14,7 +14,7 @@ The latest version of Active Support can be installed with RubyGems:
14
14
 
15
15
  Source code can be downloaded as part of the Rails project on GitHub:
16
16
 
17
- * https://github.com/rails/rails/tree/5-2-stable/activesupport
17
+ * https://github.com/rails/rails/tree/master/activesupport
18
18
 
19
19
 
20
20
  == License
@@ -31,6 +31,9 @@ module ActiveSupport
31
31
  class BacktraceCleaner
32
32
  def initialize
33
33
  @filters, @silencers = [], []
34
+ add_gem_filter
35
+ add_gem_silencer
36
+ add_stdlib_silencer
34
37
  end
35
38
 
36
39
  # Returns the backtrace after all filters and silencers have been run
@@ -82,6 +85,26 @@ module ActiveSupport
82
85
  end
83
86
 
84
87
  private
88
+
89
+ FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
90
+
91
+ def add_gem_filter
92
+ gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
93
+ return if gems_paths.empty?
94
+
95
+ gems_regexp = %r{(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
96
+ gems_result = '\3 (\4) \5'
97
+ add_filter { |line| line.sub(gems_regexp, gems_result) }
98
+ end
99
+
100
+ def add_gem_silencer
101
+ add_silencer { |line| FORMATTED_GEMS_PATTERN.match?(line) }
102
+ end
103
+
104
+ def add_stdlib_silencer
105
+ add_silencer { |line| line.start_with?(RbConfig::CONFIG["rubylibdir"]) }
106
+ end
107
+
85
108
  def filter_backtrace(backtrace)
86
109
  @filters.each do |f|
87
110
  backtrace = backtrace.map { |line| f.call(line) }
@@ -26,6 +26,11 @@ module ActiveSupport
26
26
  @cache_path = cache_path.to_s
27
27
  end
28
28
 
29
+ # Advertise cache versioning support.
30
+ def self.supports_cache_versioning?
31
+ true
32
+ end
33
+
29
34
  # Deletes all items from the cache. In this case it deletes all the entries in the specified
30
35
  # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
31
36
  # config file when using +FileStore+ because everything in that directory will be deleted.
@@ -103,12 +108,10 @@ module ActiveSupport
103
108
  def lock_file(file_name, &block)
104
109
  if File.exist?(file_name)
105
110
  File.open(file_name, "r+") do |f|
106
- begin
107
- f.flock File::LOCK_EX
108
- yield
109
- ensure
110
- f.flock File::LOCK_UN
111
- end
111
+ f.flock File::LOCK_EX
112
+ yield
113
+ ensure
114
+ f.flock File::LOCK_UN
112
115
  end
113
116
  else
114
117
  yield
@@ -127,15 +130,19 @@ module ActiveSupport
127
130
  hash = Zlib.adler32(fname)
128
131
  hash, dir_1 = hash.divmod(0x1000)
129
132
  dir_2 = hash.modulo(0x1000)
130
- fname_paths = []
131
133
 
132
134
  # Make sure file name doesn't exceed file system limits.
133
- begin
134
- fname_paths << fname[0, FILENAME_MAX_SIZE]
135
- fname = fname[FILENAME_MAX_SIZE..-1]
136
- end until fname.blank?
135
+ if fname.length < FILENAME_MAX_SIZE
136
+ fname_paths = fname
137
+ else
138
+ fname_paths = []
139
+ begin
140
+ fname_paths << fname[0, FILENAME_MAX_SIZE]
141
+ fname = fname[FILENAME_MAX_SIZE..-1]
142
+ end until fname.blank?
143
+ end
137
144
 
138
- File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
145
+ File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, fname_paths)
139
146
  end
140
147
 
141
148
  # Translate a file path into a key.
@@ -28,6 +28,14 @@ module ActiveSupport
28
28
  # Provide support for raw values in the local cache strategy.
29
29
  module LocalCacheWithRaw # :nodoc:
30
30
  private
31
+ def read_entry(key, options)
32
+ entry = super
33
+ if options[:raw] && local_cache && entry
34
+ entry = deserialize_entry(entry.value)
35
+ end
36
+ entry
37
+ end
38
+
31
39
  def write_entry(key, entry, options)
32
40
  if options[:raw] && local_cache
33
41
  raw_entry = Entry.new(entry.value.to_s)
@@ -39,6 +47,11 @@ module ActiveSupport
39
47
  end
40
48
  end
41
49
 
50
+ # Advertise cache versioning support.
51
+ def self.supports_cache_versioning?
52
+ true
53
+ end
54
+
42
55
  prepend Strategy::LocalCache
43
56
  prepend LocalCacheWithRaw
44
57
 
@@ -181,8 +194,9 @@ module ActiveSupport
181
194
  key
182
195
  end
183
196
 
184
- def deserialize_entry(entry)
185
- if entry
197
+ def deserialize_entry(raw_value)
198
+ if raw_value
199
+ entry = Marshal.load(raw_value) rescue raw_value
186
200
  entry.is_a?(Entry) ? entry : Entry.new(entry)
187
201
  end
188
202
  end
@@ -30,6 +30,11 @@ module ActiveSupport
30
30
  @pruning = false
31
31
  end
32
32
 
33
+ # Advertise cache versioning support.
34
+ def self.supports_cache_versioning?
35
+ true
36
+ end
37
+
33
38
  # Delete all data stored in a given cache store.
34
39
  def clear(options = nil)
35
40
  synchronize do
@@ -12,6 +12,11 @@ module ActiveSupport
12
12
  class NullStore < Store
13
13
  prepend Strategy::LocalCache
14
14
 
15
+ # Advertise cache versioning support.
16
+ def self.supports_cache_versioning?
17
+ true
18
+ end
19
+
15
20
  def clear(options = nil)
16
21
  end
17
22
 
@@ -17,7 +17,6 @@ end
17
17
 
18
18
  require "digest/sha2"
19
19
  require "active_support/core_ext/marshal"
20
- require "active_support/core_ext/hash/transform_values"
21
20
 
22
21
  module ActiveSupport
23
22
  module Cache
@@ -67,9 +66,22 @@ module ActiveSupport
67
66
  SCAN_BATCH_SIZE = 1000
68
67
  private_constant :SCAN_BATCH_SIZE
69
68
 
69
+ # Advertise cache versioning support.
70
+ def self.supports_cache_versioning?
71
+ true
72
+ end
73
+
70
74
  # Support raw values in the local cache strategy.
71
75
  module LocalCacheWithRaw # :nodoc:
72
76
  private
77
+ def read_entry(key, options)
78
+ entry = super
79
+ if options[:raw] && local_cache && entry
80
+ entry = deserialize_entry(entry.value)
81
+ end
82
+ entry
83
+ end
84
+
73
85
  def write_entry(key, entry, options)
74
86
  if options[:raw] && local_cache
75
87
  raw_entry = Entry.new(serialize_entry(entry, raw: true))
@@ -148,7 +160,7 @@ module ActiveSupport
148
160
  # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
149
161
  #
150
162
  # No namespace is set by default. Provide one if the Redis cache
151
- # server is shared with other apps: <tt>namespace: 'myapp-cache'<tt>.
163
+ # server is shared with other apps: <tt>namespace: 'myapp-cache'</tt>.
152
164
  #
153
165
  # Compression is enabled by default with a 1kB threshold, so cached
154
166
  # values larger than 1kB are automatically compressed. Disable by
@@ -251,7 +263,14 @@ module ActiveSupport
251
263
  def increment(name, amount = 1, options = nil)
252
264
  instrument :increment, name, amount: amount do
253
265
  failsafe :increment do
254
- redis.with { |c| c.incrby normalize_key(name, options), amount }
266
+ options = merged_options(options)
267
+ key = normalize_key(name, options)
268
+
269
+ redis.with do |c|
270
+ c.incrby(key, amount).tap do
271
+ write_key_expiry(c, key, options)
272
+ end
273
+ end
255
274
  end
256
275
  end
257
276
  end
@@ -267,7 +286,14 @@ module ActiveSupport
267
286
  def decrement(name, amount = 1, options = nil)
268
287
  instrument :decrement, name, amount: amount do
269
288
  failsafe :decrement do
270
- redis.with { |c| c.decrby normalize_key(name, options), amount }
289
+ options = merged_options(options)
290
+ key = normalize_key(name, options)
291
+
292
+ redis.with do |c|
293
+ c.decrby(key, amount).tap do
294
+ write_key_expiry(c, key, options)
295
+ end
296
+ end
271
297
  end
272
298
  end
273
299
  end
@@ -320,8 +346,7 @@ module ActiveSupport
320
346
  # Read an entry from the cache.
321
347
  def read_entry(key, options = nil)
322
348
  failsafe :read_entry do
323
- raw = options && options.fetch(:raw, false)
324
- deserialize_entry(redis.with { |c| c.get(key) }, raw: raw)
349
+ deserialize_entry redis.with { |c| c.get(key) }
325
350
  end
326
351
  end
327
352
 
@@ -336,7 +361,6 @@ module ActiveSupport
336
361
  def read_multi_mget(*names)
337
362
  options = names.extract_options!
338
363
  options = merged_options(options)
339
- raw = options && options.fetch(:raw, false)
340
364
 
341
365
  keys = names.map { |name| normalize_key(name, options) }
342
366
 
@@ -346,7 +370,7 @@ module ActiveSupport
346
370
 
347
371
  names.zip(values).each_with_object({}) do |(name, value), results|
348
372
  if value
349
- entry = deserialize_entry(value, raw: raw)
373
+ entry = deserialize_entry(value)
350
374
  unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(name, options))
351
375
  results[name] = entry.value
352
376
  end
@@ -380,6 +404,12 @@ module ActiveSupport
380
404
  end
381
405
  end
382
406
 
407
+ def write_key_expiry(client, key, options)
408
+ if options[:expires_in] && client.ttl(key).negative?
409
+ client.expire key, options[:expires_in].to_i
410
+ end
411
+ end
412
+
383
413
  # Delete an entry from the cache.
384
414
  def delete_entry(key, options)
385
415
  failsafe :delete_entry, returning: false do
@@ -415,20 +445,9 @@ module ActiveSupport
415
445
  end
416
446
  end
417
447
 
418
- def deserialize_entry(serialized_entry, raw:)
448
+ def deserialize_entry(serialized_entry)
419
449
  if serialized_entry
420
450
  entry = Marshal.load(serialized_entry) rescue serialized_entry
421
-
422
- written_raw = serialized_entry.equal?(entry)
423
- if raw != written_raw
424
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
425
- Using a different value for the raw option when reading and writing
426
- to a cache key is deprecated for :redis_cache_store and Rails 6.0
427
- will stop automatically detecting the format when reading to avoid
428
- marshal loading untrusted raw strings.
429
- MSG
430
- end
431
-
432
451
  entry.is_a?(Entry) ? entry : Entry.new(entry)
433
452
  end
434
453
  end
@@ -229,6 +229,14 @@ module ActiveSupport
229
229
  # ask whether you should force a cache write. Otherwise, it's clearer to
230
230
  # just call <tt>Cache#write</tt>.
231
231
  #
232
+ # Setting <tt>skip_nil: true</tt> will not cache nil result:
233
+ #
234
+ # cache.fetch('foo') { nil }
235
+ # cache.fetch('bar', skip_nil: true) { nil }
236
+ # cache.exist?('foo') # => true
237
+ # cache.exist?('bar') # => false
238
+ #
239
+ #
232
240
  # Setting <tt>compress: false</tt> disables compression of the cache entry.
233
241
  #
234
242
  # Setting <tt>:expires_in</tt> will set an expiration time on the cache.
@@ -333,8 +341,9 @@ module ActiveSupport
333
341
  # the cache with the given key, then that data is returned. Otherwise,
334
342
  # +nil+ is returned.
335
343
  #
336
- # Note, if data was written with the <tt>:expires_in<tt> or <tt>:version</tt> options,
337
- # both of these conditions are applied before the data is returned.
344
+ # Note, if data was written with the <tt>:expires_in</tt> or
345
+ # <tt>:version</tt> options, both of these conditions are applied before
346
+ # the data is returned.
338
347
  #
339
348
  # Options are passed to the underlying cache implementation.
340
349
  def read(name, options = nil)
@@ -402,8 +411,6 @@ module ActiveSupport
402
411
  # to the cache. If you do not want to write the cache when the cache is
403
412
  # not found, use #read_multi.
404
413
  #
405
- # Options are passed to the underlying cache implementation.
406
- #
407
414
  # Returns a hash with the data for each of the names. For example:
408
415
  #
409
416
  # cache.write("bim", "bam")
@@ -413,6 +420,17 @@ module ActiveSupport
413
420
  # # => { "bim" => "bam",
414
421
  # # "unknown_key" => "Fallback value for key: unknown_key" }
415
422
  #
423
+ # Options are passed to the underlying cache implementation. For example:
424
+ #
425
+ # cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
426
+ # "buzz"
427
+ # end
428
+ # # => {"fizz"=>"buzz"}
429
+ # cache.read("fizz")
430
+ # # => "buzz"
431
+ # sleep(6)
432
+ # cache.read("fizz")
433
+ # # => nil
416
434
  def fetch_multi(*names)
417
435
  raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given?
418
436
 
@@ -420,18 +438,18 @@ module ActiveSupport
420
438
  options = merged_options(options)
421
439
 
422
440
  instrument :read_multi, names, options do |payload|
423
- read_multi_entries(names, options).tap do |results|
424
- payload[:hits] = results.keys
425
- payload[:super_operation] = :fetch_multi
441
+ reads = read_multi_entries(names, options)
442
+ writes = {}
443
+ ordered = names.each_with_object({}) do |name, hash|
444
+ hash[name] = reads.fetch(name) { writes[name] = yield(name) }
445
+ end
426
446
 
427
- writes = {}
447
+ payload[:hits] = reads.keys
448
+ payload[:super_operation] = :fetch_multi
428
449
 
429
- (names - results.keys).each do |name|
430
- results[name] = writes[name] = yield(name)
431
- end
450
+ write_multi(writes, options)
432
451
 
433
- write_multi writes, options
434
- end
452
+ ordered
435
453
  end
436
454
  end
437
455
 
@@ -587,9 +605,13 @@ module ActiveSupport
587
605
  # Merges the default options with ones specific to a method call.
588
606
  def merged_options(call_options)
589
607
  if call_options
590
- options.merge(call_options)
608
+ if options.empty?
609
+ call_options
610
+ else
611
+ options.merge(call_options)
612
+ end
591
613
  else
592
- options.dup
614
+ options
593
615
  end
594
616
  end
595
617
 
@@ -634,7 +656,7 @@ module ActiveSupport
634
656
  if key.size > 1
635
657
  key = key.collect { |element| expanded_key(element) }
636
658
  else
637
- key = key.first
659
+ key = expanded_key(key.first)
638
660
  end
639
661
  when Hash
640
662
  key = key.sort_by { |k, _| k.to_s }.collect { |k, v| "#{k}=#{v}" }
@@ -685,7 +707,7 @@ module ActiveSupport
685
707
  end
686
708
 
687
709
  def get_entry_value(entry, name, options)
688
- instrument(:fetch_hit, name, options) {}
710
+ instrument(:fetch_hit, name, options) { }
689
711
  entry.value
690
712
  end
691
713
 
@@ -694,7 +716,7 @@ module ActiveSupport
694
716
  yield(name)
695
717
  end
696
718
 
697
- write(name, result, options)
719
+ write(name, result, options) unless result.nil? && options[:skip_nil]
698
720
  result
699
721
  end
700
722
  end
@@ -23,6 +23,9 @@ module ActiveSupport
23
23
  # +ClassMethods.set_callback+), and run the installed callbacks at the
24
24
  # appropriate times (via +run_callbacks+).
25
25
  #
26
+ # By default callbacks are halted by throwing +:abort+.
27
+ # See +ClassMethods.define_callbacks+ for details.
28
+ #
26
29
  # Three kinds of callbacks are supported: before callbacks, run before a
27
30
  # certain event; after callbacks, run after the event; and around callbacks,
28
31
  # blocks that surround the event, triggering it when they yield. Callback code
@@ -497,9 +500,7 @@ module ActiveSupport
497
500
  arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) }
498
501
  end
499
502
 
500
- def nested
501
- @nested
502
- end
503
+ attr_reader :nested
503
504
 
504
505
  def final?
505
506
  !@call_template
@@ -578,7 +579,7 @@ module ActiveSupport
578
579
  end
579
580
 
580
581
  protected
581
- def chain; @chain; end
582
+ attr_reader :chain
582
583
 
583
584
  private
584
585
 
@@ -659,9 +660,17 @@ module ActiveSupport
659
660
  # * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance
660
661
  # method or a proc; the callback will be called only when they all return
661
662
  # a true value.
663
+ #
664
+ # If a proc is given, its body is evaluated in the context of the
665
+ # current object. It can also optionally accept the current object as
666
+ # an argument.
662
667
  # * <tt>:unless</tt> - A symbol or an array of symbols, each naming an
663
668
  # instance method or a proc; the callback will be called only when they
664
669
  # all return a false value.
670
+ #
671
+ # If a proc is given, its body is evaluated in the context of the
672
+ # current object. It can also optionally accept the current object as
673
+ # an argument.
665
674
  # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
666
675
  # existing chain rather than appended.
667
676
  def set_callback(name, *filter_list, &block)
@@ -809,7 +818,9 @@ module ActiveSupport
809
818
  names.each do |name|
810
819
  name = name.to_sym
811
820
 
812
- set_callbacks name, CallbackChain.new(name, options)
821
+ ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
822
+ target.set_callbacks name, CallbackChain.new(name, options)
823
+ end
813
824
 
814
825
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
815
826
  def _run_#{name}_callbacks(&block)
@@ -2,8 +2,6 @@
2
2
 
3
3
  require "active_support/concern"
4
4
  require "active_support/ordered_options"
5
- require "active_support/core_ext/array/extract_options"
6
- require "active_support/core_ext/regexp"
7
5
 
8
6
  module ActiveSupport
9
7
  # Configurable provides a <tt>config</tt> method to store and retrieve
@@ -106,9 +104,7 @@ module ActiveSupport
106
104
  # end
107
105
  #
108
106
  # User.hair_colors # => [:brown, :black, :blonde, :red]
109
- def config_accessor(*names)
110
- options = names.extract_options!
111
-
107
+ def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true) # :doc:
112
108
  names.each do |name|
113
109
  raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
114
110
 
@@ -118,9 +114,9 @@ module ActiveSupport
118
114
  singleton_class.class_eval reader, __FILE__, reader_line
119
115
  singleton_class.class_eval writer, __FILE__, writer_line
120
116
 
121
- unless options[:instance_accessor] == false
122
- class_eval reader, __FILE__, reader_line unless options[:instance_reader] == false
123
- class_eval writer, __FILE__, writer_line unless options[:instance_writer] == false
117
+ if instance_accessor
118
+ class_eval reader, __FILE__, reader_line if instance_reader
119
+ class_eval writer, __FILE__, writer_line if instance_writer
124
120
  end
125
121
  send("#{name}=", yield) if block_given?
126
122
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Removes and returns the elements for which the block returns a true value.
5
+ # If no block is given, an Enumerator is returned instead.
6
+ #
7
+ # numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8
+ # odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
9
+ # numbers # => [0, 2, 4, 6, 8]
10
+ def extract!
11
+ return to_enum(:extract!) { size } unless block_given?
12
+
13
+ extracted_elements = []
14
+
15
+ reject! do |element|
16
+ extracted_elements << element if yield(element)
17
+ end
18
+
19
+ extracted_elements
20
+ end
21
+ end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Array
4
- # The human way of thinking about adding stuff to the end of a list is with append.
5
- alias_method :append, :push unless [].respond_to?(:append)
3
+ require "active_support/deprecation"
6
4
 
7
- # The human way of thinking about adding stuff to the beginning of a list is with prepend.
8
- alias_method :prepend, :unshift unless [].respond_to?(:prepend)
9
- end
5
+ ActiveSupport::Deprecation.warn "Ruby 2.5+ (required by Rails 6) provides Array#append and Array#prepend natively, so requiring active_support/core_ext/array/prepend_and_append is no longer necessary. Requiring it will raise LoadError in Rails 6.1."
@@ -3,7 +3,7 @@
3
3
  require "active_support/core_ext/array/wrap"
4
4
  require "active_support/core_ext/array/access"
5
5
  require "active_support/core_ext/array/conversions"
6
+ require "active_support/core_ext/array/extract"
6
7
  require "active_support/core_ext/array/extract_options"
7
8
  require "active_support/core_ext/array/grouping"
8
- require "active_support/core_ext/array/prepend_and_append"
9
9
  require "active_support/core_ext/array/inquiry"
@@ -98,7 +98,7 @@ class Class
98
98
  singleton_class.silence_redefinition_of_method("#{name}?")
99
99
  define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
100
100
 
101
- ivar = "@#{name}"
101
+ ivar = "@#{name}".to_sym
102
102
 
103
103
  singleton_class.silence_redefinition_of_method("#{name}=")
104
104
  define_singleton_method("#{name}=") do |val|
@@ -3,7 +3,7 @@
3
3
  class Class
4
4
  begin
5
5
  # Test if this Ruby supports each_object against singleton_class
6
- ObjectSpace.each_object(Numeric.singleton_class) {}
6
+ ObjectSpace.each_object(Numeric.singleton_class) { }
7
7
 
8
8
  # Returns an array with all classes that are < than its receiver.
9
9
  #
@@ -110,12 +110,13 @@ class Date
110
110
  # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
111
111
  # any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
112
112
  def advance(options)
113
- options = options.dup
114
113
  d = self
115
- d = d >> options.delete(:years) * 12 if options[:years]
116
- d = d >> options.delete(:months) if options[:months]
117
- d = d + options.delete(:weeks) * 7 if options[:weeks]
118
- d = d + options.delete(:days) if options[:days]
114
+
115
+ d = d >> options[:years] * 12 if options[:years]
116
+ d = d >> options[:months] if options[:months]
117
+ d = d + options[:weeks] * 7 if options[:weeks]
118
+ d = d + options[:days] if options[:days]
119
+
119
120
  d
120
121
  end
121
122