Skip to content

Commit de48e47

Browse files
committed
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.
1 parent dd7deef commit de48e47

File tree

7 files changed

+72
-21
lines changed

7 files changed

+72
-21
lines changed

class.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,8 +1004,8 @@ rb_define_class(const char *name, VALUE super)
10041004
}
10051005
klass = rb_define_class_id(id, super);
10061006
rb_vm_register_global_object(klass);
1007-
rb_const_set(rb_cObject, id, klass);
10081007
rb_class_inherited(super, klass);
1008+
rb_const_set(rb_cObject, id, klass);
10091009

10101010
return klass;
10111011
}
@@ -1043,8 +1043,8 @@ rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super)
10431043
}
10441044
klass = rb_define_class_id(id, super);
10451045
rb_set_class_path_string(klass, outer, rb_id2str(id));
1046-
rb_const_set(outer, id, klass);
10471046
rb_class_inherited(super, klass);
1047+
rb_const_set(outer, id, klass);
10481048

10491049
return klass;
10501050
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module CoreClassSpecs
2+
module Callbacks
3+
class Base
4+
def self.inherited(subclass)
5+
subclass.const_set(:INHERITED_NAME, subclass.name)
6+
ORDER << [:inherited, subclass, eval("defined?(#{subclass.name})")]
7+
super
8+
end
9+
end
10+
11+
ORDER = []
12+
13+
def self.const_added(const_name)
14+
ORDER << [:const_added, const_name, eval("defined?(#{const_name})")]
15+
super
16+
end
17+
18+
class Child < Base
19+
end
20+
end
21+
end

spec/ruby/core/class/inherited_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require_relative '../../spec_helper'
22
require_relative 'fixtures/classes'
3+
require_relative 'fixtures/callback_order'
34

45
describe "Class.inherited" do
56

@@ -98,4 +99,16 @@ class << top; protected :inherited; end
9899
-> { Class.new(top) }.should_not raise_error
99100
end
100101

102+
it "is invoked after the class is named when using class definition syntax" do
103+
CoreClassSpecs::Callbacks::Child::INHERITED_NAME.should == "CoreClassSpecs::Callbacks::Child"
104+
end
105+
106+
ruby_version_is "3.5" do # https://bugs.ruby-lang.org/issues/21143
107+
it "is invoked before `const_added`" do
108+
CoreClassSpecs::Callbacks::ORDER.should == [
109+
[:inherited, CoreClassSpecs::Callbacks::Child, nil],
110+
[:const_added, :Child, "constant"],
111+
]
112+
end
113+
end
101114
end

spec/ruby/optional/capi/class_spec.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,17 @@
383383
CApiClassSpecs.const_get(cls.name)
384384
}.should raise_error(NameError, /wrong constant name/)
385385
end
386+
387+
ruby_version_is "3.5" do
388+
it "calls .inherited before .const_added" do
389+
ScratchPad.record([])
390+
@s.rb_define_class_id_under(CApiClassSpecs::Callbacks, :Subclass, CApiClassSpecs::Callbacks)
391+
ScratchPad.recorded.should == [
392+
[:inherited, "CApiClassSpecs::Callbacks::Subclass"],
393+
[:const_added, :Subclass],
394+
]
395+
end
396+
end
386397
end
387398

388399
describe "rb_define_class_id_under" do

spec/ruby/optional/capi/fixtures/class.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,14 @@ class B
101101
module M
102102
end
103103
end
104+
105+
class Callbacks
106+
def self.inherited(child)
107+
ScratchPad << [:inherited, child.name]
108+
end
109+
110+
def self.const_added(const_name)
111+
ScratchPad << [:const_added, const_name]
112+
end
113+
end
104114
end

test/ruby/test_settracefunc.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,14 @@ def test_class
168168
events.shift)
169169
assert_equal(["line", 4, __method__, self.class],
170170
events.shift)
171-
assert_equal(["c-call", 4, :const_added, Module],
172-
events.shift)
173-
assert_equal(["c-return", 4, :const_added, Module],
174-
events.shift)
175171
assert_equal(["c-call", 4, :inherited, Class],
176172
events.shift)
177173
assert_equal(["c-return", 4, :inherited, Class],
178174
events.shift)
175+
assert_equal(["c-call", 4, :const_added, Module],
176+
events.shift)
177+
assert_equal(["c-return", 4, :const_added, Module],
178+
events.shift)
179179
assert_equal(["class", 4, nil, nil],
180180
events.shift)
181181
assert_equal(["line", 5, nil, nil],
@@ -411,10 +411,10 @@ def test_thread_trace
411411

412412
[["c-return", 2, :add_trace_func, Thread],
413413
["line", 3, __method__, self.class],
414-
["c-call", 3, :const_added, Module],
415-
["c-return", 3, :const_added, Module],
416414
["c-call", 3, :inherited, Class],
417415
["c-return", 3, :inherited, Class],
416+
["c-call", 3, :const_added, Module],
417+
["c-return", 3, :const_added, Module],
418418
["class", 3, nil, nil],
419419
["line", 4, nil, nil],
420420
["c-call", 4, :method_added, Module],
@@ -558,10 +558,10 @@ def trace_by_tracepoint *trace_events
558558
[:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing],
559559
[:c_return, 4, "xyzzy", Array, :reverse_each, [1], nil, [1]],
560560
[:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing],
561-
[:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, :nothing],
562-
[:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, nil],
563561
[:c_call, 7, "xyzzy", Class, :inherited, Object, nil, :nothing],
564562
[:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil],
563+
[:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, :nothing],
564+
[:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, nil, nil],
565565
[:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing],
566566
[:line, 8, "xyzzy", nil, nil, xyzzy.class, nil, :nothing],
567567
[:line, 9, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing],

vm_insnhelper.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5744,30 +5744,26 @@ vm_check_if_module(ID id, VALUE mod)
57445744
}
57455745
}
57465746

5747-
static VALUE
5748-
declare_under(ID id, VALUE cbase, VALUE c)
5749-
{
5750-
rb_set_class_path_string(c, cbase, rb_id2str(id));
5751-
rb_const_set(cbase, id, c);
5752-
return c;
5753-
}
5754-
57555747
static VALUE
57565748
vm_declare_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
57575749
{
57585750
/* new class declaration */
57595751
VALUE s = VM_DEFINECLASS_HAS_SUPERCLASS_P(flags) ? super : rb_cObject;
5760-
VALUE c = declare_under(id, cbase, rb_define_class_id(id, s));
5752+
VALUE c = rb_define_class_id(id, s);
57615753
rb_define_alloc_func(c, rb_get_alloc_func(c));
5754+
rb_set_class_path_string(c, cbase, rb_id2str(id));
57625755
rb_class_inherited(s, c);
5756+
rb_const_set(cbase, id, c);
57635757
return c;
57645758
}
57655759

57665760
static VALUE
57675761
vm_declare_module(ID id, VALUE cbase)
57685762
{
5769-
/* new module declaration */
5770-
return declare_under(id, cbase, rb_module_new());
5763+
VALUE m = rb_module_new();
5764+
rb_set_class_path_string(m, cbase, rb_id2str(id));
5765+
rb_const_set(cbase, id, m);
5766+
return m;
57715767
}
57725768

57735769
NORETURN(static void unmatched_redefinition(const char *type, VALUE cbase, ID id, VALUE old));

0 commit comments

Comments
 (0)