activesupport 5.2.5 → 6.0.4.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +452 -398
  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/backtrace_cleaner.rb +27 -1
  7. data/lib/active_support/cache/file_store.rb +32 -32
  8. data/lib/active_support/cache/mem_cache_store.rb +12 -7
  9. data/lib/active_support/cache/memory_store.rb +15 -9
  10. data/lib/active_support/cache/null_store.rb +8 -3
  11. data/lib/active_support/cache/redis_cache_store.rb +47 -20
  12. data/lib/active_support/cache/strategy/local_cache.rb +22 -22
  13. data/lib/active_support/cache.rb +71 -48
  14. data/lib/active_support/callbacks.rb +16 -8
  15. data/lib/active_support/concern.rb +24 -1
  16. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  17. data/lib/active_support/concurrency/share_lock.rb +0 -1
  18. data/lib/active_support/configurable.rb +7 -11
  19. data/lib/active_support/core_ext/array/access.rb +18 -6
  20. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  21. data/lib/active_support/core_ext/array/extract.rb +21 -0
  22. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  23. data/lib/active_support/core_ext/array.rb +1 -1
  24. data/lib/active_support/core_ext/class/attribute.rb +11 -16
  25. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  26. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  27. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
  28. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  29. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  30. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  31. data/lib/active_support/core_ext/enumerable.rb +97 -73
  32. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  33. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  34. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  35. data/lib/active_support/core_ext/hash/except.rb +2 -2
  36. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  37. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  38. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  39. data/lib/active_support/core_ext/hash.rb +1 -2
  40. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  41. data/lib/active_support/core_ext/kernel.rb +0 -1
  42. data/lib/active_support/core_ext/load_error.rb +1 -1
  43. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
  44. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
  45. data/lib/active_support/core_ext/module/delegation.rb +41 -8
  46. data/lib/active_support/core_ext/module/introspection.rb +38 -13
  47. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  48. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  49. data/lib/active_support/core_ext/module.rb +0 -1
  50. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  51. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  52. data/lib/active_support/core_ext/numeric.rb +0 -1
  53. data/lib/active_support/core_ext/object/blank.rb +1 -2
  54. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  55. data/lib/active_support/core_ext/object/json.rb +2 -1
  56. data/lib/active_support/core_ext/object/try.rb +17 -7
  57. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  58. data/lib/active_support/core_ext/range/compare_range.rb +28 -13
  59. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  60. data/lib/active_support/core_ext/range/each.rb +0 -1
  61. data/lib/active_support/core_ext/range/include_range.rb +6 -0
  62. data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
  63. data/lib/active_support/core_ext/regexp.rb +0 -4
  64. data/lib/active_support/core_ext/securerandom.rb +23 -3
  65. data/lib/active_support/core_ext/string/access.rb +8 -0
  66. data/lib/active_support/core_ext/string/filters.rb +42 -1
  67. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  68. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  69. data/lib/active_support/core_ext/string/output_safety.rb +68 -10
  70. data/lib/active_support/core_ext/string/strip.rb +3 -1
  71. data/lib/active_support/core_ext/time/calculations.rb +34 -3
  72. data/lib/active_support/core_ext/uri.rb +1 -0
  73. data/lib/active_support/current_attributes.rb +8 -0
  74. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  75. data/lib/active_support/dependencies.rb +74 -18
  76. data/lib/active_support/deprecation/behaviors.rb +1 -1
  77. data/lib/active_support/deprecation/method_wrappers.rb +17 -23
  78. data/lib/active_support/deprecation/proxy_wrappers.rb +28 -5
  79. data/lib/active_support/deprecation.rb +1 -1
  80. data/lib/active_support/descendants_tracker.rb +55 -9
  81. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  82. data/lib/active_support/duration/iso8601_serializer.rb +3 -5
  83. data/lib/active_support/duration.rb +7 -8
  84. data/lib/active_support/encrypted_configuration.rb +0 -4
  85. data/lib/active_support/encrypted_file.rb +3 -2
  86. data/lib/active_support/evented_file_update_checker.rb +39 -10
  87. data/lib/active_support/execution_wrapper.rb +1 -0
  88. data/lib/active_support/file_update_checker.rb +0 -1
  89. data/lib/active_support/gem_version.rb +4 -4
  90. data/lib/active_support/hash_with_indifferent_access.rb +22 -18
  91. data/lib/active_support/i18n.rb +1 -0
  92. data/lib/active_support/i18n_railtie.rb +13 -1
  93. data/lib/active_support/inflector/inflections.rb +1 -5
  94. data/lib/active_support/inflector/methods.rb +16 -29
  95. data/lib/active_support/inflector/transliterate.rb +47 -18
  96. data/lib/active_support/json/decoding.rb +23 -24
  97. data/lib/active_support/json/encoding.rb +6 -2
  98. data/lib/active_support/key_generator.rb +0 -32
  99. data/lib/active_support/lazy_load_hooks.rb +5 -2
  100. data/lib/active_support/locale/en.rb +33 -0
  101. data/lib/active_support/log_subscriber.rb +31 -9
  102. data/lib/active_support/logger.rb +1 -16
  103. data/lib/active_support/logger_silence.rb +28 -12
  104. data/lib/active_support/logger_thread_safe_level.rb +26 -4
  105. data/lib/active_support/message_encryptor.rb +4 -6
  106. data/lib/active_support/message_verifier.rb +5 -5
  107. data/lib/active_support/messages/metadata.rb +11 -2
  108. data/lib/active_support/messages/rotator.rb +4 -4
  109. data/lib/active_support/multibyte/chars.rb +29 -49
  110. data/lib/active_support/multibyte/unicode.rb +44 -282
  111. data/lib/active_support/notifications/fanout.rb +98 -13
  112. data/lib/active_support/notifications/instrumenter.rb +80 -9
  113. data/lib/active_support/notifications.rb +41 -4
  114. data/lib/active_support/number_helper/number_converter.rb +4 -5
  115. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  116. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  117. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -2
  118. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -2
  119. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  120. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  121. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -4
  122. data/lib/active_support/number_helper/rounding_helper.rb +1 -1
  123. data/lib/active_support/number_helper.rb +11 -0
  124. data/lib/active_support/option_merger.rb +21 -3
  125. data/lib/active_support/ordered_hash.rb +1 -1
  126. data/lib/active_support/ordered_options.rb +5 -1
  127. data/lib/active_support/parameter_filter.rb +128 -0
  128. data/lib/active_support/rails.rb +0 -6
  129. data/lib/active_support/reloader.rb +4 -5
  130. data/lib/active_support/security_utils.rb +1 -1
  131. data/lib/active_support/string_inquirer.rb +0 -1
  132. data/lib/active_support/subscriber.rb +65 -26
  133. data/lib/active_support/tagged_logging.rb +13 -4
  134. data/lib/active_support/test_case.rb +91 -0
  135. data/lib/active_support/testing/assertions.rb +15 -1
  136. data/lib/active_support/testing/deprecation.rb +0 -1
  137. data/lib/active_support/testing/file_fixtures.rb +2 -0
  138. data/lib/active_support/testing/isolation.rb +2 -2
  139. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  140. data/lib/active_support/testing/parallelization.rb +134 -0
  141. data/lib/active_support/testing/stream.rb +1 -2
  142. data/lib/active_support/testing/time_helpers.rb +7 -9
  143. data/lib/active_support/time_with_zone.rb +15 -5
  144. data/lib/active_support/values/time_zone.rb +12 -7
  145. data/lib/active_support/xml_mini/jdom.rb +2 -3
  146. data/lib/active_support/xml_mini/libxml.rb +2 -2
  147. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  148. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  149. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  150. data/lib/active_support/xml_mini/rexml.rb +2 -2
  151. data/lib/active_support/xml_mini.rb +2 -10
  152. data/lib/active_support.rb +2 -1
  153. metadata +40 -12
  154. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  155. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -50,27 +50,27 @@ module ActiveSupport
