activesupport 5.2.4.4 → 6.1.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.

Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +353 -435
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support.rb +14 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/array_inquirer.rb +4 -2
  8. data/lib/active_support/backtrace_cleaner.rb +29 -3
  9. data/lib/active_support/benchmarkable.rb +1 -1
  10. data/lib/active_support/cache.rb +142 -78
  11. data/lib/active_support/cache/file_store.rb +33 -33
  12. data/lib/active_support/cache/mem_cache_store.rb +32 -20
  13. data/lib/active_support/cache/memory_store.rb +59 -33
  14. data/lib/active_support/cache/null_store.rb +8 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +70 -43
  16. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  17. data/lib/active_support/callbacks.rb +81 -64
  18. data/lib/active_support/concern.rb +70 -3
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  20. data/lib/active_support/concurrency/share_lock.rb +0 -1
  21. data/lib/active_support/configurable.rb +10 -14
  22. data/lib/active_support/configuration_file.rb +46 -0
  23. data/lib/active_support/core_ext.rb +1 -1
  24. data/lib/active_support/core_ext/array.rb +1 -1
  25. data/lib/active_support/core_ext/array/access.rb +18 -6
  26. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/benchmark.rb +2 -2
  29. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  30. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  31. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  32. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  36. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  37. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  38. data/lib/active_support/core_ext/enumerable.rb +171 -75
  39. data/lib/active_support/core_ext/hash.rb +1 -2
  40. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  41. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  42. data/lib/active_support/core_ext/hash/except.rb +2 -2
  43. data/lib/active_support/core_ext/hash/keys.rb +1 -30
  44. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  45. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  46. data/lib/active_support/core_ext/kernel.rb +0 -1
  47. data/lib/active_support/core_ext/load_error.rb +1 -1
  48. data/lib/active_support/core_ext/marshal.rb +2 -0
  49. data/lib/active_support/core_ext/module.rb +0 -1
  50. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  51. data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
  52. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
  53. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  54. data/lib/active_support/core_ext/module/delegation.rb +76 -33
  55. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  56. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  57. data/lib/active_support/core_ext/name_error.rb +29 -2
  58. data/lib/active_support/core_ext/numeric.rb +0 -1
  59. data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
  60. data/lib/active_support/core_ext/object/blank.rb +1 -2
  61. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  62. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  63. data/lib/active_support/core_ext/object/json.rb +14 -2
  64. data/lib/active_support/core_ext/object/try.rb +17 -7
  65. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  66. data/lib/active_support/core_ext/range/compare_range.rb +34 -13
  67. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  68. data/lib/active_support/core_ext/range/each.rb +0 -1
  69. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  70. data/lib/active_support/core_ext/regexp.rb +8 -5
  71. data/lib/active_support/core_ext/securerandom.rb +23 -3
  72. data/lib/active_support/core_ext/string/access.rb +5 -16
  73. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  74. data/lib/active_support/core_ext/string/filters.rb +42 -1
  75. data/lib/active_support/core_ext/string/inflections.rb +45 -6
  76. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  77. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  78. data/lib/active_support/core_ext/string/output_safety.rb +70 -13
  79. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  80. data/lib/active_support/core_ext/string/strip.rb +3 -1
  81. data/lib/active_support/core_ext/symbol.rb +3 -0
  82. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  83. data/lib/active_support/core_ext/time/calculations.rb +50 -3
  84. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  85. data/lib/active_support/core_ext/uri.rb +6 -1
  86. data/lib/active_support/current_attributes.rb +15 -2
  87. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  88. data/lib/active_support/dependencies.rb +109 -34
  89. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  90. data/lib/active_support/deprecation.rb +6 -1
  91. data/lib/active_support/deprecation/behaviors.rb +16 -3
  92. data/lib/active_support/deprecation/disallowed.rb +56 -0
  93. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  94. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  95. data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
  96. data/lib/active_support/deprecation/reporting.rb +50 -7
  97. data/lib/active_support/descendants_tracker.rb +59 -9
  98. data/lib/active_support/duration.rb +90 -38
  99. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  100. data/lib/active_support/duration/iso8601_serializer.rb +18 -14
  101. data/lib/active_support/encrypted_configuration.rb +0 -4
  102. data/lib/active_support/encrypted_file.rb +22 -4
  103. data/lib/active_support/environment_inquirer.rb +20 -0
  104. data/lib/active_support/evented_file_update_checker.rb +82 -117
  105. data/lib/active_support/execution_wrapper.rb +1 -0
  106. data/lib/active_support/file_update_checker.rb +0 -1
  107. data/lib/active_support/fork_tracker.rb +62 -0
  108. data/lib/active_support/gem_version.rb +4 -4
  109. data/lib/active_support/hash_with_indifferent_access.rb +64 -41
  110. data/lib/active_support/i18n.rb +1 -0
  111. data/lib/active_support/i18n_railtie.rb +15 -8
  112. data/lib/active_support/inflector/inflections.rb +2 -7
  113. data/lib/active_support/inflector/methods.rb +49 -58
  114. data/lib/active_support/inflector/transliterate.rb +47 -18
  115. data/lib/active_support/json/decoding.rb +25 -26
  116. data/lib/active_support/json/encoding.rb +11 -3
  117. data/lib/active_support/key_generator.rb +1 -33
  118. data/lib/active_support/lazy_load_hooks.rb +5 -2
  119. data/lib/active_support/locale/en.rb +33 -0
  120. data/lib/active_support/locale/en.yml +7 -3
  121. data/lib/active_support/log_subscriber.rb +39 -9
  122. data/lib/active_support/logger.rb +2 -17
  123. data/lib/active_support/logger_silence.rb +11 -19
  124. data/lib/active_support/logger_thread_safe_level.rb +50 -6
  125. data/lib/active_support/message_encryptor.rb +8 -13
  126. data/lib/active_support/message_verifier.rb +10 -10
  127. data/lib/active_support/messages/metadata.rb +11 -2
  128. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  129. data/lib/active_support/messages/rotator.rb +10 -9
  130. data/lib/active_support/multibyte/chars.rb +10 -68
  131. data/lib/active_support/multibyte/unicode.rb +15 -327
  132. data/lib/active_support/notifications.rb +72 -8
  133. data/lib/active_support/notifications/fanout.rb +116 -16
  134. data/lib/active_support/notifications/instrumenter.rb +71 -9
  135. data/lib/active_support/number_helper.rb +38 -12
  136. data/lib/active_support/number_helper/number_converter.rb +5 -6
  137. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  138. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  139. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  140. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
  141. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  142. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  143. data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
  144. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  145. data/lib/active_support/option_merger.rb +22 -3
  146. data/lib/active_support/ordered_hash.rb +1 -1
  147. data/lib/active_support/ordered_options.rb +13 -3
  148. data/lib/active_support/parameter_filter.rb +133 -0
  149. data/lib/active_support/per_thread_registry.rb +1 -1
  150. data/lib/active_support/rails.rb +1 -10
  151. data/lib/active_support/railtie.rb +23 -1
  152. data/lib/active_support/reloader.rb +4 -5
  153. data/lib/active_support/rescuable.rb +4 -4
  154. data/lib/active_support/secure_compare_rotator.rb +51 -0
  155. data/lib/active_support/security_utils.rb +19 -12
  156. data/lib/active_support/string_inquirer.rb +4 -3
  157. data/lib/active_support/subscriber.rb +72 -28
  158. data/lib/active_support/tagged_logging.rb +42 -8
  159. data/lib/active_support/test_case.rb +91 -0
  160. data/lib/active_support/testing/assertions.rb +30 -9
  161. data/lib/active_support/testing/deprecation.rb +0 -1
  162. data/lib/active_support/testing/file_fixtures.rb +2 -0
  163. data/lib/active_support/testing/isolation.rb +2 -2
  164. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  165. data/lib/active_support/testing/parallelization.rb +51 -0
  166. data/lib/active_support/testing/parallelization/server.rb +78 -0
  167. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  168. data/lib/active_support/testing/stream.rb +1 -2
  169. data/lib/active_support/testing/time_helpers.rb +47 -12
  170. data/lib/active_support/time_with_zone.rb +81 -47
  171. data/lib/active_support/values/time_zone.rb +32 -17
  172. data/lib/active_support/xml_mini.rb +2 -10
  173. data/lib/active_support/xml_mini/jdom.rb +2 -3
  174. data/lib/active_support/xml_mini/libxml.rb +2 -2
  175. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  178. data/lib/active_support/xml_mini/rexml.rb +10 -3
  179. metadata +58 -32
  180. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  181. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  182. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  183. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  184. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  185. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  186. data/lib/active_support/core_ext/range/include_range.rb +0 -3
  187. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -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
 
