Fix Class inherited hook ordering

In CRuby the inherited method is invoked before Class.new yields to the
block.

An "already initialized error" exception is also removed since the
inherited method is now invoked before initialization and can set
instance variables on a class.
This commit is contained in:
Pete Kinnecom
2026-05-07 15:49:26 +00:00
parent 28624ecfd8
commit ebfdf8ae43
2 changed files with 37 additions and 5 deletions
+1 -5
View File
@@ -3077,10 +3077,6 @@ mrb_class_initialize(mrb_state *mrb, mrb_value obj)
{
struct RClass *c = mrb_class_ptr(obj);
if (c->iv) {
mrb_raise(mrb, E_TYPE_ERROR, "already initialized class");
}
mrb_value a, b;
mrb_get_args(mrb, "|C&", &a, &b);
if (!mrb_nil_p(b)) {
@@ -3099,6 +3095,7 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv)
super = mrb_obj_value(mrb->object_class);
}
mrb_value new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super)));
mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
mrb_sym mid = MRB_SYM(initialize);
if (mrb_func_basic_p(mrb, new_class, mid, mrb_class_initialize)) {
mrb_class_initialize(mrb, new_class);
@@ -3106,7 +3103,6 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv)
else {
mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk);
}
mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class));
return new_class;
}
+36
View File
@@ -503,3 +503,39 @@ assert('module with extended callback') do
assert_true BarBeingExtended.respond_to?(:answer)
assert_equal 42, BarBeingExtended.answer
end
assert("inherited hook runs before block body") do
class A
def self.values
@values ||= []
end
def self.inherited(mod)
mod.values << 1
end
end
klass = Class.new(A) do
self.values << 2
end
assert_equal [1, 2], klass.values
end
assert("inherited hook runs before class body") do
class A
def self.values
@values ||= []
end
def self.inherited(mod)
mod.values << 1
end
end
class B < A
self.values << 2
end
assert_equal [1, 2], B.values
end