50
50
  @data.clear
51
51
  end
52
52
 
53
- def read_entry(key, options)
53
+ def read_entry(key, **options)
54
54
  @data[key]
55
55
  end
56
56
 
57
- def read_multi_entries(keys, options)
57
+ def read_multi_entries(keys, **options)
58
58
  values = {}
59
59
 
60
60
  keys.each do |name|
61
- entry = read_entry(name, options)
61
+ entry = read_entry(name, **options)
62
62
  values[name] = entry.value if entry
63
63
  end
64
64
 
65
65
  values
66
66
  end
67
67
 
68
- def write_entry(key, value, options)
68
+ def write_entry(key, value, **options)
69
69
  @data[key] = value
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
 
@@ -92,34 +92,34 @@ module ActiveSupport
92
92
  local_cache_key)
93
93
  end
94
94
 
95
- def clear(options = nil) # :nodoc:
95
+ def clear(**options) # :nodoc:
96
96
  return super unless cache = local_cache
97
97
  cache.clear(options)
98
98
  super
99
99
  end
100
100
 
101
- def cleanup(options = nil) # :nodoc:
101
+ def cleanup(**options) # :nodoc:
102
102
  return super unless cache = local_cache
103
103
  cache.clear
104
104
  super
105
105
  end
106
106
 