@@ -28,14 +33,14 @@ module ActiveSupport
28
33
  end
29
34
 
30
35
  private
31
- def read_entry(key, options)
36
+ def read_entry(key, **options)
32
37
  end
33
38
 
34
- def write_entry(key, entry, options)
39
+ def write_entry(key, entry, **options)
35
40
  true
36
41
  end
37
42
 
38
- def delete_entry(key, options)
43
+ def delete_entry(key, **options)
39
44
  false
40
45
  end
41
46
  end
@@ -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,27 +66,32 @@ 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
73
- def write_entry(key, entry, options)
77
+ def write_entry(key, entry, **options)
74
78
  if options[:raw] && local_cache
75
79
  raw_entry = Entry.new(serialize_entry(entry, raw: true))
76
80
  raw_entry.expires_at = entry.expires_at
77
- super(key, raw_entry, options)
81
+ super(key, raw_entry, **options)
78
82
  else
79
83
  super
80
84
  end
81
85
  end
82
86
 
83
- def write_multi_entries(entries, options)
87
+ def write_multi_entries(entries, **options)
84
88
  if options[:raw] && local_cache
85
89
  raw_entries = entries.map do |key, entry|
86
90
  raw_entry = Entry.new(serialize_entry(entry, raw: true))
87
91
  raw_entry.expires_at = entry.expires_at
