summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <[email protected]>2025-03-13 13:29:37 +0100
committerJean Boussier <[email protected]>2025-03-14 09:51:57 +0100
commitde48e47ddf78aba02fd9623bc7ce685540a10743 (patch)
treee4e7d409eb5d8343b85dc2628f5e1c8e7782b2dc
parentdd7deef338d843c8d866ddc279854068b39bfeb9 (diff)
Invoke `inherited` callbacks before `const_added`
[Misc #21143] Conceptually this makes sense and is more consistent with using the `Name = Class.new(Superclass)` alternative method. However the new class is still named before `inherited` is called.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/12927
-rw-r--r--class.c4
-rw-r--r--spec/ruby/core/class/fixtures/callback_order.rb21
-rw-r--r--spec/ruby/core/class/inherited_spec.rb13
-rw-r--r--spec/ruby/optional/capi/class_spec.rb11
-rw-r--r--spec/ruby/optional/capi/fixtures/class.rb10
-rw-r--r--test/ruby/test_settracefunc.rb16
-rw-r--r--vm_insnhelper.c18
7 files changed, 72 insertions, 21 deletions
diff --git a/class.c b/class.c
index b39e693837..5d13cbaf7d 100644
--- a/class.c
+++ b/class.c
@@ -1004,8 +1004,8 @@ rb_define_class(const char *name, VALUE super)
}
klass = rb_define_class_id(id, super);
rb_vm_register_global_object(klass);
- rb_const_set(rb_cObject, id, klass);
rb_class_inherited(super, klass);
+ rb_const_set(rb_cObject, id, klass);
return klass;
}
@@ -1043,8 +1043,8 @@ rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super)
}
klass = rb_define_class_id(id, super);
rb_set_class_path_string(klass, outer, rb_id2str(id));
- rb_const_set(outer, id, klass);
rb_class_inherited(super, klass);
+ rb_const_set(outer, id, klass);
return klass;
}
diff --git a/spec/ruby/core/class/fixtures/callback_order.rb b/spec/ruby/core/class/fixtures/callback_order.rb
new file mode 100644
index 0000000000..e82e0e6c19
--- /dev/null
+++ b/spec/ruby/core/class/fixtures/callback_order.rb
@@ -0,0 +1,21 @@
+module CoreClassSpecs
+ module Callbacks
+ class Base
+ def self.inherited(subclass)
+ subclass.const_set(:INHERITED_NAME, subclass.name)
+ ORDER << [:inherited, subclass, eval("defined?(#{subclass.name})")]
+ super
+ end
+ end
+
+ ORDER = []
+
+ def self.const_added(const_name)
+ ORDER << [:const_added, const_name, eval("defined?(#{const_name})")]
+ super
+ end
+
+ class Child < Base
+ end
+ end
+end
diff --git a/spec/ruby/core/class/inherited_spec.rb b/spec/ruby/core/class/inherited_spec.rb
index 8ef8bb8c35..3868ba4089 100644
--- a/spec/ruby/core/class/inherited_spec.rb
+++ b/spec/ruby/core/class/inherited_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'fixtures/callback_order'
describe "Class.inherited" do
@@ -98,4 +99,16 @@ describe "Class.inherited" do
-> { Class.new(top) }.should_not raise_error
end
+ it "is invoked after the class is named when using class definition syntax" do
+ CoreClassSpecs::Callbacks::Child::INHERITED_NAME.should == "CoreClassSpecs::Callbacks::Child"
+ end
+
+ ruby_version_is "3.5" do # https://bugs.ruby-lang.org/issues/21143
+ it "is invoked before `const_added`" do
+ CoreClassSpecs::Callbacks::ORDER.should == [
+ [:inherited, CoreClassSpecs::Callbacks::Child, nil],
+ [:const_added, :Child, "constant"],
+ ]
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb
index a231245ebe..6d53b62b75 100644
--- a/spec/ruby/optional/capi/class_spec.rb
+++ b/spec/ruby/optional/capi/class_spec.rb
@@ -383,6 +383,17 @@ describe "C-API Class function" do
CApiClassSpecs.const_get(cls.name)
}.should raise_error(NameError, /wrong constant name/)
end
+
+ ruby_version_is "3.5" do
+ it "calls .inherited before .const_added" do
+ ScratchPad.record([])
+ @s.rb_define_class_id_under(CApiClassSpecs::Callbacks, :Subclass, CApiClassSpecs::Callbacks)
+ ScratchPad.recorded.should == [
+ [:inherited, "CApiClassSpecs::Callbacks::Subclass"],
+ [:const_added, :Subclass],
+ ]
+ end
+ end
end
describe "rb_define_class_id_under" do
diff --git a/spec/ruby/optional/capi/fixtures/class.rb b/spec/ruby/optional/capi/fixtures/class.rb
index b463e3b4c3..a738f2fd0f 100644
--- a/spec/ruby/optional/capi/fixtures/class.rb
+++ b/spec/ruby/optional/capi/fixtures/class.rb
@@ -101,4 +101,14 @@ class CApiClassSpecs
module M
end
end
+
+ class Callbacks
+ def self.inherited(child)
+ ScratchPad << [:inherited, child.name]
+ end
+
+ def self.const_added(const_name)
+ ScratchPad << [:const_added, const_name]
+ end
+ end
end
diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
index 55c07abbea..5542ad248a 100644
--- a/test/ruby/test_settracefunc.rb
+++ b/test/ruby/test_settracefunc.rb
@@ -168,14 +168,14 @@ class TestSetTraceFunc < Test::Unit::TestCase
events.shift)
assert_equal(["line", 4, __method__, self.class],
events.shift)
- assert_equal(["c-call", 4, :const_added, Module],
- events.shift)
- assert_equal(["c-return", 4, :const_added, Module],
- events.shift)
assert_equal(["c-call", 4, :inherited, Class],
events.shift)
assert_equal(["c-return", 4, :inherited, Class],
events.shift)
+ assert_equal(["c-call", 4, :const_added, Module],
+ events.shift)
+ assert_equal(["c-return", 4, :const_added, Module],
+ events.shift)
assert_equal(["class", 4, nil, nil],
events.shift)
assert_equal(["line", 5, nil, nil],
@@ -411,10 +411,10 @@ class TestSetTraceFunc < Test::Unit::TestCase
[["c-return", 2, :add_trace_func, Thread],
["line", 3, __method__, self.class],
- ["c-call", 3, :const_added, Module],
- ["c-return", 3, :const_added, Module],
["c-call", 3, :inherited, Class],
["c-return", 3, :inherited, Class],
+ ["c-call", 3, :const_added, Module],
+ ["c-return", 3, :const_added, Module],
["class", 3, nil, nil],
["line", 4, nil, nil],
["c-call", 4, :method_added, Module],
@@ -558,10 +558,10 @@ class TestSetTraceFunc < Test::Unit::TestCase
[:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing],
[:c_return, 4, "xyzzy", Array, :reverse_each, [1], nil, [1]],
[:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing],
- [:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, :nothing],
- [:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, nil],
[:c_call, 7, "xyzzy", Class, :inherited, Object, nil, :nothing],
[:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil],
+ [:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, :nothing],
+ [:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, nil],
[:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing],
[:line, 8, "xyzzy", nil, nil, xyzzy.class, nil, :nothing],
[:line, 9, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing],
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index e7a2728d69..8c0a68ac56 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -5745,29 +5745,25 @@ vm_check_if_module(ID id, VALUE mod)
}
static VALUE
-declare_under(ID id, VALUE cbase, VALUE c)
-{
- rb_set_class_path_string(c, cbase, rb_id2str(id));
- rb_const_set(cbase, id, c);
- return c;
-}
-
-static VALUE
vm_declare_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
{
/* new class declaration */
VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super : rb_cObject;
- VALUE c = declare_under(id, cbase, rb_define_class_id(id, s));
+ VALUE c = rb_define_class_id(id, s);
rb_define_alloc_func(c, rb_get_alloc_func(c));
+ rb_set_class_path_string(c, cbase, rb_id2str(id));
rb_class_inherited(s, c);
+ rb_const_set(cbase, id, c);
return c;
}
static VALUE
vm_declare_module(ID id, VALUE cbase)
{
- /* new module declaration */
- return declare_under(id, cbase, rb_module_new());
+ VALUE m = rb_module_new();
+ rb_set_class_path_string(m, cbase, rb_id2str(id));
+ rb_const_set(cbase, id, m);
+ return m;
}
NORETURN(static void unmatched_redefinition(const char *type, VALUE cbase, ID id, VALUE old));