activesupport 7.2.3 → 8.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -385
  3. data/README.rdoc +1 -1
  4. data/lib/active_support/backtrace_cleaner.rb +2 -2
  5. data/lib/active_support/benchmark.rb +21 -0
  6. data/lib/active_support/benchmarkable.rb +3 -2
  7. data/lib/active_support/broadcast_logger.rb +74 -61
  8. data/lib/active_support/cache/file_store.rb +14 -4
  9. data/lib/active_support/cache/mem_cache_store.rb +15 -13
  10. data/lib/active_support/cache/memory_store.rb +9 -5
  11. data/lib/active_support/cache/null_store.rb +2 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +6 -3
  13. data/lib/active_support/cache/strategy/local_cache.rb +20 -56
  14. data/lib/active_support/cache.rb +17 -12
  15. data/lib/active_support/callbacks.rb +3 -5
  16. data/lib/active_support/class_attribute.rb +26 -0
  17. data/lib/active_support/code_generator.rb +9 -0
  18. data/lib/active_support/concurrency/share_lock.rb +0 -1
  19. data/lib/active_support/configuration_file.rb +15 -6
  20. data/lib/active_support/core_ext/benchmark.rb +6 -10
  21. data/lib/active_support/core_ext/class/attribute.rb +12 -21
  22. data/lib/active_support/core_ext/date/conversions.rb +2 -0
  23. data/lib/active_support/core_ext/date_and_time/compatibility.rb +2 -2
  24. data/lib/active_support/core_ext/date_time/conversions.rb +2 -4
  25. data/lib/active_support/core_ext/enumerable.rb +13 -20
  26. data/lib/active_support/core_ext/erb/util.rb +2 -2
  27. data/lib/active_support/core_ext/hash/except.rb +0 -12
  28. data/lib/active_support/core_ext/module/introspection.rb +0 -3
  29. data/lib/active_support/core_ext/object/json.rb +18 -14
  30. data/lib/active_support/core_ext/object/try.rb +2 -2
  31. data/lib/active_support/core_ext/range.rb +0 -1
  32. data/lib/active_support/core_ext/securerandom.rb +8 -24
  33. data/lib/active_support/core_ext/string/filters.rb +3 -3
  34. data/lib/active_support/core_ext/string/multibyte.rb +3 -3
  35. data/lib/active_support/core_ext/time/calculations.rb +14 -2
  36. data/lib/active_support/core_ext/time/compatibility.rb +1 -9
  37. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  38. data/lib/active_support/core_ext/time/zones.rb +1 -1
  39. data/lib/active_support/current_attributes.rb +7 -14
  40. data/lib/active_support/deprecation.rb +1 -1
  41. data/lib/active_support/encrypted_configuration.rb +20 -2
  42. data/lib/active_support/error_reporter.rb +27 -6
  43. data/lib/active_support/execution_wrapper.rb +1 -1
  44. data/lib/active_support/file_update_checker.rb +1 -1
  45. data/lib/active_support/gem_version.rb +4 -4
  46. data/lib/active_support/hash_with_indifferent_access.rb +31 -31
  47. data/lib/active_support/i18n_railtie.rb +19 -10
  48. data/lib/active_support/isolated_execution_state.rb +0 -1
  49. data/lib/active_support/json/decoding.rb +1 -1
  50. data/lib/active_support/json/encoding.rb +7 -25
  51. data/lib/active_support/lazy_load_hooks.rb +1 -1
  52. data/lib/active_support/message_encryptors.rb +2 -2
  53. data/lib/active_support/message_verifier.rb +0 -9
  54. data/lib/active_support/message_verifiers.rb +3 -5
  55. data/lib/active_support/messages/rotator.rb +0 -5
  56. data/lib/active_support/multibyte/chars.rb +1 -4
  57. data/lib/active_support/number_helper.rb +22 -0
  58. data/lib/active_support/railtie.rb +4 -0
  59. data/lib/active_support/tagged_logging.rb +5 -0
  60. data/lib/active_support/testing/assertions.rb +72 -21
  61. data/lib/active_support/testing/isolation.rb +0 -2
  62. data/lib/active_support/testing/parallelization/server.rb +2 -15
  63. data/lib/active_support/testing/parallelization/worker.rb +2 -2
  64. data/lib/active_support/testing/parallelization.rb +1 -12
  65. data/lib/active_support/testing/strict_warnings.rb +43 -0
  66. data/lib/active_support/testing/time_helpers.rb +2 -1
  67. data/lib/active_support/time_with_zone.rb +22 -13
  68. data/lib/active_support/values/time_zone.rb +17 -15
  69. data/lib/active_support/xml_mini.rb +0 -2
  70. data/lib/active_support.rb +10 -2
  71. metadata +27 -8
  72. data/lib/active_support/core_ext/range/sole.rb +0 -17