88
92
  end.to_h
89
93
 
90
- super(raw_entries, options)
94
+ super(raw_entries, **options)
91
95
  else
92
96
  super
93
97
  end
@@ -140,15 +144,17 @@ module ActiveSupport
140
144
 
141
145
  # Creates a new Redis cache store.
142
146
  #
143
- # Handles three options: block provided to instantiate, single URL
144
- # provided, and multiple URLs provided.
147
+ # Handles four options: :redis block, :redis instance, single :url
148
+ # string, and multiple :url strings.
145
149
  #
146
- # :redis Proc -> options[:redis].call
147
- # :url String -> Redis.new(url: …)
148
- # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
150
+ # Option Class Result
151
+ # :redis Proc -> options[:redis].call
152
+ # :redis Object -> options[:redis]
153
+ # :url String -> Redis.new(url: …)
154
+ # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
149
155
  #
150
156
  # No namespace is set by default. Provide one if the Redis cache
151
- # server is shared with other apps: <tt>namespace: 'myapp-cache'<tt>.
157
+ # server is shared with other apps: <tt>namespace: 'myapp-cache'</tt>.
152
158
  #
153
159
  # Compression is enabled by default with a 1kB threshold, so cached
154
160
  # values larger than 1kB are automatically compressed. Disable by
@@ -163,7 +169,7 @@ module ActiveSupport
163
169
  # Race condition TTL is not set by default. This can be used to avoid
164
170
  # "thundering herd" cache writes when hot cache entries are expired.
165
171
  # See <tt>ActiveSupport::Cache::Store#fetch</tt> for more.
166
- def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
172
+ def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, coder: DEFAULT_CODER, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
167
173
  @redis_options = redis_options
168
174
 
169
175
  @max_key_bytesize = MAX_KEY_BYTESIZE
@@ -171,7 +177,8 @@ module ActiveSupport
171
177
 
172
178
  super namespace: namespace,
173
179
  compress: compress, compress_threshold: compress_threshold,
174
- expires_in: expires_in, race_condition_ttl: race_condition_ttl
180
+ expires_in: expires_in, race_condition_ttl: race_condition_ttl,
181
+ coder: coder
175
182
  end
176
183
 
177
184
  def redis
@@ -189,7 +196,7 @@ module ActiveSupport
189
196
 
190
197
  def inspect
191
198
  instance = @redis || @redis_options
192
- "<##{self.class} options=#{options.inspect} redis=#{instance.inspect}>"
199
+ "#<#{self.class} options=#{options.inspect} redis=#{instance.inspect}>"
193
200
  end
194
201
 
195
202
  # Cache Store API implementation.
@@ -232,10 +239,14 @@ module ActiveSupport
232
239
  pattern = namespace_key(matcher, options)
233
240
  cursor = "0"
234
241
  # Fetch keys in batches using SCAN to avoid blocking the Redis server.