107
- def increment(name, amount = 1, options = nil) # :nodoc:
107
+ def increment(name, amount = 1, **options) # :nodoc:
108
108
  return super unless local_cache
109
109
  value = bypass_local_cache { super }
110
- write_cache_value(name, value, options)
110
+ write_cache_value(name, value, **options)
111
111
  value
112
112
  end
113
113
 
114
- def decrement(name, amount = 1, options = nil) # :nodoc:
114
+ def decrement(name, amount = 1, **options) # :nodoc:
115
115
  return super unless local_cache
116
116
  value = bypass_local_cache { super }
117
- write_cache_value(name, value, options)
117
+ write_cache_value(name, value, **options)
118
118
  value
119
119
  end
120
120
 
121
121
  private
122
- def read_entry(key, options)
122
+ def read_entry(key, **options)
123
123
  if cache = local_cache
124
124
  cache.fetch_entry(key) { super }
125
125
  else
@@ -127,42 +127,42 @@ module ActiveSupport
127
127
  end
128
128
  end
129
129
 
130
- def read_multi_entries(keys, options)
130
+ def read_multi_entries(keys, **options)
131
131
  return super unless local_cache
132
132
 
133
- local_entries = local_cache.read_multi_entries(keys, options)
133
+ local_entries = local_cache.read_multi_entries(keys, **options)
134
134
  missed_keys = keys - local_entries.keys
135
135
 
136
136
  if missed_keys.any?
137
- local_entries.merge!(super(missed_keys, options))
137
+ local_entries.merge!(super(missed_keys, **options))
138
138
  else
139
139
  local_entries
140
140
  end
141
141
  end
142
142
 
143
- def write_entry(key, entry, options)
143
+ def write_entry(key, entry, **options)
144
144
  if options[:unless_exist]
145
- local_cache.delete_entry(key, options) if local_cache
145
+ local_cache.delete_entry(key, **options) if local_cache
146
146
  else
147
- local_cache.write_entry(key, entry, options) if local_cache
147
+ local_cache.write_entry(key, entry, **options) if local_cache
148
148
  end
149
149
 
150
150
  super
151
151
  end
152
152
 
153
- def delete_entry(key, options)
154
- local_cache.delete_entry(key, options) if local_cache
153
+ def delete_entry(key, **options)
154
+ local_cache.delete_entry(key, **options) if local_cache
155
155
  super
156
156
  end
157
157
 
158
- def write_cache_value(name, value, options)
158
+ def write_cache_value(name, value, **options)
159
159
  name = normalize_key(name, options)
160
160
  cache = local_cache
161
161
  cache.mute do
162
162
  if value
163
163
  cache.write(name, value, options)
164
164
  else
165
- cache.delete(name, options)
165
+ cache.delete(name, **options)
166
166
  end
167
167
  end
168
168
  end
@@ -52,12 +52,13 @@ module ActiveSupport
52
52
  #
53
53
  # ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
54
54
  # # => returns MyOwnCacheStore.new
55
- def lookup_store(*store_option)
56
- store, *parameters = *Array.wrap(store_option).flatten
57
-
55
+ def lookup_store(store = nil, *parameters)
58
56
  case store
59
57
  when Symbol
60
- retrieve_store_class(store).new(*parameters)
58
+ options = parameters.extract_options!
59
+ retrieve_store_class(store).new(*parameters, **options)
60
+ when Array
61
+ lookup_store(*store)
61
62
  when nil
62
63
  ActiveSupport::Cache::MemoryStore.new
63
64
  else
@@ -229,6 +230,14 @@ module ActiveSupport
229
230
  # ask whether you should force a cache write. Otherwise, it's clearer to
230
231
  # just call <tt>Cache#write</tt>.
231
232
  #
