activesupport 5.2.7.1 → 6.1.4.6

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 +399 -434
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +29 -3
  8. data/lib/active_support/benchmarkable.rb +1 -1
  9. data/lib/active_support/cache/file_store.rb +34 -34
  10. data/lib/active_support/cache/mem_cache_store.rb +39 -24
  11. data/lib/active_support/cache/memory_store.rb +59 -33
  12. data/lib/active_support/cache/null_store.rb +8 -3
  13. data/lib/active_support/cache/redis_cache_store.rb +72 -45
  14. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  15. data/lib/active_support/cache.rb +148 -78
  16. data/lib/active_support/callbacks.rb +81 -64
  17. data/lib/active_support/concern.rb +70 -3
  18. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  19. data/lib/active_support/concurrency/share_lock.rb +0 -1
  20. data/lib/active_support/configurable.rb +10 -14
  21. data/lib/active_support/configuration_file.rb +51 -0
  22. data/lib/active_support/core_ext/array/access.rb +18 -6
  23. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  24. data/lib/active_support/core_ext/array/extract.rb +21 -0
  25. data/lib/active_support/core_ext/array.rb +1 -1
  26. data/lib/active_support/core_ext/benchmark.rb +2 -2
  27. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  28. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  29. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  30. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  31. data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
  32. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  33. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  34. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  35. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  36. data/lib/active_support/core_ext/enumerable.rb +171 -75
  37. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  38. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  39. data/lib/active_support/core_ext/hash/except.rb +2 -2
  40. data/lib/active_support/core_ext/hash/keys.rb +1 -30
  41. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  42. data/lib/active_support/core_ext/hash.rb +1 -2
  43. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  44. data/lib/active_support/core_ext/kernel.rb +0 -1
  45. data/lib/active_support/core_ext/load_error.rb +1 -1
  46. data/lib/active_support/core_ext/marshal.rb +2 -0
  47. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  48. data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
  49. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
  50. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  51. data/lib/active_support/core_ext/module/delegation.rb +76 -33
  52. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  53. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  54. data/lib/active_support/core_ext/module.rb +0 -1
  55. data/lib/active_support/core_ext/name_error.rb +29 -2
  56. data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
  57. data/lib/active_support/core_ext/numeric.rb +0 -1
  58. data/lib/active_support/core_ext/object/blank.rb +1 -2
  59. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  60. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  61. data/lib/active_support/core_ext/object/json.rb +14 -2
  62. data/lib/active_support/core_ext/object/try.rb +17 -7
  63. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  64. data/lib/active_support/core_ext/range/compare_range.rb +34 -13
  65. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  66. data/lib/active_support/core_ext/range/each.rb +0 -1
  67. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  68. data/lib/active_support/core_ext/regexp.rb +8 -5
  69. data/lib/active_support/core_ext/securerandom.rb +23 -3
  70. data/lib/active_support/core_ext/string/access.rb +5 -16
  71. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  72. data/lib/active_support/core_ext/string/filters.rb +42 -1
  73. data/lib/active_support/core_ext/string/inflections.rb +45 -6
  74. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  75. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  76. data/lib/active_support/core_ext/string/output_safety.rb +70 -41
  77. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  78. data/lib/active_support/core_ext/string/strip.rb +3 -1
  79. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  80. data/lib/active_support/core_ext/symbol.rb +3 -0
  81. data/lib/active_support/core_ext/time/calculations.rb +51 -3
  82. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  83. data/lib/active_support/core_ext/uri.rb +6 -1
  84. data/lib/active_support/core_ext.rb +1 -1
  85. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  86. data/lib/active_support/current_attributes.rb +16 -2
  87. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  88. data/lib/active_support/dependencies.rb +109 -34
  89. data/lib/active_support/deprecation/behaviors.rb +16 -3
  90. data/lib/active_support/deprecation/disallowed.rb +56 -0
  91. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  92. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  93. data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
  94. data/lib/active_support/deprecation/reporting.rb +50 -7
  95. data/lib/active_support/deprecation.rb +6 -1
  96. data/lib/active_support/descendants_tracker.rb +59 -9
  97. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  98. data/lib/active_support/duration/iso8601_serializer.rb +18 -14
  99. data/lib/active_support/duration.rb +78 -30
  100. data/lib/active_support/encrypted_configuration.rb +0 -4
  101. data/lib/active_support/encrypted_file.rb +22 -4
  102. data/lib/active_support/environment_inquirer.rb +20 -0
  103. data/lib/active_support/evented_file_update_checker.rb +82 -117
  104. data/lib/active_support/execution_wrapper.rb +2 -1
  105. data/lib/active_support/file_update_checker.rb +0 -1
  106. data/lib/active_support/fork_tracker.rb +64 -0
  107. data/lib/active_support/gem_version.rb +4 -4
  108. data/lib/active_support/hash_with_indifferent_access.rb +70 -42
  109. data/lib/active_support/i18n.rb +1 -0
  110. data/lib/active_support/i18n_railtie.rb +15 -8
  111. data/lib/active_support/inflector/inflections.rb +2 -7
  112. data/lib/active_support/inflector/methods.rb +49 -58
  113. data/lib/active_support/inflector/transliterate.rb +47 -18
  114. data/lib/active_support/json/decoding.rb +25 -26
  115. data/lib/active_support/json/encoding.rb +11 -3
  116. data/lib/active_support/key_generator.rb +1 -33
  117. data/lib/active_support/lazy_load_hooks.rb +5 -2
  118. data/lib/active_support/locale/en.rb +33 -0
  119. data/lib/active_support/locale/en.yml +7 -3
  120. data/lib/active_support/log_subscriber.rb +39 -9
  121. data/lib/active_support/logger.rb +2 -17
  122. data/lib/active_support/logger_silence.rb +11 -19
  123. data/lib/active_support/logger_thread_safe_level.rb +50 -6
  124. data/lib/active_support/message_encryptor.rb +8 -13
  125. data/lib/active_support/message_verifier.rb +10 -10
  126. data/lib/active_support/messages/metadata.rb +11 -2
  127. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  128. data/lib/active_support/messages/rotator.rb +10 -9
  129. data/lib/active_support/multibyte/chars.rb +10 -68
  130. data/lib/active_support/multibyte/unicode.rb +15 -327
  131. data/lib/active_support/notifications/fanout.rb +116 -16
  132. data/lib/active_support/notifications/instrumenter.rb +71 -9
  133. data/lib/active_support/notifications.rb +72 -8
  134. data/lib/active_support/number_helper/number_converter.rb +5 -6
  135. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  136. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  137. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  138. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
  139. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  140. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  141. data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
  142. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  143. data/lib/active_support/number_helper.rb +38 -12
  144. data/lib/active_support/option_merger.rb +22 -3
  145. data/lib/active_support/ordered_hash.rb +1 -1
  146. data/lib/active_support/ordered_options.rb +13 -3
  147. data/lib/active_support/parameter_filter.rb +133 -0
  148. data/lib/active_support/per_thread_registry.rb +1 -1
  149. data/lib/active_support/rails.rb +1 -10
  150. data/lib/active_support/railtie.rb +23 -1
  151. data/lib/active_support/reloader.rb +4 -5
  152. data/lib/active_support/rescuable.rb +4 -4
  153. data/lib/active_support/secure_compare_rotator.rb +51 -0
  154. data/lib/active_support/security_utils.rb +19 -12
  155. data/lib/active_support/string_inquirer.rb +4 -3
  156. data/lib/active_support/subscriber.rb +72 -28
  157. data/lib/active_support/tagged_logging.rb +42 -8
  158. data/lib/active_support/test_case.rb +91 -0
  159. data/lib/active_support/testing/assertions.rb +30 -9
  160. data/lib/active_support/testing/deprecation.rb +0 -1
  161. data/lib/active_support/testing/file_fixtures.rb +2 -0
  162. data/lib/active_support/testing/isolation.rb +2 -2
  163. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  164. data/lib/active_support/testing/parallelization/server.rb +78 -0
  165. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  166. data/lib/active_support/testing/parallelization.rb +51 -0
  167. data/lib/active_support/testing/stream.rb +1 -2
  168. data/lib/active_support/testing/time_helpers.rb +47 -12
  169. data/lib/active_support/time_with_zone.rb +81 -47
  170. data/lib/active_support/values/time_zone.rb +32 -17
  171. data/lib/active_support/xml_mini/jdom.rb +2 -3
  172. data/lib/active_support/xml_mini/libxml.rb +2 -2
  173. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  174. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  175. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  176. data/lib/active_support/xml_mini/rexml.rb +10 -3
  177. data/lib/active_support/xml_mini.rb +2 -10
  178. data/lib/active_support.rb +14 -1
  179. metadata +55 -29
  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