235
- begin
236
- cursor, keys = c.scan(cursor, match: pattern, count: SCAN_BATCH_SIZE)
237
- c.del(*keys) unless keys.empty?
238
- end until cursor == "0"
242
+ nodes = c.respond_to?(:nodes) ? c.nodes : [c]
243
+
244
+ nodes.each do |node|
245
+ begin
246
+ cursor, keys = node.scan(cursor, match: pattern, count: SCAN_BATCH_SIZE)
247
+ node.del(*keys) unless keys.empty?
248
+ end until cursor == "0"
249
+ end
239
250
  end
240
251
  end
241
252
  end
@@ -251,7 +262,14 @@ module ActiveSupport
251
262
  def increment(name, amount = 1, options = nil)
252
263
  instrument :increment, name, amount: amount do
253
264
  failsafe :increment do
254
- redis.with { |c| c.incrby normalize_key(name, options), amount }
265
+ options = merged_options(options)
266
+ key = normalize_key(name, options)
267
+
268
+ redis.with do |c|
269
+ c.incrby(key, amount).tap do
270
+ write_key_expiry(c, key, options)
271
+ end
272
+ end
255
273
  end
256
274
  end
257
275
  end
@@ -267,7 +285,14 @@ module ActiveSupport
267
285
  def decrement(name, amount = 1, options = nil)
268
286
  instrument :decrement, name, amount: amount do
269
287
  failsafe :decrement do
270
- redis.with { |c| c.decrby normalize_key(name, options), amount }
288
+ options = merged_options(options)
289
+ key = normalize_key(name, options)
290
+
291
+ redis.with do |c|
292
+ c.decrby(key, amount).tap do
293
+ write_key_expiry(c, key, options)
294
+ end
295
+ end
271
296
  end
272
297
  end
273
298
  end
@@ -318,16 +343,16 @@ module ActiveSupport
318
343
 
319
344
  # Store provider interface:
320
345
  # Read an entry from the cache.
321
- def read_entry(key, options = nil)
346
+ def read_entry(key, **options)
322
347
  failsafe :read_entry do
323
348
  raw = options&.fetch(:raw, false)
324
349
  deserialize_entry(redis.with { |c| c.get(key) }, raw: raw)
325
350
  end
326
351
  end
327
352
 
328
- def read_multi_entries(names, _options)
353
+ def read_multi_entries(names, **options)
329
354
  if mget_capable?
330
- read_multi_mget(*names)
355
+ read_multi_mget(*names, **options)
331
356
  else
332
357
  super
333
358
  end
@@ -336,6 +361,7 @@ module ActiveSupport
336
361
  def read_multi_mget(*names)
337
362
  options = names.extract_options!
338
363
  options = merged_options(options)
364
+ return {} if names == []
339
365
  raw = options&.fetch(:raw, false)
340
366
 
341
367
  keys = names.map { |name| normalize_key(name, options) }
@@ -373,13 +399,19 @@ module ActiveSupport
373
399
  modifiers[:nx] = unless_exist
374
400
  modifiers[:px] = (1000 * expires_in.to_f).ceil if expires_in
375
401
 
376
- redis.with { |c| c.set key, serialized_entry, modifiers }
402
+ redis.with { |c| c.set key, serialized_entry, **modifiers }
377
403
  else
378
404
  redis.with { |c| c.set key, serialized_entry }
379
405
  end
380
406
  end
381
407
  end
382
408
 
409
+ def write_key_expiry(client, key, options)
410
+ if options[:expires_in] && client.ttl(key).negative?
411
+ client.expire key, options[:expires_in].to_i
412
+ end
413
+ end
414
+
383
415
  # Delete an entry from the cache.
384
416
  def delete_entry(key, options)
385
417
  failsafe :delete_entry, returning: false do
@@ -387,6 +419,11 @@ module ActiveSupport
387
419
  end
388
420
  end
389
421
 
422
+ # Deletes multiple entries in the cache. Returns the number of entries deleted.
423
+ def delete_multi_entries(entries, **_options)
424
+ redis.with { |c| c.del(entries) }
425
+ end
426
+
390
427
  # Nonstandard store provider API to write multiple values at once.
391
428
  def write_multi_entries(entries, expires_in: nil, **options)
392
429
  if entries.any?
@@ -402,11 +439,11 @@ module ActiveSupport
402
439
 
403
440
  # Truncate keys that exceed 1kB.
404
441
  def normalize_key(key, options)
405
- truncate_key super.b
442
+ truncate_key super&.b
406
443
  end
407
444
 
408
445
  def truncate_key(key)
