Skip to content

Commit ce35980

Browse files
authored
Merge pull request rails#54746 from Edouard-chin/ec-method-added
Add tests ensuring CurrentAttributes eagerly define class methods
2 parents 8e9d63d + 2ed9bc1 commit ce35980

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

activesupport/lib/active_support/current_attributes.rb

+10-3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ def attribute(*names, default: NOT_SET)
117117
raise ArgumentError, "Restricted attribute names: #{invalid_attribute_names.join(", ")}"
118118
end
119119

120+
Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
121+
Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
122+
120123
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
121124
names.each do |name|
122125
owner.define_cached_method(name, namespace: :current_attributes) do |batch|
@@ -134,9 +137,6 @@ def attribute(*names, default: NOT_SET)
134137
end
135138
end
136139

137-
Delegation.generate(singleton_class, names, to: :instance, nilable: false, signature: "")
138-
Delegation.generate(singleton_class, names.map { |n| "#{n}=" }, to: :instance, nilable: false, signature: "value")
139-
140140
self.defaults = defaults.merge(names.index_with { default })
141141
end
142142

@@ -185,9 +185,16 @@ def respond_to_missing?(name, _)
185185

186186
def method_added(name)
187187
super
188+
189+
# We try to generate instance delegators early to not rely on method_missing.
188190
return if name == :initialize
191+
192+
# If the added method isn't public, we don't delegate it.
189193
return unless public_method_defined?(name)
194+
195+
# If we already have a class method by that name, we don't override it.
190196
return if singleton_class.method_defined?(name) || singleton_class.private_method_defined?(name)
197+
191198
Delegation.generate(singleton_class, [name], to: :instance, as: self, nilable: false)
192199
end
193200
end

activesupport/test/current_attributes_test.rb

+31
Original file line numberDiff line numberDiff line change
@@ -276,4 +276,35 @@ def foo; end # Sets the cache because of a `method_added` hook
276276

277277
assert_instance_of(Hash, current.bar)
278278
end
279+
280+
test "instance delegators are eagerly defined" do
281+
current = Class.new(ActiveSupport::CurrentAttributes) do
282+
def self.name
283+
"MyCurrent"
284+
end
285+
286+
def regular
287+
:regular
288+
end
289+
290+
attribute :attr, default: :att
291+
end
292+
293+
assert current.singleton_class.method_defined?(:attr)
294+
assert current.singleton_class.method_defined?(:attr=)
295+
assert current.singleton_class.method_defined?(:regular)
296+
end
297+
298+
test "attribute delegators have precise signature" do
299+
current = Class.new(ActiveSupport::CurrentAttributes) do
300+
def self.name
301+
"MyCurrent"
302+
end
303+
304+
attribute :attr, default: :att
305+
end
306+
307+
assert_equal [], current.method(:attr).parameters
308+
assert_equal [[:req, :value]], current.method(:attr=).parameters
309+
end
279310
end

0 commit comments

Comments
 (0)