@@ -3,10 +3,12 @@
3
3
  require "zlib"
4
4
  require "active_support/core_ext/array/extract_options"
5
5
  require "active_support/core_ext/array/wrap"
6
+ require "active_support/core_ext/enumerable"
6
7
  require "active_support/core_ext/module/attribute_accessors"
7
8
  require "active_support/core_ext/numeric/bytes"
8
9
  require "active_support/core_ext/numeric/time"
9
10
  require "active_support/core_ext/object/to_param"
11
+ require "active_support/core_ext/object/try"
10
12
  require "active_support/core_ext/string/inflections"
11
13
 
12
14
  module ActiveSupport
@@ -20,7 +22,7 @@ module ActiveSupport
20
22
 
21
23
  # These options mean something to all cache implementations. Individual cache
22
24
  # implementations may support additional options.
23
- UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl]
25
+ UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder]
24
26
 
25
27
  module Strategy
26
28
  autoload :LocalCache, "active_support/cache/strategy/local_cache"
@@ -52,12 +54,19 @@ module ActiveSupport
52
54
  #
53
55
  # ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
54
56
  # # => returns MyOwnCacheStore.new
55
- def lookup_store(*store_option)
56
- store, *parameters = *Array.wrap(store_option).flatten
57
-
57
+ def lookup_store(store = nil, *parameters)
58
58
  case store