409
- if key.bytesize > max_key_bytesize
446
+ if key && key.bytesize > max_key_bytesize
410
447
  suffix = ":sha2:#{::Digest::SHA2.hexdigest(key)}"
411
448
  truncate_at = max_key_bytesize - suffix.bytesize
412
449
  "#{key.byteslice(0, truncate_at)}#{suffix}"
@@ -415,21 +452,11 @@ module ActiveSupport
415
452
  end
416
453
  end
417
454
 
418
- def deserialize_entry(serialized_entry, raw:)
419
- if serialized_entry
420
- 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
- entry.is_a?(Entry) ? entry : Entry.new(entry)
455
+ def deserialize_entry(payload, raw:)
456
+ if payload && raw
457
+ Entry.new(payload, compress: false)
458
+ else
459
+ super(payload)
433
460
  end
434
461
  end
435
462
 
@@ -437,7 +464,7 @@ module ActiveSupport
437
464
  if raw
438
465
  entry.value.to_s
439
466
  else
440
- Marshal.dump(entry)
467
+ super(entry)
441
468
  end
442
469
  end
443
470
 
@@ -449,7 +476,7 @@ module ActiveSupport
449
476
 
450
477
  def failsafe(method, returning: nil)
451
478
  yield
452
- rescue ::Redis::BaseConnectionError => e
479
+ rescue ::Redis::BaseError => e
453
480
  handle_exception exception: e, method: method, returning: returning
454
481
  returning
455
482
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/duplicable"
4
3
  require "active_support/core_ext/string/inflections"
5
4
  require "active_support/per_thread_registry"
6
5
 
@@ -50,32 +49,36 @@ module ActiveSupport
50
49
  @data.clear
51
50
  end
52
51
 
53
- def read_entry(key, options)
52
+ def read_entry(key, **options)
54
53
  @data[key]
55
54
  end
56
55
 
57
- def read_multi_entries(keys, options)
56
+ def read_multi_entries(keys, **options)
58
57
  values = {}
59
58
 
60
59
  keys.each do |name|
61
- entry = read_entry(name, options)
60
+ entry = read_entry(name, **options)
62
61
  values[name] = entry.value if entry
63
62
  end
64
63
 
65
64
  values
66
65
  end
67
66
 
68
- def write_entry(key, value, options)
69
- @data[key] = value
67
+ def write_entry(key, entry, **options)
68
+ entry.dup_value!
69
+ @data[key] = entry
70
70
  true
71
71
  end
72
72
 
73
- def delete_entry(key, options)
73
+ def delete_entry(key, **options)
74
74
  !!@data.delete(key)
75
75
  end
76
76
 
77
77
  def fetch_entry(key, options = nil) # :nodoc:
78
- @data.fetch(key) { @data[key] = yield }
78
+ entry = @data.fetch(key) { @data[key] = yield }
79
+ dup_entry = entry.dup
80
+ dup_entry&.dup_value!
81
+ dup_entry
79
82
  end
80
83
  end
81
84
 
@@ -92,77 +95,89 @@ module ActiveSupport
92
95
  local_cache_key)
93
96
  end
94
97
 
95
- def clear(options = nil) # :nodoc:
98
+ def clear(**options) # :nodoc:
96
99
  return super unless cache = local_cache
97
100
  cache.clear(options)
98
101
  super
99
102
  end
100
103
 
101
- def cleanup(options = nil) # :nodoc:
104
+ def cleanup(**options) # :nodoc:
102
105
  return super unless cache = local_cache
103
106
  cache.clear
104
107
  super
105
108
  end
106
109
 
107
- def increment(name, amount = 1, options = nil) # :nodoc:
110
+ def delete_matched(matcher, options = nil) # :nodoc:
111
+ return super unless cache = local_cache
112
+ cache.clear
113
+ super
114
+ end
115
+
116
+ def increment(name, amount = 1, **options) # :nodoc:
108
117
  return super unless local_cache
109
118
  value = bypass_local_cache { super }
110
- write_cache_value(name, value, options)
119
+ write_cache_value(name, value, **options)
111
120
  value
112
121
  end
113
122
 
114
- def decrement(name, amount = 1, options = nil) # :nodoc:
123
+ def decrement(name, amount = 1, **options) # :nodoc:
115
124
  return super unless local_cache
116
125
  value = bypass_local_cache { super }