233
+ # Setting <tt>skip_nil: true</tt> will not cache nil result:
234
+ #
235
+ # cache.fetch('foo') { nil }
236
+ # cache.fetch('bar', skip_nil: true) { nil }
237
+ # cache.exist?('foo') # => true
238
+ # cache.exist?('bar') # => false
239
+ #
240
+ #
232
241
  # Setting <tt>compress: false</tt> disables compression of the cache entry.
233
242
  #
234
243
  # Setting <tt>:expires_in</tt> will set an expiration time on the cache.
@@ -303,14 +312,14 @@ module ActiveSupport
303
312
  # :bar
304
313
  # end
305
314
  # cache.fetch('foo') # => "bar"
306
- def fetch(name, options = nil)
315
+ def fetch(name, options = nil, &block)
307
316
  if block_given?
308
317
  options = merged_options(options)
309
318
  key = normalize_key(name, options)
310
319
 
311
320
  entry = nil
312
321
  instrument(:read, name, options) do |payload|
313
- cached_entry = read_entry(key, options) unless options[:force]
322
+ cached_entry = read_entry(key, **options) unless options[:force]
314
323
  entry = handle_expired_entry(cached_entry, key, options)
315
324
  entry = nil if entry && entry.mismatched?(normalize_version(name, options))
316
325
  payload[:super_operation] = :fetch if payload
@@ -320,7 +329,7 @@ module ActiveSupport
320
329
  if entry
321
330
  get_entry_value(entry, name, options)
322
331
  else
323
- save_block_result_to_cache(name, options) { |_name| yield _name }
332
+ save_block_result_to_cache(name, options, &block)
324
333
  end
325
334
  elsif options && options[:force]
326
335
  raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
@@ -333,8 +342,9 @@ module ActiveSupport
333
342
  # the cache with the given key, then that data is returned. Otherwise,
334
343
  # +nil+ is returned.
335
344
  #
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.
345
+ # Note, if data was written with the <tt>:expires_in</tt> or
346
+ # <tt>:version</tt> options, both of these conditions are applied before
347
+ # the data is returned.
338
348
  #
339
349
  # Options are passed to the underlying cache implementation.
340
350
  def read(name, options = nil)
@@ -343,11 +353,11 @@ module ActiveSupport
343
353
  version = normalize_version(name, options)
344
354
 
345
355
  instrument(:read, name, options) do |payload|
346
- entry = read_entry(key, options)
356
+ entry = read_entry(key, **options)
347
357
 
348
358
  if entry
349
359
  if entry.expired?
350
- delete_entry(key, options)
360
+ delete_entry(key, **options)
351
361
  payload[:hit] = false if payload
352
362
  nil
353
363
  elsif entry.mismatched?(version)
@@ -375,7 +385,7 @@ module ActiveSupport
375
385
  options = merged_options(options)
376
386
 
377
387
  instrument :read_multi, names, options do |payload|
378
- read_multi_entries(names, options).tap do |results|
388
+ read_multi_entries(names, **options).tap do |results|
379
389
  payload[:hits] = results.keys
380
390
  end
381
391
  end
@@ -387,10 +397,10 @@ module ActiveSupport
387
397
 
388
398
  instrument :write_multi, hash, options do |payload|
389
399
  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)))
400
+ memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options)))
391
401
  end
392
402
 
393
- write_multi_entries entries, options
403
+ write_multi_entries entries, **options
394
404
  end
395
405
  end
396
406
 
@@ -402,8 +412,6 @@ module ActiveSupport
402
412
  # to the cache. If you do not want to write the cache when the cache is
403
413
  # not found, use #read_multi.
404
414
  #
405
- # Options are passed to the underlying cache implementation.
406
- #
407
415
  # Returns a hash with the data for each of the names. For example:
408
416
  #
409
417
  # cache.write("bim", "bam")
@@ -413,6 +421,17 @@ module ActiveSupport
413
421
  # # => { "bim" => "bam",
414
422
  # # "unknown_key" => "Fallback value for key: unknown_key" }
415
423
  #
424
+ # Options are passed to the underlying cache implementation. For example:
425
+ #
426
+ # cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
427
+ # "buzz"
428
+ # end
429
+ # # => {"fizz"=>"buzz"}
430
+ # cache.read("fizz")
431
+ # # => "buzz"
432
+ # sleep(6)
433
+ # cache.read("fizz")
434
+ # # => nil
416
435
  def fetch_multi(*names)
417
436
  raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given?
418
437
 