59
59
  when Symbol
60
- retrieve_store_class(store).new(*parameters)
60
+ options = parameters.extract_options!
61
+ # clean this up once Ruby 2.7 support is dropped
62
+ # see https://github.com/rails/rails/pull/41522#discussion_r581186602
63
+ if options.empty?
64
+ retrieve_store_class(store).new(*parameters)
65
+ else
66
+ retrieve_store_class(store).new(*parameters, **options)
67
+ end
68
+ when Array
69
+ lookup_store(*store)
61
70
  when nil
62
71
  ActiveSupport::Cache::MemoryStore.new
63
72
  else
@@ -78,7 +87,7 @@ module ActiveSupport
78
87
  #
79
88
  # The +key+ argument can also respond to +cache_key+ or +to_param+.
80
89
  def expand_cache_key(key, namespace = nil)
81
- expanded_cache_key = (namespace ? "#{namespace}/" : "").dup
90
+ expanded_cache_key = namespace ? +"#{namespace}/" : +""
82
91
 
83
92
  if prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
84
93
  expanded_cache_key << "#{prefix}/"
@@ -155,6 +164,8 @@ module ActiveSupport
155
164
  # threshold is configurable with the <tt>:compress_threshold</tt> option,
156
165
  # specified in bytes.
157
166
  class Store
167
+ DEFAULT_CODER = Marshal
168
+
158
169
  cattr_accessor :logger, instance_writer: true
159
170
 
160
171
  attr_reader :silence, :options
@@ -182,6 +193,7 @@ module ActiveSupport
182
193
  # namespace for the cache.
183
194
  def initialize(options = nil)
184
195
  @options = options ? options.dup : {}
196
+ @coder = @options.delete(:coder) { self.class::DEFAULT_CODER } || NullCoder
185
197
  end
186
198
 
187
199
  # Silences the logger.
@@ -229,6 +241,14 @@ module ActiveSupport
229
241
  # ask whether you should force a cache write. Otherwise, it's clearer to
