Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,24 @@ static bool ensure_origin(VALUE klass);
static inline bool
RMODULE_UNINITIALIZED(VALUE module)
{
return RCLASS_SUPER(module) == rb_cBasicObject;
VALUE mod = module;
while ((mod = RCLASS_SUPER(mod))) {
if (mod == rb_cBasicObject) return true;
}
return false;
}

static inline void
RMODULE_INITIALIZE(VALUE module)
{
if (FL_TEST(module, RMODULE_IS_REFINEMENT)) return;

do {
if (RCLASS_SUPER(module) == rb_cBasicObject) {
RB_OBJ_WRITE(module, &RCLASS(module)->super, 0);
break;
}
} while ((module = RCLASS_SUPER(module)));
}

void
Expand All @@ -363,7 +380,7 @@ rb_module_check_initializable(VALUE mod)
if (!RMODULE_UNINITIALIZED(mod)) {
rb_raise(rb_eTypeError, "already initialized module");
}
RB_OBJ_WRITE(mod, &RCLASS(mod)->super, 0);
RMODULE_INITIALIZE(mod);
}

/* :nodoc: */
Expand Down Expand Up @@ -917,7 +934,7 @@ ensure_includable(VALUE klass, VALUE module)
rb_class_modify_check(klass);
Check_Type(module, T_MODULE);
if (RMODULE_UNINITIALIZED(module)) {
RB_OBJ_WRITE(module, &RCLASS(module)->super, 0);
RMODULE_INITIALIZE(module);
/* no more re-initialization */
}
if (!NIL_P(rb_refinement_module_get_refined_class(module))) {
Expand Down
23 changes: 23 additions & 0 deletions test/ruby/test_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,29 @@ def initialize_copy(other)
end
end

def test_initialize_subclass_with_included_module
mod = Class.new(Module) do
const_set(:InstanceMethods, Module.new)
define_method(:initialize) do |aaa:|
include mod::InstanceMethods
end
end
foo = Class.new do
def initialize(key:)
end
end

bar = Class.new(foo) do
include mod.new(aaa: 1)
end

ancestors = bar.ancestors
assert_equal(bar, ancestors.shift)
assert_instance_of(mod, ancestors.shift)
assert_equal([mod::InstanceMethods, foo, Object], ancestors[0..2])
assert_instance_of(bar, bar.new(key: 1))
end

def test_dup
OtherSetup.call

Expand Down