@@ -420,18 +439,18 @@ module ActiveSupport
420
439
  options = merged_options(options)
421
440
 
422
441
  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
442
+ reads = read_multi_entries(names, **options)
443
+ writes = {}
444
+ ordered = names.each_with_object({}) do |name, hash|
445
+ hash[name] = reads.fetch(name) { writes[name] = yield(name) }
446
+ end
426
447
 
427
- writes = {}
448
+ payload[:hits] = reads.keys
449
+ payload[:super_operation] = :fetch_multi
428
450
 
429
- (names - results.keys).each do |name|
430
- results[name] = writes[name] = yield(name)
431
- end
451
+ write_multi(writes, options)
432
452
 
433
- write_multi writes, options
434
- end
453
+ ordered
435
454
  end
436
455
  end
437
456
 
@@ -442,8 +461,8 @@ module ActiveSupport
442
461
  options = merged_options(options)
443
462
 
444
463
  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)
464
+ entry = Entry.new(value, **options.merge(version: normalize_version(name, options)))
465
+ write_entry(normalize_key(name, options), entry, **options)
447
466
  end
448
467
  end
449
468
 
@@ -454,7 +473,7 @@ module ActiveSupport
454
473
  options = merged_options(options)
455
474
 
456
475
  instrument(:delete, name) do
457
- delete_entry(normalize_key(name, options), options)
476
+ delete_entry(normalize_key(name, options), **options)
458
477
  end
459
478
  end
460
479
 
@@ -465,7 +484,7 @@ module ActiveSupport
465
484
  options = merged_options(options)
466
485
 
467
486
  instrument(:exist?, name) do