@@ -76,6 +76,7 @@ module ActiveSupport
76
76
 
77
77
  # Returns all the logger that are part of this broadcast.
78
78
  attr_reader :broadcasts
79
+ attr_reader :formatter
79
80
  attr_accessor :progname
80
81
 
81
82
  def initialize(*loggers)
@@ -104,119 +105,131 @@ module ActiveSupport
104
105
  @broadcasts.delete(logger)
105
106
  end
106
107
 
107
- def local_level=(level)
108
- @broadcasts.each do |logger|
109
- logger.local_level = level if logger.respond_to?(:local_level=)
110
- end
108
+ def level
109
+ @broadcasts.map(&:level).min
111
110
  end
112
111
 
113
- def local_level
114
- loggers = @broadcasts.select { |logger| logger.respond_to?(:local_level) }
112
+ def <<(message)
113
+ dispatch { |logger| logger.<<(message) }
114
+ end
115
115
 
116
- loggers.map do |logger|
117
- logger.local_level
118
- end.first
116
+ def add(...)
117
+ dispatch { |logger| logger.add(...) }
119
118
  end
119
+ alias_method :log, :add
120
120
 
121
- LOGGER_METHODS = %w[
122
- << log add debug info warn error fatal unknown
123
- level= sev_threshold= close
124
- formatter formatter=
125
- ] # :nodoc:
126
- LOGGER_METHODS.each do |method|
127
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
128
- def #{method}(...)
129
- dispatch(:#{method}, ...)
130
- end
131
- RUBY
121
+ def debug(...)
122
+ dispatch { |logger| logger.debug(...) }
132
123
  end
133
124
 
134
- # Returns the lowest level of all the loggers in the broadcast.
135
- def level
136
- @broadcasts.map(&:level).min
125
+ def info(...)
126
+ dispatch { |logger| logger.info(...) }
127
+ end
128
+
129
+ def warn(...)
130
+ dispatch { |logger| logger.warn(...) }
131
+ end
132
+
133
+ def error(...)
134
+ dispatch { |logger| logger.error(...) }
135
+ end
136
+
137
+ def fatal(...)
138
+ dispatch { |logger| logger.fatal(...) }
137
139
  end
138
140
 
139
- # True if the log level allows entries with severity +Logger::DEBUG+ to be written
140
- # to at least one broadcast. False otherwise.
141
+ def unknown(...)
142
+ dispatch { |logger| logger.unknown(...) }
143
+ end
144
+
145
+ def formatter=(formatter)
146
+ dispatch { |logger| logger.formatter = formatter }
147
+
148
+ @formatter = formatter
149
+ end
150
+
151
+ def level=(level)
152
+ dispatch { |logger| logger.level = level }
153
+ end
154
+ alias_method :sev_threshold=, :level=
155
+
156
+ def local_level=(level)
157
+ dispatch do |logger|
158
+ logger.local_level = level if logger.respond_to?(:local_level=)
159
+ end
160
+ end
161
+
162
+ def close
163
+ dispatch { |logger| logger.close }
164
+ end
165
+
166
+ # +True+ if the log level allows entries with severity Logger::DEBUG to be written
167
+ # to at least one broadcast. +False+ otherwise.
141
168
  def debug?
142
169
  @broadcasts.any? { |logger| logger.debug? }
143
170
  end
144
171
 
145
- # Sets the log level to +Logger::DEBUG+ for the whole broadcast.
172
+ # Sets the log level to Logger::DEBUG for the whole broadcast.
146
173
  def debug!
147
- dispatch(:debug!)
174
+ dispatch { |logger| logger.debug! }
148
175
  end
149
176
 
150
- # True if the log level allows entries with severity +Logger::INFO+ to be written
151
- # to at least one broadcast. False otherwise.
177
+ # +True+ if the log level allows entries with severity Logger::INFO to be written
178
+ # to at least one broadcast. +False+ otherwise.
152
179
  def info?
153
180
  @broadcasts.any? { |logger| logger.info? }
154
181
  end
155
182
 
156
- # Sets the log level to +Logger::INFO+ for the whole broadcast.
183
+ # Sets the log level to Logger::INFO for the whole broadcast.
157
184
  def info!
158
- dispatch(:info!)
185
+ dispatch { |logger| logger.info! }
159
186
  end
160
187
 
161
- # True if the log level allows entries with severity +Logger::WARN+ to be written
162
- # to at least one broadcast. False otherwise.
188
+ # +True+ if the log level allows entries with severity Logger::WARN to be written
189
+ # to at least one broadcast. +False+ otherwise.
163
190
  def warn?
164
191
  @broadcasts.any? { |logger| logger.warn? }
165
192
  end
166
193
 
167
- # Sets the log level to +Logger::WARN+ for the whole broadcast.
194
+ # Sets the log level to Logger::WARN for the whole broadcast.
168
195
  def warn!
169
- dispatch(:warn!)
196
+ dispatch { |logger| logger.warn! }
170
197
  end
171
198
 
172
- # True if the log level allows entries with severity +Logger::ERROR+ to be written
173
- # to at least one broadcast. False otherwise.
199
+ # +True+ if the log level allows entries with severity Logger::ERROR to be written
200
+ # to at least one broadcast. +False+ otherwise.
174
201
  def error?
175
202
  @broadcasts.any? { |logger| logger.error? }
176
203
  end
177
204
 
178
- # Sets the log level to +Logger::ERROR+ for the whole broadcast.
205
+ # Sets the log level to Logger::ERROR for the whole broadcast.
179
206
  def error!
180
- dispatch(:error!)
207
+ dispatch { |logger| logger.error! }
181
208
  end
182
209
 
183
- # True if the log level allows entries with severity +Logger::FATAL+ to be written
184
- # to at least one broadcast. False otherwise.
210
+ # +True+ if the log level allows entries with severity Logger::FATAL to be written
211
+ # to at least one broadcast. +False+ otherwise.
185
212
  def fatal?
186
213
  @broadcasts.any? { |logger| logger.fatal? }
187
214
  end
188
215
 
189
- # Sets the log level to +Logger::FATAL+ for the whole broadcast.
216
+ # Sets the log level to Logger::FATAL for the whole broadcast.
190
217
  def fatal!
191
- dispatch(:fatal!)
218
+ dispatch { |logger| logger.fatal! }
192
219
  end
193
220
 
194
221
  def initialize_copy(other)
195
222
  @broadcasts = []
196
223
  @progname = other.progname.dup
224
+ @formatter = other.formatter.dup
197
225
 
198
226
  broadcast_to(*other.broadcasts.map(&:dup))
199
227
  end
200
228
 
201
229
  private
202
- def dispatch(method, *args, **kwargs, &block)
203
- if block_given?
204
- # Maintain semantics that the first logger yields the block
205
- # as normal, but subsequent loggers won't re-execute the block.
206
- # Instead, the initial result is immediately returned.
207
- called, result = false, nil
208
- block = proc { |*args, **kwargs|
209
- if called then result
210
- else
211
- called = true
212
- result = yield(*args, **kwargs)
213
- end
214
- }
215
- end
216
-
217
- @broadcasts.map { |logger|
218
- logger.send(method, *args, **kwargs, &block)
219
- }.first
230
+ def dispatch(&block)
231
+ @broadcasts.each { |logger| block.call(logger) }
232
+ true
220
233
  end
221
234
 
222
235
  def method_missing(name, ...)
@@ -57,8 +57,13 @@ module ActiveSupport
57
57
  # cache.write("baz", 5)
58
58
  # cache.increment("baz") # => 6
59
59
  #
60
- def increment(name, amount = 1, **options)
61
- modify_value(name, amount, options)
60
+ def increment(name, amount = 1, options = nil)
61
+ options = merged_options(options)
62
+ key = normalize_key(name, options)
63
+
64
+ instrument(:increment, key, amount: amount) do
65
+ modify_value(name, amount, options)
66
+ end
62
67
  end
63
68
 
64
69
  # Decrement a cached integer value. Returns the updated value.
@@ -72,8 +77,13 @@ module ActiveSupport
72
77
  # cache.write("baz", 5)
73
78
  # cache.decrement("baz") # => 4
74
79
  #
75
- def decrement(name, amount = 1, **options)
76
- modify_value(name, -amount, options)
80
+ def decrement(name, amount = 1, options = nil)
81
+ options = merged_options(options)
82
+ key = normalize_key(name, options)
83
+
84
+ instrument(:decrement, key, amount: amount) do
85
+ modify_value(name, -amount, options)
86
+ end
77
87
  end
78
88
 
79
89
  def delete_matched(matcher, options = nil)
@@ -212,24 +212,26 @@ module ActiveSupport
212
212
  def read_multi_entries(names, **options)
213
213
  keys_to_names = names.index_by { |name| normalize_key(name, options) }
214
214
 
215
- rescue_error_with({}) do
216
- raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
215
+ raw_values = begin
216
+ @data.with { |c| c.get_multi(keys_to_names.keys) }
217
+ rescue Dalli::UnmarshalError
218
+ {}
219
+ end
217
220
 
218
- values = {}
221
+ values = {}
219
222
 
220
- raw_values.each do |key, value|
221
- entry = deserialize_entry(value, raw: options[:raw])
223
+ raw_values.each do |key, value|
224
+ entry = deserialize_entry(value, raw: options[:raw])
222
225
 
223
- unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
224
- begin
225
- values[keys_to_names[key]] = entry.value
226
- rescue DeserializationError
227
- end
226
+ unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
227
+ begin
228
+ values[keys_to_names[key]] = entry.value
229
+ rescue DeserializationError
228
230
  end
229
231
  end
230
-
231
- values
232
232
  end
233
+
234
+ values
233
235
  end
234
236
 
235
237
  # Delete an entry from the cache.
@@ -274,7 +276,7 @@ module ActiveSupport
274
276
 
275
277
  def rescue_error_with(fallback)
276
278
  yield
277
- rescue Dalli::DalliError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
279
+ rescue Dalli::DalliError => error
278
280
  logger.error("DalliError (#{error}): #{error.message}") if logger
279
281
  ActiveSupport.error_reporter&.report(
280
282
  error,
@@ -146,8 +146,10 @@ module ActiveSupport
146
146
  # cache.write("baz", 5)
147
147
  # cache.increment("baz") # => 6
148
148
  #
149
- def increment(name, amount = 1, **options)
150
- modify_value(name, amount, **options)
149
+ def increment(name, amount = 1, options = nil)
150
+ instrument(:increment, name, amount: amount) do
151
+ modify_value(name, amount, options)
152
+ end
151
153
  end
152
154
 
153
155
  # Decrement a cached integer value. Returns the updated value.
@@ -161,8 +163,10 @@ module ActiveSupport
161
163
  # cache.write("baz", 5)
162
164
  # cache.decrement("baz") # => 4
163
165
  #
164
- def decrement(name, amount = 1, **options)
165
- modify_value(name, -amount, **options)
166
+ def decrement(name, amount = 1, options = nil)
167
+ instrument(:decrement, name, amount: amount) do
168
+ modify_value(name, -amount, options)
169
+ end
166
170
  end
167
171
 
168
172
  # Deletes cache entries if the cache key matches a given pattern.
@@ -234,7 +238,7 @@ module ActiveSupport
234
238
 
235
239
  # Modifies the amount of an integer value that is stored in the cache.
236
240
  # If the key is not found it is created and set to +amount+.
237
- def modify_value(name, amount, **options)
241
+ def modify_value(name, amount, options)
238
242
  options = merged_options(options)
239
243
  key = normalize_key(name, options)
240
244
  version = normalize_version(name, options)
@@ -25,10 +25,10 @@ module ActiveSupport
25
25
  def cleanup(options = nil)
26
26
  end
27
27
 
28
- def increment(name, amount = 1, **options)
28
+ def increment(name, amount = 1, options = nil)
29
29
  end
30
30
 
31
- def decrement(name, amount = 1, **options)
31
+ def decrement(name, amount = 1, options = nil)
32
32
  end
33
33
 
34
34
  def delete_matched(matcher, options = nil)
@@ -173,9 +173,12 @@ module ActiveSupport
173
173
  return {} if names.empty?
174
174
 
175
175
  options = names.extract_options!
176
- instrument_multi(:read_multi, names, options) do |payload|
176
+ options = merged_options(options)
177
+ keys = names.map { |name| normalize_key(name, options) }
178
+
179
+ instrument_multi(:read_multi, keys, options) do |payload|
177
180
  read_multi_entries(names, **options).tap do |results|
178
- payload[:hits] = results.keys
181
+ payload[:hits] = results.keys.map { |name| normalize_key(name, options) }
179
182
  end
180
183
  end
181
184
  end
@@ -480,7 +483,7 @@ module ActiveSupport
480
483
 
481
484
  def failsafe(method, returning: nil)
482
485
  yield
483
- rescue ::Redis::BaseError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
486
+ rescue ::Redis::BaseError => error
484
487
  @error_handler&.call(method: method, exception: error, returning: returning)
485
488
  returning
486
489
  end
@@ -94,52 +94,26 @@ module ActiveSupport
94
94
  super
95
95
  end
96
96
 
97
- def increment(name, amount = 1, **options) # :nodoc:
97
+ def increment(name, amount = 1, options = nil) # :nodoc:
98
98
  return super unless local_cache
99
99
  value = bypass_local_cache { super }
100
- write_cache_value(name, value, raw: true, **options)
100
+ if options
101
+ write_cache_value(name, value, raw: true, **options)
102
+ else
103
+ write_cache_value(name, value, raw: true)
104
+ end
101
105
  value
102
106
  end
103
107
 
104
- def decrement(name, amount = 1, **options) # :nodoc:
108
+ def decrement(name, amount = 1, options = nil) # :nodoc:
105
109
  return super unless local_cache
106
110
  value = bypass_local_cache { super }
107
- write_cache_value(name, value, raw: true, **options)
108
- value
109
- end
110
-
111
- def fetch_multi(*names, &block) # :nodoc:
112
- return super if local_cache.nil? || names.empty?
113
-
114
- options = names.extract_options!
115
- options = merged_options(options)
116
-
117
- keys_to_names = names.index_by { |name| normalize_key(name, options) }
118
-
119
- local_entries = local_cache.read_multi_entries(keys_to_names.keys)
120
- results = local_entries.each_with_object({}) do |(key, value), result|
121
- # If we recorded a miss in the local cache, `#fetch_multi` will forward
122
- # that key to the real store, and the entry will be replaced
123
- # local_cache.delete_entry(key)
124
- next if value.nil?
125
-
126
- entry = deserialize_entry(value, **options)
127
-
128
- normalized_key = keys_to_names[key]
129
- if entry.nil?
130
- result[normalized_key] = nil
131
- elsif entry.expired? || entry.mismatched?(normalize_version(normalized_key, options))
132
- local_cache.delete_entry(key)
133
- else
134
- result[normalized_key] = entry.value
135
- end
111
+ if options
112
+ write_cache_value(name, value, raw: true, **options)
113
+ else
114
+ write_cache_value(name, value, raw: true)
136
115
  end
137
-
138
- if results.size < names.size
139
- results.merge!(super(*(names - results.keys), options, &block))
140
- end
141
-
142
- results
116
+ value
143
117
  end
144
118
 
145
119
  private
@@ -163,27 +137,17 @@ module ActiveSupport
163
137
  keys_to_names = names.index_by { |name| normalize_key(name, options) }
164
138
 
165
139
  local_entries = local_cache.read_multi_entries(keys_to_names.keys)
166
-
167
- results = local_entries.each_with_object({}) do |(key, value), result|
168
- next if value.nil? # recorded cache miss
169
-
170
- entry = deserialize_entry(value, **options)
171
-
172
- normalized_key = keys_to_names[key]
173
- if entry.nil?
174
- result[normalized_key] = nil
175
- elsif entry.expired? || entry.mismatched?(normalize_version(normalized_key, options))
176
- local_cache.delete_entry(key)
177
- else
178
- result[normalized_key] = entry.value
179
- end
140
+ local_entries.transform_keys! { |key| keys_to_names[key] }
141
+ local_entries.transform_values! do |payload|
142
+ deserialize_entry(payload, **options)&.value
180
143
  end
144
+ missed_names = names - local_entries.keys
181
145
 
182
- if results.size < names.size
183
- results.merge!(super(names - results.keys, **options))
146
+ if missed_names.any?
147
+ local_entries.merge!(super(missed_names, **options))
148
+ else
149
+ local_entries
184
150
  end
185
-
186
- results
187
151
  end
188
152
 
189
153
  def write_serialized_entry(key, payload, **)
@@ -35,7 +35,6 @@ module ActiveSupport
35
35
  :race_condition_ttl,
36
36
  :serializer,
37
37
  :skip_nil,
38
- :raw,
39
38
  ]
40
39
 
41
40
  # Mapping of canonical option names to aliases that a store will recognize.
@@ -387,7 +386,7 @@ module ActiveSupport
387
386
  # process can try to generate a new value after the extended time window
388
387
  # has elapsed.
389
388
  #
390
- # # Set all values to expire after one second.
389
+ # # Set all values to expire after one minute.
391
390
  # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
392
391
  #
393
392
  # cache.write("foo", "original value")
@@ -539,10 +538,11 @@ module ActiveSupport
539
538
 
540
539
  options = names.extract_options!
541
540
  options = merged_options(options)
541
+ keys = names.map { |name| normalize_key(name, options) }
542
542
 
543
- instrument_multi :read_multi, names, options do |payload|
543
+ instrument_multi :read_multi, keys, options do |payload|
544
544
  read_multi_entries(names, **options, event: payload).tap do |results|
545
- payload[:hits] = results.keys
545
+ payload[:hits] = results.keys.map { |name| normalize_key(name, options) }
546
546
  end
547
547
  end
548
548
  end
@@ -552,8 +552,9 @@ module ActiveSupport
552
552
  return hash if hash.empty?
553
553
 
554
554
  options = merged_options(options)
555
+ normalized_hash = hash.transform_keys { |key| normalize_key(key, options) }
555
556
 
556
- instrument_multi :write_multi, hash, options do |payload|
557
+ instrument_multi :write_multi, normalized_hash, options do |payload|
557
558
  entries = hash.each_with_object({}) do |(name, value), memo|
558
559
  memo[normalize_key(name, options)] = Entry.new(value, **options.merge(version: normalize_version(name, options)))
559
560
  end
@@ -597,9 +598,9 @@ module ActiveSupport
597
598
 
598
599
  options = names.extract_options!
599
600
  options = merged_options(options)
600
-
601
+ keys = names.map { |name| normalize_key(name, options) }
601
602
  writes = {}
602
- ordered = instrument_multi :read_multi, names, options do |payload|
603
+ ordered = instrument_multi :read_multi, keys, options do |payload|
603
604
  if options[:force]
604
605
  reads = {}
605
606
  else
@@ -611,7 +612,7 @@ module ActiveSupport
611
612
  end
612
613
  writes.compact! if options[:skip_nil]
613
614
 
614
- payload[:hits] = reads.keys
615
+ payload[:hits] = reads.keys.map { |name| normalize_key(name, options) }
615
616
  payload[:super_operation] = :fetch_multi
616
617
 
617
618
  ordered
@@ -944,9 +945,12 @@ module ActiveSupport
944
945
  #
945
946
  # namespace_key 'foo', namespace: -> { 'cache' }
946
947
  # # => 'cache:foo'
947
- def namespace_key(key, options = nil)
948
- options = merged_options(options)
949
- namespace = options[:namespace]
948
+ def namespace_key(key, call_options = nil)
949
+ namespace = if call_options&.key?(:namespace)
950
+ call_options[:namespace]
951
+ else
952
+ options[:namespace]
953
+ end
950
954
 
951
955
  if namespace.respond_to?(:call)
952
956
  namespace = namespace.call
@@ -1031,7 +1035,8 @@ module ActiveSupport
1031
1035
  # When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache
1032
1036
  # for a brief period while the entry is being recalculated.
1033
1037
  entry.expires_at = Time.now.to_f + race_ttl
1034
- write_entry(key, entry, **options, expires_in: race_ttl * 2)
1038
+ options[:expires_in] = race_ttl * 2
1039
+ write_entry(key, entry, **options)
1035
1040
  else
1036
1041
  delete_entry(key, **options)
1037
1042
  end
@@ -6,7 +6,6 @@ require "active_support/core_ext/array/extract_options"
6
6
  require "active_support/core_ext/class/attribute"
7
7
  require "active_support/core_ext/string/filters"
8
8
  require "active_support/core_ext/object/blank"
9
- require "thread"
10
9
 
11
10
  module ActiveSupport
12
11
  # = Active Support \Callbacks
@@ -67,7 +66,7 @@ module ActiveSupport
67
66
 
68
67
  included do
69
68
  extend ActiveSupport::DescendantsTracker
70
- class_attribute :__callbacks, instance_writer: false, default: {}
69
+ class_attribute :__callbacks, instance_writer: false, instance_predicate: false, default: {}
71
70
  end
72
71
 
73
72
  CALLBACK_FILTER_TYPES = [:before, :after, :around].freeze
@@ -499,10 +498,9 @@ module ActiveSupport
499
498
  when Conditionals::Value
500
499
  ProcCall.new(filter)
501
500
  when ::Proc
502
- case filter.arity
503
- when 2
501
+ if filter.arity > 1
504
502
  InstanceExec2.new(filter)
505
- when 1, -2
503
+ elsif filter.arity > 0
506
504
  InstanceExec1.new(filter)
507
505
  else
508
506
  InstanceExec0.new(filter)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module ClassAttribute # :nodoc:
5
+ class << self
6
+ def redefine(owner, name, value)
7
+ if owner.singleton_class?
8
+ owner.redefine_method(name) { value }
9
+ owner.send(:public, name)
10
+ end
11
+
12
+ owner.redefine_singleton_method(name) { value }
13
+ owner.singleton_class.send(:public, name)
14
+
15
+ owner.redefine_singleton_method("#{name}=") do |new_value|
16
+ if owner.equal?(self)
17
+ value = new_value
18
+ else
19
+ ::ActiveSupport::ClassAttribute.redefine(self, name, new_value)
20
+ end
21
+ end
22
+ owner.singleton_class.send(:public, "#{name}=")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -55,6 +55,11 @@ module ActiveSupport
55
55
  @path = path
56
56
  @line = line
57
57
  @namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
58
+ @sources = []
59
+ end
60
+
61
+ def class_eval
62
+ yield @sources
58
63
  end
59
64
 
60
65
  def define_cached_method(canonical_name, namespace:, as: nil, &block)
@@ -65,6 +70,10 @@ module ActiveSupport
65
70
  @namespaces.each_value do |method_set|
66
71
  method_set.apply(@owner, @path, @line - 1)
67
72
  end
73
+
74
+ unless @sources.empty?
75
+ @owner.class_eval("# frozen_string_literal: true\n" + @sources.join(";"), @path, @line - 1)
76
+ end
68
77
  end
69
78
  end
70
79
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "thread"
4
3
  require "monitor"
5
4
 
6
5
  module ActiveSupport
@@ -19,11 +19,20 @@ module ActiveSupport
19
19
  end
20
20
 
21
21
  def parse(context: nil, **options)
22
- source = render(context)
23
- if YAML.respond_to?(:unsafe_load)
24
- YAML.unsafe_load(source, **options) || {}
22
+ source = @content.include?("<%") ? render(context) : @content
23
+
24
+ if source == @content
25
+ if YAML.respond_to?(:unsafe_load)
26
+ YAML.unsafe_load_file(@content_path, **options) || {}
27
+ else
28
+ YAML.load_file(@content_path, **options) || {}
29
+ end
25
30
  else
26
- YAML.load(source, **options) || {}
31
+ if YAML.respond_to?(:unsafe_load)
32
+ YAML.unsafe_load(source, **options) || {}
33
+ else
34
+ YAML.load(source, **options) || {}
35
+ end
27
36
  end
28
37
  rescue Psych::SyntaxError => error
29
38
  raise "YAML syntax error occurred while parsing #{@content_path}. " \
@@ -33,8 +42,7 @@ module ActiveSupport
33
42
 
34
43
  private
35
44
  def read(content_path)
36
- require "yaml"
37
- require "erb"
45
+ require "yaml" unless defined?(YAML)
38
46
 
39
47
  File.read(content_path).tap do |content|
40
48
  if content.include?("\u00A0")
@@ -44,6 +52,7 @@ module ActiveSupport
44
52
  end
45
53
 
46
54
  def render(context)
55
+ require "erb" unless defined?(ERB)
47
56
  erb = ERB.new(@content).tap { |e| e.filename = @content_path }
48
57
  context ? erb.result(context) : erb.result
49
58
  end