230
242
  # just call <tt>Cache#write</tt>.
231
243
  #
244
+ # Setting <tt>skip_nil: true</tt> will not cache nil result:
245
+ #
246
+ # cache.fetch('foo') { nil }
247
+ # cache.fetch('bar', skip_nil: true) { nil }
248
+ # cache.exist?('foo') # => true
249
+ # cache.exist?('bar') # => false
250
+ #
251
+ #
232
252
  # Setting <tt>compress: false</tt> disables compression of the cache entry.
233
253
  #
234
254
  # Setting <tt>:expires_in</tt> will set an expiration time on the cache.
@@ -303,14 +323,14 @@ module ActiveSupport
303
323
  # :bar
304
324
  # end
305
325
  # cache.fetch('foo') # => "bar"
306
- def fetch(name, options = nil)
326
+ def fetch(name, options = nil, &block)
307
327
  if block_given?
308
328
  options = merged_options(options)
309
329
  key = normalize_key(name, options)
310
330
 
311
331
  entry = nil
312
332
  instrument(:read, name, options) do |payload|
313
- cached_entry = read_entry(key, options) unless options[:force]
333
+ cached_entry = read_entry(key, **options, event: payload) unless options[:force]
314
334
  entry = handle_expired_entry(cached_entry, key, options)
315
335
  entry = nil if entry && entry.mismatched?(normalize_version(name, options))
316
336
  payload[:super_operation] = :fetch if payload
@@ -320,7 +340,7 @@ module ActiveSupport
320
340
  if entry
321
341
  get_entry_value(entry, name, options)
322
342
  else
323
- save_block_result_to_cache(name, options) { |_name| yield _name }
343
+ save_block_result_to_cache(name, options, &block)
324
344
  end
325
345
  elsif options && options[:force]
326
346
  raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
@@ -333,8 +353,9 @@ module ActiveSupport
333
353
  # the cache with the given key, then that data is returned. Otherwise,
334
354
  # +nil+ is returned.
335
355
  #
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.
356
+ # Note, if data was written with the <tt>:expires_in</tt> or
357
+ # <tt>:version</tt> options, both of these conditions are applied before
358
+ # the data is returned.
338
359
  #
339
360
  # Options are passed to the underlying cache implementation.
340
361
  def read(name, options = nil)
@@ -343,11 +364,11 @@ module ActiveSupport
343
364
  version = normalize_version(name, options)
344
365
 
345
366
  instrument(:read, name, options) do |payload|
346
- entry = read_entry(key, options)
367
+ entry = read_entry(key, **options, event: payload)
347
368
 
348
369
  if entry
349
370
  if entry.expired?
350
- delete_entry(key, options)
371
+ delete_entry(key, **options)
351
372
  payload[:hit] = false if payload
352
373
  nil
353
374
  elsif entry.mismatched?(version)
@@ -375,7 +396,7 @@ module ActiveSupport
375
396
  options = merged_options(options)
376
397
 
377
398
  instrument :read_multi, names, options do |payload|
378
- read_multi_entries(names, options).tap do |results|
399
+ read_multi_entries(names, **options, event: payload).tap do |results|
379
400
  payload[:hits] = results.keys
380
401
  end
381
402
  end
@@ -387,10 +408,10 @@ module ActiveSupport
387
408
 
388
409
  instrument :write_multi, hash, options do |payload|
389
410
  entries = hash.each_with_object({}) do |(name, value), memo|
390
- memo[normalize_key(name, options)] = Entry.new(value, options.merge(version: normalize_version(name, options)))
411
+ memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options)))
391
412
  end
392
413
 
393
- write_multi_entries entries, options
414
+ write_multi_entries entries, **options
394
415
  end
395
416
  end
396
417
 
@@ -402,8 +423,6 @@ module ActiveSupport
402
423
  # to the cache. If you do not want to write the cache when the cache is
403
424
  # not found, use #read_multi.
404
425
  #
405
- # Options are passed to the underlying cache implementation.
406
- #
407
426
  # Returns a hash with the data for each of the names. For example:
408
427
  #
409
428
  # cache.write("bim", "bam")