468
- entry = read_entry(normalize_key(name, options), options)
487
+ entry = read_entry(normalize_key(name, options), **options)
469
488
  (entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
470
489
  end
471
490
  end
@@ -474,7 +493,7 @@ module ActiveSupport
474
493
  #
475
494
  # Options are passed to the underlying cache implementation.
476
495
  #
477
- # All implementations may not support this method.
496
+ # Some implementations may not support this method.
478
497
  def delete_matched(matcher, options = nil)
479
498
  raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
480
499
  end
@@ -483,7 +502,7 @@ module ActiveSupport
483
502
  #
484
503
  # Options are passed to the underlying cache implementation.
485
504
  #
486
- # All implementations may not support this method.
505
+ # Some implementations may not support this method.
487
506
  def increment(name, amount = 1, options = nil)
488
507
  raise NotImplementedError.new("#{self.class.name} does not support increment")
489
508
  end
@@ -492,7 +511,7 @@ module ActiveSupport
492
511
  #
493
512
  # Options are passed to the underlying cache implementation.
494
513
  #
495
- # All implementations may not support this method.
514
+ # Some implementations may not support this method.
496
515
  def decrement(name, amount = 1, options = nil)
497
516
  raise NotImplementedError.new("#{self.class.name} does not support decrement")
498
517
  end
@@ -501,7 +520,7 @@ module ActiveSupport
501
520
  #
502
521
  # Options are passed to the underlying cache implementation.
503
522
  #
504
- # All implementations may not support this method.
523
+ # Some implementations may not support this method.
505
524
  def cleanup(options = nil)
506
525
  raise NotImplementedError.new("#{self.class.name} does not support cleanup")
507
526
  end
@@ -511,7 +530,7 @@ module ActiveSupport
511
530
  #
512
531
  # The options hash is passed to the underlying cache implementation.
513
532
  #
514
- # All implementations may not support this method.
533
+ # Some implementations may not support this method.
515
534
  def clear(options = nil)
516
535
  raise NotImplementedError.new("#{self.class.name} does not support clear")
517
536
  end
@@ -538,28 +557,28 @@ module ActiveSupport
538
557
 
539
558
  # Reads an entry from the cache implementation. Subclasses must implement
540
559
  # this method.
541
- def read_entry(key, options)
560
+ def read_entry(key, **options)
542
561
  raise NotImplementedError.new
543
562
  end
544
563
 
545
564
  # Writes an entry to the cache implementation. Subclasses must implement
546
565
  # this method.
547
- def write_entry(key, entry, options)
566
+ def write_entry(key, entry, **options)
548
567
  raise NotImplementedError.new
549
568
  end
550
569
 
551
570
  # Reads multiple entries from the cache implementation. Subclasses MAY
552
571
  # implement this method.
553
- def read_multi_entries(names, options)
572
+ def read_multi_entries(names, **options)
554
573
  results = {}
555
574
  names.each do |name|
556
575
  key = normalize_key(name, options)
557
576
  version = normalize_version(name, options)
558
- entry = read_entry(key, options)
577
+ entry = read_entry(key, **options)
559
578
 
560
579
  if entry
561
580
  if entry.expired?
562
- delete_entry(key, options)
581
+ delete_entry(key, **options)
563
582
  elsif entry.mismatched?(version)
564
583
  # Skip mismatched versions
565
584
  else
@@ -572,24 +591,28 @@ module ActiveSupport
572
591
 
573
592
  # Writes multiple entries to the cache implementation. Subclasses MAY
574
593
  # implement this method.
575
- def write_multi_entries(hash, options)
594
+ def write_multi_entries(hash, **options)
576
595
  hash.each do |key, entry|
577
- write_entry key, entry, options
596
+ write_entry key, entry, **options
578
597
  end
579
598
  end
580
599
 
581
600
  # Deletes an entry from the cache implementation. Subclasses must
582
601
  # implement this method.
583
- def delete_entry(key, options)
602
+ def delete_entry(key, **options)
584
603
  raise NotImplementedError.new
585
604
  end
586
605
 
587
606
  # Merges the default options with ones specific to a method call.
588
607
  def merged_options(call_options)
589
608
  if call_options
590
- options.merge(call_options)
609
+ if options.empty?
610
+ call_options
611
+ else
612
+ options.merge(call_options)
613
+ end
591
614
  else
592
- options.dup
615
+ options
593
616
  end
594
617
  end
595
618
 
@@ -634,7 +657,7 @@ module ActiveSupport
634
657
  if key.size > 1
635
658
  key = key.collect { |element| expanded_key(element) }
636
659
  else
637
- key = key.first
660
+ key = expanded_key(key.first)
638
661
  end
639
662
  when Hash
640
663
  key = key.sort_by { |k, _| k.to_s }.collect { |k, v| "#{k}=#{v}" }
@@ -677,7 +700,7 @@ module ActiveSupport
677
700
  entry.expires_at = Time.now + race_ttl
678
701
  write_entry(key, entry, expires_in: race_ttl * 2)
679
702
  else
680
- delete_entry(key, options)
703
+ delete_entry(key, **options)
681
704
  end
682
705
  entry = nil
683
706
  end
@@ -685,7 +708,7 @@ module ActiveSupport
685
708
  end
686
709
 
687
710
  def get_entry_value(entry, name, options)
688
- instrument(:fetch_hit, name, options) {}
711
+ instrument(:fetch_hit, name, options) { }
689
712
  entry.value
690
713
  end
691
714
 
@@ -694,7 +717,7 @@ module ActiveSupport
694
717
  yield(name)
695
718
  end
696
719
 
697
- write(name, result, options)
720
+ write(name, result, options) unless result.nil? && options[:skip_nil]
698
721
  result
699
722
  end
700
723
  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
@@ -139,7 +142,6 @@ module ActiveSupport
139
142
  end
140
143
 
141
144
  private
142
-
143
145
  # A hook invoked every time a before callback is halted.
144
146
  # This can be overridden in ActiveSupport::Callbacks implementors in order
145
147
  # to provide better debugging/logging.
@@ -497,9 +499,7 @@ module ActiveSupport
497
499
  arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) }
498
500
  end
499
501
 
500
- def nested
501
- @nested
502
- end
502
+ attr_reader :nested
503
503
 
504
504
  def final?
505
505
  !@call_template
@@ -578,10 +578,9 @@ module ActiveSupport
578
578
  end
579
579
 
580
580
  protected
581
- def chain; @chain; end
581
+ attr_reader :chain
582
582
 
583
583
  private
584
-
585
584
  def append_one(callback)
586
585
  @callbacks = nil
587
586
  remove_duplicates(callback)
@@ -659,9 +658,17 @@ module ActiveSupport
659
658
  # * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance
660
659
  # method or a proc; the callback will be called only when they all return
661
660
  # a true value.
661
+ #
662
+ # If a proc is given, its body is evaluated in the context of the
663
+ # current object. It can also optionally accept the current object as
664
+ # an argument.
662
665
  # * <tt>:unless</tt> - A symbol or an array of symbols, each naming an