117
- write_cache_value(name, value, options)
126
+ write_cache_value(name, value, **options)
118
127
  value
119
128
  end
120
129
 
121
130
  private
122
- def read_entry(key, options)
131
+ def read_entry(key, **options)
123
132
  if cache = local_cache
124
- cache.fetch_entry(key) { super }
133
+ hit = true
134
+ value = cache.fetch_entry(key) do
135
+ hit = false
136
+ super
137
+ end
138
+ options[:event][:store] = cache.class.name if hit && options[:event]
139
+ value
125
140
  else
126
141
  super
127
142
  end
128
143
  end
129
144
 
130
- def read_multi_entries(keys, options)
145
+ def read_multi_entries(keys, **options)
131
146
  return super unless local_cache
132
147
 
133
- local_entries = local_cache.read_multi_entries(keys, options)
148
+ local_entries = local_cache.read_multi_entries(keys, **options)
134
149
  missed_keys = keys - local_entries.keys
135
150
 
136
151
  if missed_keys.any?
137
- local_entries.merge!(super(missed_keys, options))
152
+ local_entries.merge!(super(missed_keys, **options))
138
153
  else
139
154
  local_entries
140
155
  end
141
156
  end
142
157
 
143
- def write_entry(key, entry, options)
158
+ def write_entry(key, entry, **options)
144
159
  if options[:unless_exist]
145
- local_cache.delete_entry(key, options) if local_cache
160
+ local_cache.delete_entry(key, **options) if local_cache
146
161
  else
147
- local_cache.write_entry(key, entry, options) if local_cache
162
+ local_cache.write_entry(key, entry, **options) if local_cache
148
163
  end
149
164
 
150
165
  super
151
166
  end
152
167
 
153
- def delete_entry(key, options)
154
- local_cache.delete_entry(key, options) if local_cache
168
+ def delete_entry(key, **options)
169
+ local_cache.delete_entry(key, **options) if local_cache
155
170
  super
156
171
  end
157
172
 
158
- def write_cache_value(name, value, options)
173
+ def write_cache_value(name, value, **options)
159
174
  name = normalize_key(name, options)
160
175
  cache = local_cache
161
176
  cache.mute do
162
177
  if value
163
178
  cache.write(name, value, options)
164
179
  else
165
- cache.delete(name, options)
180
+ cache.delete(name, **options)
166
181
  end
167
182
  end
168
183
  end
@@ -4,10 +4,7 @@ require "active_support/concern"
4
4
  require "active_support/descendants_tracker"
5
5
  require "active_support/core_ext/array/extract_options"
6
6
  require "active_support/core_ext/class/attribute"
7
- require "active_support/core_ext/kernel/reporting"
8
- require "active_support/core_ext/kernel/singleton_class"
9
7
  require "active_support/core_ext/string/filters"
10
- require "active_support/deprecation"
11
8
  require "thread"
12
9
 
13
10
  module ActiveSupport
@@ -23,6 +20,9 @@ module ActiveSupport
23
20
  # +ClassMethods.set_callback+), and run the installed callbacks at the
24
21
  # appropriate times (via +run_callbacks+).
25
22
  #
23
+ # By default callbacks are halted by throwing +:abort+.
24
+ # See +ClassMethods.define_callbacks+ for details.
25
+ #
26
26
  # Three kinds of callbacks are supported: before callbacks, run before a
27
27
  # certain event; after callbacks, run after the event; and around callbacks,
28
28
  # blocks that surround the event, triggering it when they yield. Callback code
@@ -100,32 +100,6 @@ module ActiveSupport
100
100
  env = Filters::Environment.new(self, false, nil)
101
101
  next_sequence = callbacks.compile
102
102
 
103
- invoke_sequence = Proc.new do
104
- skipped = nil
105
- while true
106
- current = next_sequence
107
- current.invoke_before(env)
108
- if current.final?
109
- env.value = !env.halted && (!block_given? || yield)
110
- elsif current.skip?(env)
111
- (skipped ||= []) << current
112
- next_sequence = next_sequence.nested
113
- next
114
- else
115
- next_sequence = next_sequence.nested
116
- begin
117
- target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
118
- target.send(method, *arguments, &block)
119
- ensure
120
- next_sequence = current
121
- end
122
- end
123
- current.invoke_after(env)
124
- skipped.pop.invoke_after(env) while skipped && skipped.first
125
- break env.value
126
- end
127
- end
128
-
129
103
  # Common case: no 'around' callbacks defined