@@ -413,6 +432,17 @@ module ActiveSupport
413
432
  # # => { "bim" => "bam",
414
433
  # # "unknown_key" => "Fallback value for key: unknown_key" }
415
434
  #
435
+ # Options are passed to the underlying cache implementation. For example:
436
+ #
437
+ # cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
438
+ # "buzz"
439
+ # end
440
+ # # => {"fizz"=>"buzz"}
441
+ # cache.read("fizz")
442
+ # # => "buzz"
443
+ # sleep(6)
444
+ # cache.read("fizz")
445
+ # # => nil
416
446
  def fetch_multi(*names)
417
447
  raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given?
418
448
 
@@ -420,18 +450,18 @@ module ActiveSupport
420
450
  options = merged_options(options)
421
451
 
422
452
  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
453
+ reads = read_multi_entries(names, **options)
454
+ writes = {}
455
+ ordered = names.index_with do |name|
456
+ reads.fetch(name) { writes[name] = yield(name) }
457
+ end
426
458
 
427
- writes = {}
459
+ payload[:hits] = reads.keys
460
+ payload[:super_operation] = :fetch_multi
428
461
 
429
- (names - results.keys).each do |name|
430
- results[name] = writes[name] = yield(name)
431
- end
462
+ write_multi(writes, options)
432
463
 
433
- write_multi writes, options
434
- end
464
+ ordered
435
465
  end
436
466
  end
437
467
 
@@ -442,8 +472,8 @@ module ActiveSupport
442
472
  options = merged_options(options)
443
473
 
444
474
  instrument(:write, name, options) do
445
- entry = Entry.new(value, options.merge(version: normalize_version(name, options)))
446
- write_entry(normalize_key(name, options), entry, options)
475
+ entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
476
+ write_entry(normalize_key(name, options), entry, **options)
447
477
  end
448
478
  end
449
479
 
@@ -454,7 +484,19 @@ module ActiveSupport
454
484
  options = merged_options(options)
455
485
 
456
486
  instrument(:delete, name) do
457
- delete_entry(normalize_key(name, options), options)
487
+ delete_entry(normalize_key(name, options), **options)
488
+ end
489
+ end
490
+
491
+ # Deletes multiple entries in the cache.
492
+ #
493
+ # Options are passed to the underlying cache implementation.
494
+ def delete_multi(names, options = nil)
495
+ options = merged_options(options)
496
+ names.map! { |key| normalize_key(key, options) }
497
+
498
+ instrument :delete_multi, names do
499
+ delete_multi_entries(names, **options)
458
500
  end
459
501
  end
460
502
 
@@ -464,8 +506,8 @@ module ActiveSupport
464
506
  def exist?(name, options = nil)
465
507
  options = merged_options(options)
466
508
 