663
666
  # instance method or a proc; the callback will be called only when they
664
667
  # all return a false value.
668
+ #
669
+ # If a proc is given, its body is evaluated in the context of the
670
+ # current object. It can also optionally accept the current object as
671
+ # an argument.
665
672
  # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
666
673
  # existing chain rather than appended.
667
674
  def set_callback(name, *filter_list, &block)
@@ -809,7 +816,9 @@ module ActiveSupport
809
816
  names.each do |name|
810
817
  name = name.to_sym
811
818
 
812
- set_callbacks name, CallbackChain.new(name, options)
819
+ ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
820
+ target.set_callbacks name, CallbackChain.new(name, options)
821
+ end
813
822
 
814
823
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
815
824
  def _run_#{name}_callbacks(&block)
@@ -832,7 +841,6 @@ module ActiveSupport
832
841
  end
833
842
 
834
843
  protected
835
-
836
844
  def get_callbacks(name) # :nodoc:
837
845
  __callbacks[name.to_sym]
838
846
  end
@@ -110,7 +110,7 @@ module ActiveSupport
110
110
  base.instance_variable_set(:@_dependencies, [])
111
111
  end
112
112
 
113
- def append_features(base)
113
+ def append_features(base) #:nodoc:
114
114
  if base.instance_variable_defined?(:@_dependencies)
115
115
  base.instance_variable_get(:@_dependencies) << self
116
116
  false
@@ -123,6 +123,9 @@ module ActiveSupport
123
123
  end
124
124
  end
125
125
 
126
+ # Evaluate given block in context of base class,
127
+ # so that you can write class macros here.
128
+ # When you define more than one +included+ block, it raises an exception.
126
129
  def included(base = nil, &block)
127
130
  if base.nil?
128
131
  if instance_variable_defined?(:@_included_block)
@@ -137,6 +140,26 @@ module ActiveSupport
137
140
  end
138
141
  end
139
142
 
143
+ # Define class methods from given block.
144
+ # You can define private class methods as well.
145
+ #
146
+ # module Example
147
+ # extend ActiveSupport::Concern
148
+ #
149
+ # class_methods do
150
+ # def foo; puts 'foo'; end
151
+ #
152
+ # private
153
+ # def bar; puts 'bar'; end
154
+ # end
155
+ # end
156
+ #
157
+ # class Buzz
158
+ # include Example
159
+ # end
160
+ #
161
+ # Buzz.foo # => "foo"
162
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
140
163
  def class_methods(&class_methods_module_definition)
141
164
  mod = const_defined?(:ClassMethods, false) ?
142
165
  const_get(:ClassMethods) :
@@ -7,11 +7,29 @@ module ActiveSupport
7
7
  # A monitor that will permit dependency loading while blocked waiting for
8
8
  # the lock.
9
9
  class LoadInterlockAwareMonitor < Monitor
10
+ EXCEPTION_NEVER = { Exception => :never }.freeze
11
+ EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
12
+ private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
13
+
10
14
  # Enters an exclusive section, but allows dependency loading while blocked
11
15
  def mon_enter
12
16
  mon_try_enter ||
13
17
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
14
18
  end
19
+
20
+ def synchronize
21
+ Thread.handle_interrupt(EXCEPTION_NEVER) do
22
+ mon_enter
23
+
24
+ begin
25
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE) do
26
+ yield
27
+ end
28
+ ensure
29
+ mon_exit
30
+ end
31
+ end
32
+ end
15
33
  end
16
34
  end
17
35
  end
@@ -200,7 +200,6 @@ module ActiveSupport
200
200
  end
201
201
 
202
202
  private
203
-
204
203
  # Must be called within synchronize
205
204
  def busy_for_exclusive?(purpose)
206
205
  busy_for_sharing?(purpose) ||
@@ -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
@@ -69,8 +67,8 @@ module ActiveSupport
69
67
  # end
70
68
  # # => NameError: invalid config attribute name
71
69
  #
72
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
73
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
70
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
71
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
74
72
  #
75
73
  # class User
76
74
  # include ActiveSupport::Configurable
@@ -83,7 +81,7 @@ module ActiveSupport
83
81
  # User.new.allowed_access = true # => NoMethodError
84
82
  # User.new.allowed_access # => NoMethodError
85
83
  #
86
- # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
84
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
87
85
  #
88
86
  # class User
89
87
  # include ActiveSupport::Configurable
@@ -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