activesupport 7.1.6 → 8.1.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +256 -1133
- data/README.rdoc +1 -1
- data/lib/active_support/array_inquirer.rb +1 -1
- data/lib/active_support/backtrace_cleaner.rb +81 -3
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +65 -78
- data/lib/active_support/cache/file_store.rb +29 -14
- data/lib/active_support/cache/mem_cache_store.rb +42 -102
- data/lib/active_support/cache/memory_store.rb +11 -6
- data/lib/active_support/cache/null_store.rb +2 -2
- data/lib/active_support/cache/redis_cache_store.rb +58 -46
- data/lib/active_support/cache/serializer_with_fallback.rb +0 -23
- data/lib/active_support/cache/strategy/local_cache.rb +72 -27
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +7 -7
- data/lib/active_support/cache.rb +146 -86
- data/lib/active_support/callbacks.rb +102 -126
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +9 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +8 -62
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +34 -0
- data/lib/active_support/configuration_file.rb +15 -6
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/conversions.rb +3 -5
- data/lib/active_support/core_ext/array.rb +7 -7
- data/lib/active_support/core_ext/benchmark.rb +4 -14
- data/lib/active_support/core_ext/big_decimal.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +26 -19
- data/lib/active_support/core_ext/class/subclasses.rb +15 -35
- data/lib/active_support/core_ext/class.rb +2 -2
- data/lib/active_support/core_ext/date/blank.rb +4 -0
- data/lib/active_support/core_ext/date/conversions.rb +2 -2
- data/lib/active_support/core_ext/date.rb +5 -5
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -9
- data/lib/active_support/core_ext/date_time/blank.rb +4 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +3 -5
- data/lib/active_support/core_ext/date_time/conversions.rb +4 -6
- data/lib/active_support/core_ext/date_time.rb +5 -5
- data/lib/active_support/core_ext/digest/uuid.rb +6 -0
- data/lib/active_support/core_ext/digest.rb +1 -1
- data/lib/active_support/core_ext/enumerable.rb +25 -8
- data/lib/active_support/core_ext/erb/util.rb +10 -5
- data/lib/active_support/core_ext/file.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_merge.rb +1 -0
- data/lib/active_support/core_ext/hash/except.rb +0 -12
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/hash.rb +8 -8
- data/lib/active_support/core_ext/integer.rb +3 -3
- data/lib/active_support/core_ext/kernel.rb +3 -3
- data/lib/active_support/core_ext/module/attr_internal.rb +16 -6
- data/lib/active_support/core_ext/module/delegation.rb +20 -163
- data/lib/active_support/core_ext/module/deprecation.rb +1 -4
- data/lib/active_support/core_ext/module/introspection.rb +3 -0
- data/lib/active_support/core_ext/module.rb +11 -11
- data/lib/active_support/core_ext/numeric/conversions.rb +3 -3
- data/lib/active_support/core_ext/numeric.rb +3 -3
- data/lib/active_support/core_ext/object/blank.rb +45 -1
- data/lib/active_support/core_ext/object/instance_variables.rb +11 -19
- data/lib/active_support/core_ext/object/json.rb +24 -11
- data/lib/active_support/core_ext/object/to_query.rb +7 -1
- data/lib/active_support/core_ext/object/try.rb +2 -2
- data/lib/active_support/core_ext/object/with.rb +5 -3
- data/lib/active_support/core_ext/object.rb +13 -13
- data/lib/active_support/core_ext/pathname/blank.rb +4 -0
- data/lib/active_support/core_ext/pathname.rb +2 -2
- data/lib/active_support/core_ext/range/overlap.rb +4 -4
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +4 -4
- data/lib/active_support/core_ext/securerandom.rb +4 -4
- data/lib/active_support/core_ext/string/conversions.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +4 -4
- data/lib/active_support/core_ext/string/multibyte.rb +13 -4
- data/lib/active_support/core_ext/string/output_safety.rb +19 -19
- data/lib/active_support/core_ext/string.rb +13 -13
- data/lib/active_support/core_ext/symbol.rb +1 -1
- data/lib/active_support/core_ext/thread/backtrace/location.rb +2 -7
- data/lib/active_support/core_ext/time/calculations.rb +25 -30
- data/lib/active_support/core_ext/time/compatibility.rb +2 -3
- data/lib/active_support/core_ext/time/conversions.rb +2 -2
- data/lib/active_support/core_ext/time/zones.rb +1 -1
- data/lib/active_support/core_ext/time.rb +5 -5
- data/lib/active_support/core_ext.rb +1 -2
- data/lib/active_support/current_attributes/test_helper.rb +2 -2
- data/lib/active_support/current_attributes.rb +58 -50
- data/lib/active_support/delegation.rb +200 -0
- data/lib/active_support/dependencies/autoload.rb +0 -12
- data/lib/active_support/dependencies/interlock.rb +11 -5
- data/lib/active_support/dependencies.rb +6 -2
- data/lib/active_support/deprecation/constant_accessor.rb +47 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +9 -12
- data/lib/active_support/deprecation/reporting.rb +5 -17
- data/lib/active_support/deprecation.rb +8 -5
- data/lib/active_support/descendants_tracker.rb +9 -87
- data/lib/active_support/duration/iso8601_parser.rb +2 -2
- data/lib/active_support/duration/iso8601_serializer.rb +1 -2
- data/lib/active_support/duration.rb +25 -16
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +20 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/error_reporter.rb +121 -6
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +5 -3
- data/lib/active_support/execution_context.rb +64 -7
- data/lib/active_support/execution_wrapper.rb +1 -2
- data/lib/active_support/file_update_checker.rb +9 -7
- data/lib/active_support/fork_tracker.rb +2 -38
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/gzip.rb +1 -0
- data/lib/active_support/hash_with_indifferent_access.rb +66 -45
- data/lib/active_support/html_safe_translation.rb +3 -0
- data/lib/active_support/i18n_railtie.rb +19 -11
- data/lib/active_support/inflector/inflections.rb +31 -15
- data/lib/active_support/inflector/transliterate.rb +6 -8
- data/lib/active_support/isolated_execution_state.rb +12 -17
- data/lib/active_support/json/decoding.rb +6 -4
- data/lib/active_support/json/encoding.rb +157 -21
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/log_subscriber.rb +2 -18
- data/lib/active_support/logger.rb +15 -2
- data/lib/active_support/logger_thread_safe_level.rb +4 -9
- data/lib/active_support/message_encryptors.rb +54 -2
- data/lib/active_support/message_pack/extensions.rb +20 -2
- data/lib/active_support/message_verifier.rb +21 -0
- data/lib/active_support/message_verifiers.rb +57 -3
- data/lib/active_support/messages/rotation_coordinator.rb +9 -0
- data/lib/active_support/messages/rotator.rb +10 -0
- data/lib/active_support/multibyte/chars.rb +14 -4
- data/lib/active_support/multibyte.rb +4 -0
- data/lib/active_support/notifications/fanout.rb +68 -50
- data/lib/active_support/notifications/instrumenter.rb +22 -19
- data/lib/active_support/notifications.rb +28 -27
- data/lib/active_support/number_helper/number_converter.rb +2 -2
- data/lib/active_support/number_helper.rb +22 -0
- data/lib/active_support/option_merger.rb +2 -2
- data/lib/active_support/ordered_options.rb +53 -15
- data/lib/active_support/railtie.rb +36 -20
- data/lib/active_support/string_inquirer.rb +1 -1
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +1 -5
- data/lib/active_support/syntax_error_proxy.rb +3 -0
- data/lib/active_support/tagged_logging.rb +5 -1
- data/lib/active_support/test_case.rb +63 -6
- data/lib/active_support/testing/assertions.rb +113 -27
- data/lib/active_support/testing/constant_stubbing.rb +30 -8
- data/lib/active_support/testing/deprecation.rb +5 -12
- data/lib/active_support/testing/error_reporter_assertions.rb +18 -1
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/isolation.rb +19 -9
- data/lib/active_support/testing/method_call_assertions.rb +2 -16
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +18 -2
- data/lib/active_support/testing/parallelization/worker.rb +4 -2
- data/lib/active_support/testing/parallelization.rb +25 -1
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +11 -6
- data/lib/active_support/time_with_zone.rb +39 -26
- data/lib/active_support/values/time_zone.rb +26 -17
- data/lib/active_support/xml_mini.rb +14 -4
- data/lib/active_support.rb +22 -9
- metadata +31 -17
- data/lib/active_support/core_ext/range/each.rb +0 -24
- data/lib/active_support/deprecation/instance_delegator.rb +0 -65
- data/lib/active_support/proxy_object.rb +0 -17
- data/lib/active_support/ruby_features.rb +0 -7
- data/lib/active_support/testing/strict_warnings.rb +0 -39
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/callbacks"
|
|
4
|
+
require "active_support/execution_context"
|
|
5
|
+
require "active_support/core_ext/object/with"
|
|
4
6
|
require "active_support/core_ext/enumerable"
|
|
5
7
|
require "active_support/core_ext/module/delegation"
|
|
6
8
|
|
|
@@ -94,6 +96,8 @@ module ActiveSupport
|
|
|
94
96
|
|
|
95
97
|
INVALID_ATTRIBUTE_NAMES = [:set, :reset, :resets, :instance, :before_reset, :after_reset, :reset_all, :clear_all] # :nodoc:
|
|
96
98
|
|
|
99
|
+
NOT_SET = Object.new.freeze # :nodoc:
|
|
100
|
+
|
|
97
101
|
class << self
|
|
98
102
|
# Returns singleton instance for this class in this thread. If none exists, one is created.
|
|
99
103
|
def instance
|
|
@@ -101,45 +105,40 @@ module ActiveSupport
|
|
|
101
105
|
end
|
|
102
106
|
|
|
103
107
|
# Declares one or more attributes that will be given both class and instance accessor methods.
|
|
104
|
-
|
|
108
|
+
#
|
|
109
|
+
# ==== Options
|
|
110
|
+
#
|
|
111
|
+
# * <tt>:default</tt> - The default value for the attributes. If the value
|
|
112
|
+
# is a proc or lambda, it will be called whenever an instance is
|
|
113
|
+
# constructed. Otherwise, the value will be duplicated with +#dup+.
|
|
114
|
+
# Default values are re-assigned when the attributes are reset.
|
|
115
|
+
def attribute(*names, default: NOT_SET)
|
|
105
116
|
invalid_attribute_names = names.map(&:to_sym) & INVALID_ATTRIBUTE_NAMES
|
|
106
117
|
if invalid_attribute_names.any?
|
|
107
118
|
raise ArgumentError, "Restricted attribute names: #{invalid_attribute_names.join(", ")}"
|
|
108
119
|
end
|
|
109
120
|
|
|
121
|
+
Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
|
|
122
|
+
Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
|
|
123
|
+
|
|
110
124
|
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
|
|
111
125
|
names.each do |name|
|
|
112
126
|
owner.define_cached_method(name, namespace: :current_attributes) do |batch|
|
|
113
127
|
batch <<
|
|
114
128
|
"def #{name}" <<
|
|
115
|
-
"attributes[:#{name}]" <<
|
|
129
|
+
"@attributes[:#{name}]" <<
|
|
116
130
|
"end"
|
|
117
131
|
end
|
|
118
132
|
owner.define_cached_method("#{name}=", namespace: :current_attributes) do |batch|
|
|
119
133
|
batch <<
|
|
120
134
|
"def #{name}=(value)" <<
|
|
121
|
-
"attributes[:#{name}] = value" <<
|
|
135
|
+
"@attributes[:#{name}] = value" <<
|
|
122
136
|
"end"
|
|
123
137
|
end
|
|
124
138
|
end
|
|
125
139
|
end
|
|
126
140
|
|
|
127
|
-
|
|
128
|
-
names.each do |name|
|
|
129
|
-
owner.define_cached_method(name, namespace: :current_attributes_delegation) do |batch|
|
|
130
|
-
batch <<
|
|
131
|
-
"def #{name}" <<
|
|
132
|
-
"instance.#{name}" <<
|
|
133
|
-
"end"
|
|
134
|
-
end
|
|
135
|
-
owner.define_cached_method("#{name}=", namespace: :current_attributes_delegation) do |batch|
|
|
136
|
-
batch <<
|
|
137
|
-
"def #{name}=(value)" <<
|
|
138
|
-
"instance.#{name} = value" <<
|
|
139
|
-
"end"
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
end
|
|
141
|
+
self.defaults = defaults.merge(names.index_with { default })
|
|
143
142
|
end
|
|
144
143
|
|
|
145
144
|
# Calls this callback before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
|
|
@@ -155,13 +154,11 @@ module ActiveSupport
|
|
|
155
154
|
|
|
156
155
|
delegate :set, :reset, to: :instance
|
|
157
156
|
|
|
158
|
-
def reset_all # :nodoc:
|
|
159
|
-
current_instances.each_value(&:reset)
|
|
160
|
-
end
|
|
161
|
-
|
|
162
157
|
def clear_all # :nodoc:
|
|
163
|
-
|
|
164
|
-
|
|
158
|
+
if instances = current_instances
|
|
159
|
+
instances.values.each(&:reset)
|
|
160
|
+
instances.clear
|
|
161
|
+
end
|
|
165
162
|
end
|
|
166
163
|
|
|
167
164
|
private
|
|
@@ -170,32 +167,47 @@ module ActiveSupport
|
|
|
170
167
|
end
|
|
171
168
|
|
|
172
169
|
def current_instances
|
|
173
|
-
|
|
170
|
+
ExecutionContext.current_attributes_instances
|
|
174
171
|
end
|
|
175
172
|
|
|
176
173
|
def current_instances_key
|
|
177
174
|
@current_instances_key ||= name.to_sym
|
|
178
175
|
end
|
|
179
176
|
|
|
180
|
-
def method_missing(name,
|
|
181
|
-
|
|
182
|
-
#
|
|
183
|
-
# By letting #delegate handle it, we avoid an enclosure that'll capture args.
|
|
184
|
-
singleton_class.delegate name, to: :instance
|
|
185
|
-
|
|
186
|
-
send(name, *args, &block)
|
|
177
|
+
def method_missing(name, ...)
|
|
178
|
+
instance.public_send(name, ...)
|
|
187
179
|
end
|
|
188
|
-
ruby2_keywords(:method_missing)
|
|
189
180
|
|
|
190
181
|
def respond_to_missing?(name, _)
|
|
191
|
-
|
|
182
|
+
instance.respond_to?(name) || super
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def method_added(name)
|
|
186
|
+
super
|
|
187
|
+
|
|
188
|
+
# We try to generate instance delegators early to not rely on method_missing.
|
|
189
|
+
return if name == :initialize
|
|
190
|
+
|
|
191
|
+
# If the added method isn't public, we don't delegate it.
|
|
192
|
+
return unless public_method_defined?(name)
|
|
193
|
+
|
|
194
|
+
# If we already have a class method by that name, we don't override it.
|
|
195
|
+
return if singleton_class.method_defined?(name) || singleton_class.private_method_defined?(name)
|
|
196
|
+
|
|
197
|
+
Delegation.generate(singleton_class, [name], to: :instance, as: self, nilable: false)
|
|
192
198
|
end
|
|
193
199
|
end
|
|
194
200
|
|
|
195
|
-
|
|
201
|
+
class_attribute :defaults, instance_writer: false, default: {}.freeze
|
|
202
|
+
|
|
203
|
+
attr_writer :attributes
|
|
196
204
|
|
|
197
205
|
def initialize
|
|
198
|
-
@attributes =
|
|
206
|
+
@attributes = resolve_defaults
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def attributes
|
|
210
|
+
@attributes.dup
|
|
199
211
|
end
|
|
200
212
|
|
|
201
213
|
# Expose one or more attributes within a block. Old values are returned after the block concludes.
|
|
@@ -208,28 +220,24 @@ module ActiveSupport
|
|
|
208
220
|
# end
|
|
209
221
|
# end
|
|
210
222
|
# end
|
|
211
|
-
def set(
|
|
212
|
-
|
|
213
|
-
assign_attributes(set_attributes)
|
|
214
|
-
yield
|
|
215
|
-
ensure
|
|
216
|
-
assign_attributes(old_attributes)
|
|
223
|
+
def set(attributes, &block)
|
|
224
|
+
with(**attributes, &block)
|
|
217
225
|
end
|
|
218
226
|
|
|
219
227
|
# Reset all attributes. Should be called before and after actions, when used as a per-request singleton.
|
|
220
228
|
def reset
|
|
221
229
|
run_callbacks :reset do
|
|
222
|
-
self.attributes =
|
|
230
|
+
self.attributes = resolve_defaults
|
|
223
231
|
end
|
|
224
232
|
end
|
|
225
233
|
|
|
226
234
|
private
|
|
227
|
-
def
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
235
|
+
def resolve_defaults
|
|
236
|
+
defaults.each_with_object({}) do |(key, value), result|
|
|
237
|
+
if value != NOT_SET
|
|
238
|
+
result[key] = Proc === value ? value.call : value.dup
|
|
239
|
+
end
|
|
240
|
+
end
|
|
233
241
|
end
|
|
234
242
|
end
|
|
235
243
|
end
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveSupport
|
|
4
|
+
# Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
|
|
5
|
+
# option is not used.
|
|
6
|
+
class DelegationError < NoMethodError
|
|
7
|
+
class << self
|
|
8
|
+
def nil_target(method_name, target) # :nodoc:
|
|
9
|
+
new("#{method_name} delegated to #{target}, but #{target} is nil")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module Delegation # :nodoc:
|
|
15
|
+
RUBY_RESERVED_KEYWORDS = %w(__ENCODING__ __LINE__ __FILE__ alias and BEGIN begin break
|
|
16
|
+
case class def defined? do else elsif END end ensure false for if in module next nil
|
|
17
|
+
not or redo rescue retry return self super then true undef unless until when while yield)
|
|
18
|
+
RESERVED_METHOD_NAMES = (RUBY_RESERVED_KEYWORDS + %w(_ arg args block)).to_set.freeze
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
def generate(owner, methods, location: nil, to: nil, prefix: nil, allow_nil: nil, nilable: true, private: nil, as: nil, signature: nil)
|
|
22
|
+
unless to
|
|
23
|
+
raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if prefix == true && /^[^a-z_]/.match?(to)
|
|
27
|
+
raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
method_prefix = \
|
|
31
|
+
if prefix
|
|
32
|
+
"#{prefix == true ? to : prefix}_"
|
|
33
|
+
else
|
|
34
|
+
""
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
location ||= caller_locations(1, 1).first
|
|
38
|
+
file, line = location.path, location.lineno
|
|
39
|
+
|
|
40
|
+
receiver = if to.is_a?(Module)
|
|
41
|
+
if to.name.nil?
|
|
42
|
+
raise ArgumentError, "Can't delegate to anonymous class or module: #{to}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
unless Inflector.safe_constantize(to.name).equal?(to)
|
|
46
|
+
raise ArgumentError, "Can't delegate to detached class or module: #{to.name}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
"::#{to.name}"
|
|
50
|
+
else
|
|
51
|
+
to.to_s
|
|
52
|
+
end
|
|
53
|
+
receiver = "self.#{receiver}" if RESERVED_METHOD_NAMES.include?(receiver)
|
|
54
|
+
|
|
55
|
+
explicit_receiver = false
|
|
56
|
+
receiver_class = if as
|
|
57
|
+
explicit_receiver = true
|
|
58
|
+
as
|
|
59
|
+
elsif to.is_a?(Module)
|
|
60
|
+
to.singleton_class
|
|
61
|
+
elsif receiver == "self.class"
|
|
62
|
+
nilable = false # self.class can't possibly be nil
|
|
63
|
+
owner.singleton_class
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
method_def = []
|
|
67
|
+
method_names = []
|
|
68
|
+
|
|
69
|
+
method_def << "self.private" if private
|
|
70
|
+
|
|
71
|
+
methods.each do |method|
|
|
72
|
+
method_name = prefix ? "#{method_prefix}#{method}" : method
|
|
73
|
+
method_names << method_name.to_sym
|
|
74
|
+
|
|
75
|
+
# Attribute writer methods only accept one argument. Makes sure []=
|
|
76
|
+
# methods still accept two arguments.
|
|
77
|
+
definition = \
|
|
78
|
+
if signature
|
|
79
|
+
signature
|
|
80
|
+
elsif /[^\]]=\z/.match?(method)
|
|
81
|
+
"arg"
|
|
82
|
+
else
|
|
83
|
+
method_object = if receiver_class
|
|
84
|
+
begin
|
|
85
|
+
receiver_class.public_instance_method(method)
|
|
86
|
+
rescue NameError
|
|
87
|
+
raise if explicit_receiver
|
|
88
|
+
# Do nothing. Fall back to `"..."`
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if method_object
|
|
93
|
+
parameters = method_object.parameters
|
|
94
|
+
|
|
95
|
+
if parameters.map(&:first).intersect?([:opt, :rest, :keyreq, :key, :keyrest])
|
|
96
|
+
"..."
|
|
97
|
+
else
|
|
98
|
+
defn = parameters.filter_map { |type, arg| arg if type == :req }
|
|
99
|
+
defn << "&"
|
|
100
|
+
defn.join(", ")
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
"..."
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# The following generated method calls the target exactly once, storing
|
|
108
|
+
# the returned value in a dummy variable.
|
|
109
|
+
#
|
|
110
|
+
# Reason is twofold: On one hand doing less calls is in general better.
|
|
111
|
+
# On the other hand it could be that the target has side-effects,
|
|
112
|
+
# whereas conceptually, from the user point of view, the delegator should
|
|
113
|
+
# be doing one call.
|
|
114
|
+
if nilable == false
|
|
115
|
+
method_def <<
|
|
116
|
+
"def #{method_name}(#{definition})" <<
|
|
117
|
+
" (#{receiver}).#{method}(#{definition})" <<
|
|
118
|
+
"end"
|
|
119
|
+
elsif allow_nil
|
|
120
|
+
method = method.to_s
|
|
121
|
+
|
|
122
|
+
method_def <<
|
|
123
|
+
"def #{method_name}(#{definition})" <<
|
|
124
|
+
" _ = #{receiver}" <<
|
|
125
|
+
" if !_.nil? || nil.respond_to?(:#{method})" <<
|
|
126
|
+
" _.#{method}(#{definition})" <<
|
|
127
|
+
" end" <<
|
|
128
|
+
"end"
|
|
129
|
+
else
|
|
130
|
+
method = method.to_s
|
|
131
|
+
method_name = method_name.to_s
|
|
132
|
+
|
|
133
|
+
method_def <<
|
|
134
|
+
"def #{method_name}(#{definition})" <<
|
|
135
|
+
" _ = #{receiver}" <<
|
|
136
|
+
" _.#{method}(#{definition})" <<
|
|
137
|
+
"rescue NoMethodError => e" <<
|
|
138
|
+
" if _.nil? && e.name == :#{method}" <<
|
|
139
|
+
" raise ::ActiveSupport::DelegationError.nil_target(:#{method_name}, :'#{receiver}')" <<
|
|
140
|
+
" else" <<
|
|
141
|
+
" raise" <<
|
|
142
|
+
" end" <<
|
|
143
|
+
"end"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
owner.module_eval(method_def.join(";"), file, line)
|
|
147
|
+
method_names
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def generate_method_missing(owner, target, allow_nil: nil)
|
|
151
|
+
target = target.to_s
|
|
152
|
+
target = "self.#{target}" if RESERVED_METHOD_NAMES.include?(target) || target == "__target"
|
|
153
|
+
|
|
154
|
+
if allow_nil
|
|
155
|
+
owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
156
|
+
def respond_to_missing?(name, include_private = false)
|
|
157
|
+
# It may look like an oversight, but we deliberately do not pass
|
|
158
|
+
# +include_private+, because they do not get delegated.
|
|
159
|
+
|
|
160
|
+
return false if name == :marshal_dump || name == :_dump
|
|
161
|
+
#{target}.respond_to?(name) || super
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def method_missing(method, ...)
|
|
165
|
+
__target = #{target}
|
|
166
|
+
if __target.nil? && !nil.respond_to?(method)
|
|
167
|
+
nil
|
|
168
|
+
elsif __target.respond_to?(method)
|
|
169
|
+
__target.public_send(method, ...)
|
|
170
|
+
else
|
|
171
|
+
super
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
RUBY
|
|
175
|
+
else
|
|
176
|
+
owner.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
177
|
+
def respond_to_missing?(name, include_private = false)
|
|
178
|
+
# It may look like an oversight, but we deliberately do not pass
|
|
179
|
+
# +include_private+, because they do not get delegated.
|
|
180
|
+
|
|
181
|
+
return false if name == :marshal_dump || name == :_dump
|
|
182
|
+
#{target}.respond_to?(name) || super
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def method_missing(method, ...)
|
|
186
|
+
__target = #{target}
|
|
187
|
+
if __target.nil? && !nil.respond_to?(method)
|
|
188
|
+
raise ::ActiveSupport::DelegationError.nil_target(method, :'#{target}')
|
|
189
|
+
elsif __target.respond_to?(method)
|
|
190
|
+
__target.public_send(method, ...)
|
|
191
|
+
else
|
|
192
|
+
super
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
RUBY
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -27,18 +27,6 @@ module ActiveSupport
|
|
|
27
27
|
#
|
|
28
28
|
# MyLib.eager_load!
|
|
29
29
|
module Autoload
|
|
30
|
-
def self.extended(base) # :nodoc:
|
|
31
|
-
if RUBY_VERSION < "3"
|
|
32
|
-
base.class_eval do
|
|
33
|
-
@_autoloads = nil
|
|
34
|
-
@_under_path = nil
|
|
35
|
-
@_at_path = nil
|
|
36
|
-
@_eager_autoload = false
|
|
37
|
-
@_eagerloaded_constants = nil
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
30
|
def autoload(const_name, path = @_at_path)
|
|
43
31
|
unless path
|
|
44
32
|
full = [name, @_under_path, const_name.to_s].compact.join("::")
|
|
@@ -10,19 +10,24 @@ module ActiveSupport # :nodoc:
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def loading(&block)
|
|
13
|
-
|
|
13
|
+
ActiveSupport.deprecator.warn(
|
|
14
|
+
"ActiveSupport::Dependencies::Interlock#loading is deprecated and " \
|
|
15
|
+
"will be removed in Rails 9.0. The loading interlock is no longer " \
|
|
16
|
+
"used since Rails switched to Zeitwerk for autoloading."
|
|
17
|
+
)
|
|
18
|
+
yield if block
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
def unloading(&block)
|
|
17
|
-
@lock.exclusive(purpose: :unload, compatible: [:
|
|
22
|
+
@lock.exclusive(purpose: :unload, compatible: [:unload], after_compatible: [:unload], &block)
|
|
18
23
|
end
|
|
19
24
|
|
|
20
25
|
def start_unloading
|
|
21
|
-
@lock.start_exclusive(purpose: :unload, compatible: [:
|
|
26
|
+
@lock.start_exclusive(purpose: :unload, compatible: [:unload])
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
def done_unloading
|
|
25
|
-
@lock.stop_exclusive(compatible: [:
|
|
30
|
+
@lock.stop_exclusive(compatible: [:unload])
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
def start_running
|
|
@@ -38,7 +43,8 @@ module ActiveSupport # :nodoc:
|
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
def permit_concurrent_loads(&block)
|
|
41
|
-
|
|
46
|
+
# Soft deprecated: no deprecation warning for now, but this is a no-op.
|
|
47
|
+
yield if block
|
|
42
48
|
end
|
|
43
49
|
|
|
44
50
|
def raw_state(&block) # :nodoc:
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "set"
|
|
4
3
|
require "active_support/dependencies/interlock"
|
|
5
4
|
|
|
6
5
|
module ActiveSupport # :nodoc:
|
|
@@ -22,7 +21,12 @@ module ActiveSupport # :nodoc:
|
|
|
22
21
|
# preventing any other thread from being inside a #run_interlock
|
|
23
22
|
# block at the same time.
|
|
24
23
|
def self.load_interlock(&block)
|
|
25
|
-
|
|
24
|
+
ActiveSupport.deprecator.warn(
|
|
25
|
+
"ActiveSupport::Dependencies.load_interlock is deprecated and " \
|
|
26
|
+
"will be removed in Rails 9.0. The loading interlock is no longer " \
|
|
27
|
+
"used since Rails switched to Zeitwerk for autoloading."
|
|
28
|
+
)
|
|
29
|
+
yield if block
|
|
26
30
|
end
|
|
27
31
|
|
|
28
32
|
# Execute the supplied block while holding an exclusive lock,
|
|
@@ -2,28 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveSupport
|
|
4
4
|
class Deprecation
|
|
5
|
-
# DeprecatedConstantAccessor transforms a constant into a deprecated one by
|
|
6
|
-
# hooking +const_missing+.
|
|
7
|
-
#
|
|
8
|
-
# It takes the names of an old (deprecated) constant and of a new constant
|
|
9
|
-
# (both in string form) and a deprecator.
|
|
10
|
-
#
|
|
11
|
-
# The deprecated constant now returns the same object as the new one rather
|
|
12
|
-
# than a proxy object, so it can be used transparently in +rescue+ blocks
|
|
13
|
-
# etc.
|
|
14
|
-
#
|
|
15
|
-
# PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto)
|
|
16
|
-
#
|
|
17
|
-
# # (In a later update, the original implementation of `PLANETS` has been removed.)
|
|
18
|
-
#
|
|
19
|
-
# PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
|
|
20
|
-
# include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
|
21
|
-
# deprecate_constant 'PLANETS', 'PLANETS_POST_2006', deprecator: ActiveSupport::Deprecation.new
|
|
22
|
-
#
|
|
23
|
-
# PLANETS.map { |planet| planet.capitalize }
|
|
24
|
-
# # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
|
|
25
|
-
# (Backtrace information…)
|
|
26
|
-
# ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
|
|
27
5
|
module DeprecatedConstantAccessor
|
|
28
6
|
def self.included(base)
|
|
29
7
|
require "active_support/inflector/methods"
|
|
@@ -39,11 +17,54 @@ module ActiveSupport
|
|
|
39
17
|
super
|
|
40
18
|
end
|
|
41
19
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
20
|
+
# Provides a way to rename constants with a deprecation cycle in which
|
|
21
|
+
# both the old and new names work, but using the old one prints a
|
|
22
|
+
# deprecation message.
|
|
23
|
+
#
|
|
24
|
+
# In order to rename <tt>A::B</tt> to <tt>C::D</tt>, you need to delete the
|
|
25
|
+
# definition of <tt>A::B</tt> and declare the deprecation in +A+:
|
|
26
|
+
#
|
|
27
|
+
# require "active_support/deprecation"
|
|
28
|
+
#
|
|
29
|
+
# module A
|
|
30
|
+
# include ActiveSupport::Deprecation::DeprecatedConstantAccessor
|
|
31
|
+
#
|
|
32
|
+
# deprecate_constant "B", "C::D", deprecator: ActiveSupport::Deprecation.new
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# The first argument is a constant name (no colons). It is the name of
|
|
36
|
+
# the constant you want to deprecate in the enclosing class or module.
|
|
37
|
+
#
|
|
38
|
+
# The second argument is the constant path of the replacement. That
|
|
39
|
+
# has to be a full path even if the replacement is defined in the same
|
|
40
|
+
# namespace as the deprecated one was.
|
|
41
|
+
#
|
|
42
|
+
# In both cases, strings and symbols are supported.
|
|
43
|
+
#
|
|
44
|
+
# The +deprecator+ keyword argument is the object that will print the
|
|
45
|
+
# deprecation message, an instance of ActiveSupport::Deprecation.
|
|
46
|
+
#
|
|
47
|
+
# With that in place, references to <tt>A::B</tt> still work, they
|
|
48
|
+
# evaluate to <tt>C::D</tt> now, and trigger a deprecation warning:
|
|
49
|
+
#
|
|
50
|
+
# DEPRECATION WARNING: A::B is deprecated! Use C::D instead.
|
|
51
|
+
# (called from ...)
|
|
52
|
+
#
|
|
53
|
+
# The message can be customized with the optional +message+ keyword
|
|
54
|
+
# argument.
|
|
55
|
+
#
|
|
56
|
+
# For this to work, a +const_missing+ hook is installed. When client
|
|
57
|
+
# code references the deprecated constant, the callback prints the
|
|
58
|
+
# message and constantizes the replacement.
|
|
59
|
+
#
|
|
60
|
+
# Caveat: If the deprecated constant name is reachable in a different
|
|
61
|
+
# namespace and Ruby constant lookup finds it, the hook won't be
|
|
62
|
+
# called and the deprecation won't work as intended. This may happen,
|
|
63
|
+
# for example, if an ancestor of the enclosing namespace has a
|
|
64
|
+
# constant with the same name. This is an unsupported edge case.
|
|
65
|
+
def deprecate_constant(old_constant_name, new_constant_path, deprecator:, message: nil)
|
|
45
66
|
class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
|
|
46
|
-
class_variable_get(:@@_deprecated_constants)[
|
|
67
|
+
class_variable_get(:@@_deprecated_constants)[old_constant_name.to_s] = { new: new_constant_path, message: message, deprecator: deprecator }
|
|
47
68
|
end
|
|
48
69
|
end
|
|
49
70
|
base.singleton_class.prepend extension
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module ActiveSupport
|
|
4
4
|
class Deprecation
|
|
5
5
|
class DeprecationProxy # :nodoc:
|
|
6
|
-
def self.new(*args, &block)
|
|
6
|
+
def self.new(*args, **kwargs, &block)
|
|
7
7
|
object = args.first
|
|
8
8
|
|
|
9
9
|
return object unless object
|
|
@@ -36,11 +36,10 @@ module ActiveSupport
|
|
|
36
36
|
# (Backtrace)
|
|
37
37
|
# # => "#<Object:0x007fb9b34c34b0>"
|
|
38
38
|
class DeprecatedObjectProxy < DeprecationProxy
|
|
39
|
-
def initialize(object, message, deprecator
|
|
39
|
+
def initialize(object, message, deprecator)
|
|
40
40
|
@object = object
|
|
41
41
|
@message = message
|
|
42
|
-
|
|
43
|
-
@deprecator = deprecator || ActiveSupport::Deprecation._instance
|
|
42
|
+
@deprecator = deprecator
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
private
|
|
@@ -86,12 +85,11 @@ module ActiveSupport
|
|
|
86
85
|
# example.request.to_s
|
|
87
86
|
# # => "special_request"
|
|
88
87
|
class DeprecatedInstanceVariableProxy < DeprecationProxy
|
|
89
|
-
def initialize(instance, method, var = "@#{method}", deprecator
|
|
88
|
+
def initialize(instance, method, var = "@#{method}", deprecator:)
|
|
90
89
|
@instance = instance
|
|
91
90
|
@method = method
|
|
92
91
|
@var = var
|
|
93
|
-
|
|
94
|
-
@deprecator = deprecator || ActiveSupport::Deprecation._instance
|
|
92
|
+
@deprecator = deprecator
|
|
95
93
|
end
|
|
96
94
|
|
|
97
95
|
private
|
|
@@ -127,13 +125,12 @@ module ActiveSupport
|
|
|
127
125
|
super
|
|
128
126
|
end
|
|
129
127
|
|
|
130
|
-
def initialize(old_const, new_const, deprecator
|
|
128
|
+
def initialize(old_const, new_const, deprecator, message: "#{old_const} is deprecated! Use #{new_const} instead.")
|
|
131
129
|
Kernel.require "active_support/inflector/methods"
|
|
132
130
|
|
|
133
131
|
@old_const = old_const
|
|
134
132
|
@new_const = new_const
|
|
135
|
-
|
|
136
|
-
@deprecator = deprecator || ActiveSupport::Deprecation._instance
|
|
133
|
+
@deprecator = deprecator
|
|
137
134
|
@message = message
|
|
138
135
|
end
|
|
139
136
|
|
|
@@ -183,9 +180,9 @@ module ActiveSupport
|
|
|
183
180
|
target.const_get(name)
|
|
184
181
|
end
|
|
185
182
|
|
|
186
|
-
def method_missing(
|
|
183
|
+
def method_missing(...)
|
|
187
184
|
@deprecator.warn(@message, caller_locations)
|
|
188
|
-
target.__send__(
|
|
185
|
+
target.__send__(...)
|
|
189
186
|
end
|
|
190
187
|
end
|
|
191
188
|
end
|
|
@@ -139,7 +139,6 @@ module ActiveSupport
|
|
|
139
139
|
|
|
140
140
|
def extract_callstack(callstack)
|
|
141
141
|
return [] if callstack.empty?
|
|
142
|
-
return _extract_callstack(callstack) if callstack.first.is_a? String
|
|
143
142
|
|
|
144
143
|
offending_line = callstack.find { |frame|
|
|
145
144
|
# Code generated with `eval` doesn't have an `absolute_path`, e.g. templates.
|
|
@@ -150,24 +149,13 @@ module ActiveSupport
|
|
|
150
149
|
[offending_line.path, offending_line.lineno, offending_line.label]
|
|
151
150
|
end
|
|
152
151
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if offending_line
|
|
158
|
-
if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
|
|
159
|
-
md.captures
|
|
160
|
-
else
|
|
161
|
-
offending_line
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/" # :nodoc:
|
|
167
|
-
LIB_DIR = RbConfig::CONFIG["libdir"] # :nodoc:
|
|
152
|
+
RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
|
|
153
|
+
private_constant :RAILS_GEM_ROOT
|
|
154
|
+
LIB_DIR = RbConfig::CONFIG["libdir"]
|
|
155
|
+
private_constant :LIB_DIR
|
|
168
156
|
|
|
169
157
|
def ignored_callstack?(path)
|
|
170
|
-
path.start_with?(RAILS_GEM_ROOT, LIB_DIR)
|
|
158
|
+
path.start_with?(RAILS_GEM_ROOT, LIB_DIR) || path.include?("<internal:")
|
|
171
159
|
end
|
|
172
160
|
end
|
|
173
161
|
end
|