467
- instrument(:exist?, name) do
468
- entry = read_entry(normalize_key(name, options), options)
509
+ instrument(:exist?, name) do |payload|
510
+ entry = read_entry(normalize_key(name, options), **options, event: payload)
469
511
  (entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
470
512
  end
471
513
  end
@@ -474,7 +516,7 @@ module ActiveSupport
474
516
  #
475
517
  # Options are passed to the underlying cache implementation.
476
518
  #
477
- # All implementations may not support this method.
519
+ # Some implementations may not support this method.
478
520
  def delete_matched(matcher, options = nil)
479
521
  raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
480
522
  end
@@ -483,7 +525,7 @@ module ActiveSupport
483
525
  #
484
526
  # Options are passed to the underlying cache implementation.
485
527
  #
486
- # All implementations may not support this method.
528
+ # Some implementations may not support this method.
487
529
  def increment(name, amount = 1, options = nil)
488
530
  raise NotImplementedError.new("#{self.class.name} does not support increment")
489
531
  end
@@ -492,7 +534,7 @@ module ActiveSupport
492
534
  #
493
535
  # Options are passed to the underlying cache implementation.
494
536
  #
495
- # All implementations may not support this method.
537
+ # Some implementations may not support this method.
496
538
  def decrement(name, amount = 1, options = nil)
497
539
  raise NotImplementedError.new("#{self.class.name} does not support decrement")
498
540
  end
@@ -501,7 +543,7 @@ module ActiveSupport
501
543
  #
502
544
  # Options are passed to the underlying cache implementation.
503
545
  #
504
- # All implementations may not support this method.
546
+ # Some implementations may not support this method.
505
547
  def cleanup(options = nil)
506
548
  raise NotImplementedError.new("#{self.class.name} does not support cleanup")
507
549
  end
@@ -511,7 +553,7 @@ module ActiveSupport
511
553
  #
512
554
  # The options hash is passed to the underlying cache implementation.
513
555
  #
514
- # All implementations may not support this method.
556
+ # Some implementations may not support this method.
515
557
  def clear(options = nil)
516
558
  raise NotImplementedError.new("#{self.class.name} does not support clear")
517
559
  end
@@ -538,58 +580,73 @@ module ActiveSupport
538
580
 
539
581
  # Reads an entry from the cache implementation. Subclasses must implement
540
582
  # this method.
541
- def read_entry(key, options)
583
+ def read_entry(key, **options)
542
584
  raise NotImplementedError.new
543
585
  end
544
586
 
545
587
  # Writes an entry to the cache implementation. Subclasses must implement
546
588
  # this method.
547
- def write_entry(key, entry, options)
589
+ def write_entry(key, entry, **options)
548
590
  raise NotImplementedError.new
549
591
  end
550
592
 
593
+ def serialize_entry(entry)
594
+ @coder.dump(entry)
595
+ end
596
+
597
+ def deserialize_entry(payload)
598
+ payload.nil? ? nil : @coder.load(payload)
599
+ end
600
+
551
601
  # Reads multiple entries from the cache implementation. Subclasses MAY
552
602
  # implement this method.
553
- def read_multi_entries(names, options)
554
- results = {}
555
- names.each do |name|
556
- key = normalize_key(name, options)
603
+ def read_multi_entries(names, **options)
604
+ names.each_with_object({}) do |name, results|
605
+ key = normalize_key(name, options)
606
+ entry = read_entry(key, **options)
607
+
608
+ next unless entry
609
+
557
610
  version = normalize_version(name, options)
558
- entry = read_entry(key, options)
559
-
560
- if entry
561
- if entry.expired?
562
- delete_entry(key, options)
563
- elsif entry.mismatched?(version)
564
- # Skip mismatched versions
565
- else
566
- results[name] = entry.value
567
- end
611
+
612
+ if entry.expired?
613
+ delete_entry(key, **options)
614
+ elsif !entry.mismatched?(version)
615
+ results[name] = entry.value
568
616
  end
569
617
  end
570
- results
571
618
  end
572
619
 
573
620
  # Writes multiple entries to the cache implementation. Subclasses MAY
574
621
  # implement this method.
575
- def write_multi_entries(hash, options)
622
+ def write_multi_entries(hash, **options)
576
623
  hash.each do |key, entry|
577
- write_entry key, entry, options
624
+ write_entry key, entry, **options
578
625
  end
579
626
  end
580
627
 
581
628
  # Deletes an entry from the cache implementation. Subclasses must
582
629
  # implement this method.
583
- def delete_entry(key, options)
630
+ def delete_entry(key, **options)
584
631
  raise NotImplementedError.new
585
632
  end
586
633
 
634
+ # Deletes multiples entries in the cache implementation. Subclasses MAY
635
+ # implement this method.
636
+ def delete_multi_entries(entries, **options)
637
+ entries.count { |key| delete_entry(key, **options) }
638
+ end
639
+
587
640
  # Merges the default options with ones specific to a method call.
588
641
  def merged_options(call_options)
589
642
  if call_options
590
- options.merge(call_options)
643
+ if options.empty?
644
+ call_options
645
+ else
646
+ options.merge(call_options)
647
+ end
591
648
  else
592
- options.dup
649
+ options
593
650
  end
594
651
  end
595
652
 
@@ -616,6 +673,10 @@ module ActiveSupport
616
673
  namespace = namespace.call
617
674
  end
618
675
 
676
+ if key && key.encoding != Encoding::UTF_8
677
+ key = key.dup.force_encoding(Encoding::UTF_8)
678
+ end
679
+
619
680
  if namespace
620
681
  "#{namespace}:#{key}"
621
682
  else
@@ -632,15 +693,15 @@ module ActiveSupport
632
693
  case key
633
694
  when Array
634
695
  if key.size > 1
635
- key = key.collect { |element| expanded_key(element) }
696
+ key.collect { |element| expanded_key(element) }
636
697
  else
637
- key = key.first
698
+ expanded_key(key.first)
638
699
  end
639
700
  when Hash
640
- key = key.sort_by { |k, _| k.to_s }.collect { |k, v| "#{k}=#{v}" }
641
- end
642
-
643
- key.to_param
701
+ key.collect { |k, v| "#{k}=#{v}" }.sort!
702
+ else
703
+ key
704
+ end.to_param
644
705
  end
645
706
 
646
707
  def normalize_version(key, options = nil)
@@ -650,24 +711,21 @@ module ActiveSupport
650
711
  def expanded_version(key)
651
712
  case
652
713
  when key.respond_to?(:cache_version) then key.cache_version.to_param
653
- when key.is_a?(Array) then key.map { |element| expanded_version(element) }.compact.to_param
714
+ when key.is_a?(Array) then key.map { |element| expanded_version(element) }.tap(&:compact!).to_param
654
715
  when key.respond_to?(:to_a) then expanded_version(key.to_a)
655
716
  end
656
717
  end
657
718
 
658
719
  def instrument(operation, key, options = nil)
659
- log { "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}" }
720
+ if logger && logger.debug? && !silence?
721
+ logger.debug "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}"
722
+ end
660
723
 
661
- payload = { key: key }
724
+ payload = { key: key, store: self.class.name }
662
725
  payload.merge!(options) if options.is_a?(Hash)
663
726
  ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) }