130
104
  if next_sequence.final?
131
105
  next_sequence.invoke_before(env)
@@ -133,17 +107,43 @@ module ActiveSupport
133
107
  next_sequence.invoke_after(env)
134
108
  env.value
135
109
  else
110
+ invoke_sequence = Proc.new do
111
+ skipped = nil
112
+
113
+ while true
114
+ current = next_sequence
115
+ current.invoke_before(env)
116
+ if current.final?
117
+ env.value = !env.halted && (!block_given? || yield)
118
+ elsif current.skip?(env)
119
+ (skipped ||= []) << current
120
+ next_sequence = next_sequence.nested
121
+ next
122
+ else
123
+ next_sequence = next_sequence.nested
124
+ begin
125
+ target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
126
+ target.send(method, *arguments, &block)
127
+ ensure
128
+ next_sequence = current
129
+ end
130
+ end
131
+ current.invoke_after(env)
132
+ skipped.pop.invoke_after(env) while skipped&.first
133
+ break env.value
134
+ end
135
+ end
136
+
136
137
  invoke_sequence.call
137
138
  end
138
139
  end
139
140
  end
140
141
 
141
142
  private
142
-
143
143
  # A hook invoked every time a before callback is halted.
144
144
  # This can be overridden in ActiveSupport::Callbacks implementors in order
145
145
  # to provide better debugging/logging.
146
- def halted_callback_hook(filter)
146
+ def halted_callback_hook(filter, name)
147
147
  end
148
148
 
149
149
  module Conditionals # :nodoc:
@@ -159,17 +159,17 @@ module ActiveSupport
159
159
  Environment = Struct.new(:target, :halted, :value)
160
160
 
161
161
  class Before
162
- def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter)
162
+ def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter, name)
163
163
  halted_lambda = chain_config[:terminator]
164
164
 
165
165
  if user_conditions.any?
166
- halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
166
+ halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
167
167
  else
168
- halting(callback_sequence, user_callback, halted_lambda, filter)
168
+ halting(callback_sequence, user_callback, halted_lambda, filter, name)
169
169
  end
170
170
  end
171
171
 
172
- def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
172
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
173
173
  callback_sequence.before do |env|
174
174
  target = env.target
175
175
  value = env.value
@@ -179,7 +179,7 @@ module ActiveSupport
179
179
  result_lambda = -> { user_callback.call target, value }
180
180
  env.halted = halted_lambda.call(target, result_lambda)
181
181
  if env.halted
182
- target.send :halted_callback_hook, filter
182
+ target.send :halted_callback_hook, filter, name
183
183
  end
184
184
  end
185
185
 
@@ -188,7 +188,7 @@ module ActiveSupport
188
188
  end
189
189
  private_class_method :halting_and_conditional
190
190
 
191
- def self.halting(callback_sequence, user_callback, halted_lambda, filter)
191
+ def self.halting(callback_sequence, user_callback, halted_lambda, filter, name)
192
192
  callback_sequence.before do |env|
193
193
  target = env.target
194
194
  value = env.value
@@ -197,9 +197,8 @@ module ActiveSupport
197
197
  unless halted
198
198
  result_lambda = -> { user_callback.call target, value }
199
199
  env.halted = halted_lambda.call(target, result_lambda)
200
-
201
200
  if env.halted
202
- target.send :halted_callback_hook, filter
201
+ target.send :halted_callback_hook, filter, name
203
202
  end
204
203
  end
205
204
 
@@ -298,8 +297,8 @@ module ActiveSupport
298
297
  @kind = kind
299
298
  @filter = filter
300
299
  @key = compute_identifier filter
301
- @if = check_conditionals(Array(options[:if]))
302
- @unless = check_conditionals(Array(options[:unless]))
300
+ @if = check_conditionals(options[:if])
301
+ @unless = check_conditionals(options[:unless])
303
302
  end
304
303
 
305
304
  def filter; @key; end
@@ -337,7 +336,7 @@ module ActiveSupport
337
336
 
338
337
  case kind
339
338
  when :before
340
- Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter)
339
+ Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter, name)
341
340
  when :after
342
341
  Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config)
343
342
  when :around
@@ -350,7 +349,13 @@ module ActiveSupport
350
349
  end
351
350
 
352
351
  private
352
+ EMPTY_ARRAY = [].freeze
353
+ private_constant :EMPTY_ARRAY
354
+
353
355
  def check_conditionals(conditionals)