664
727
  end
665
728
 
666
- def log
667
- return unless logger && logger.debug? && !silence?
668
- logger.debug(yield)
669
- end
670
-
671
729
  def handle_expired_entry(entry, key, options)
672
730
  if entry && entry.expired?
673
731
  race_ttl = options[:race_condition_ttl].to_i
@@ -677,7 +735,7 @@ module ActiveSupport
677
735
  entry.expires_at = Time.now + race_ttl
678
736
  write_entry(key, entry, expires_in: race_ttl * 2)
679
737
  else
680
- delete_entry(key, options)
738
+ delete_entry(key, **options)
681
739
  end
682
740
  entry = nil
683
741
  end
@@ -685,7 +743,7 @@ module ActiveSupport
685
743
  end
686
744
 
687
745
  def get_entry_value(entry, name, options)
688
- instrument(:fetch_hit, name, options) {}
746
+ instrument(:fetch_hit, name, options) { }
689
747
  entry.value
690
748
  end
691
749
 
@@ -694,11 +752,23 @@ module ActiveSupport
694
752
  yield(name)
695
753
  end
696
754
 
697
- write(name, result, options)
755
+ write(name, result, options) unless result.nil? && options[:skip_nil]
698
756
  result
699
757
  end
700
758
  end
701
759
 
760
+ module NullCoder # :nodoc:
761
+ class << self
762
+ def load(payload)
763
+ payload
764
+ end
765
+
766
+ def dump(entry)
767
+ entry
768
+ end
769
+ end
770
+ end
771
+
702
772
  # This class is used to represent cache entries. Cache entries have a value, an optional
703
773
  # expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
704
774
  # on the cache. The version is used to support the :version option on the cache for rejecting
@@ -749,8 +819,8 @@ module ActiveSupport
749
819
  end
750
820
 
751
821
  # Returns the size of the cached value. This could be less than
752
- # <tt>value.size</tt> if the data is compressed.
753
- def size
822
+ # <tt>value.bytesize</tt> if the data is compressed.
823
+ def bytesize
754
824
  case value
755
825
  when NilClass
756
826
  0