356
+ return EMPTY_ARRAY if conditionals.blank?
357
+
358
+ conditionals = Array(conditionals)
354
359
  if conditionals.any? { |c| c.is_a?(String) }
355
360
  raise ArgumentError, <<-MSG.squish
356
361
  Passing string to be evaluated in :if and :unless conditional
@@ -359,7 +364,7 @@ module ActiveSupport
359
364
  MSG
360
365
  end
361
366
 
362
- conditionals
367
+ conditionals.freeze
363
368
  end
364
369
 
365
370
  def compute_identifier(filter)
@@ -401,21 +406,17 @@ module ActiveSupport
401
406
  # The actual invocation is left up to the caller to minimize
402
407
  # call stack pollution.
403
408
  def expand(target, value, block)
404
- result = @arguments.map { |arg|
409
+ expanded = [@override_target || target, @override_block || block, @method_name]
410
+
411
+ @arguments.each do |arg|
405
412
  case arg
406
- when :value; value
407
- when :target; target
408
- when :block; block || raise(ArgumentError)
413
+ when :value then expanded << value
414
+ when :target then expanded << target
415
+ when :block then expanded << (block || raise(ArgumentError))
409
416
  end
410
- }
411
-
412
- result.unshift @method_name
413
- result.unshift @override_block || block
414
- result.unshift @override_target || target
417
+ end
415
418
 
416
- # target, block, method, *arguments = result
417
- # target.send(method, *arguments, &block)
418
- result
419
+ expanded
419
420
  end
420
421
 
421
422
  # Return a lambda that will make this call when given the input
@@ -497,9 +498,7 @@ module ActiveSupport
497
498
  arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) }
498
499
  end
499
500
 
500
- def nested
501
- @nested
502
- end
501
+ attr_reader :nested
503
502
 
504
503
  def final?
505
504
  !@call_template
@@ -578,10 +577,9 @@ module ActiveSupport
578
577
  end
579
578
 
580
579
  protected
581
- def chain; @chain; end
580
+ attr_reader :chain
582
581
 
583
582
  private
584
-
585
583
  def append_one(callback)
586
584
  @callbacks = nil
587
585
  remove_duplicates(callback)
@@ -659,9 +657,17 @@ module ActiveSupport
659
657
  # * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance
660
658
  # method or a proc; the callback will be called only when they all return
661
659
  # a true value.
660
+ #
661
+ # If a proc is given, its body is evaluated in the context of the
662
+ # current object. It can also optionally accept the current object as
663
+ # an argument.
662
664
  # * <tt>:unless</tt> - A symbol or an array of symbols, each naming an
663
665
  # instance method or a proc; the callback will be called only when they
664
666
  # all return a false value.
667
+ #
668
+ # If a proc is given, its body is evaluated in the context of the
669
+ # current object. It can also optionally accept the current object as
670
+ # an argument.
665
671
  # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
666
672
  # existing chain rather than appended.
667
673
  def set_callback(name, *filter_list, &block)
@@ -809,7 +815,9 @@ module ActiveSupport
809
815
  names.each do |name|
810
816
  name = name.to_sym
811
817
 
812
- set_callbacks name, CallbackChain.new(name, options)
818
+ ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
819
+ target.set_callbacks name, CallbackChain.new(name, options)
820
+ end
813
821
 
814
822
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
815
823
  def _run_#{name}_callbacks(&block)
@@ -832,13 +840,22 @@ module ActiveSupport
832
840
  end
833
841
 
834
842
  protected
835
-
836
843
  def get_callbacks(name) # :nodoc:
837
844
  __callbacks[name.to_sym]
838
845
  end
839
846
 
840
- def set_callbacks(name, callbacks) # :nodoc:
841
- self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
847
+ if Module.instance_method(:method_defined?).arity == 1 # Ruby 2.5 and older
848
+ def set_callbacks(name, callbacks) # :nodoc:
849
+ self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
850
+ end
851
+ else # Ruby 2.6 and newer
852
+ def set_callbacks(name, callbacks) # :nodoc:
853
+ unless singleton_class.method_defined?(:__callbacks, false)
854
+ self.__callbacks = __callbacks.dup
855
+ end
856
+ self.__callbacks[name.to_sym] = callbacks
857
+ self.__callbacks
858
+ end
842
859
  end
843
860
  end
844
861
  end