mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Already initialized modules cannot be replaced [Bug #17048]
This commit is contained in:
parent
8f41c791b1
commit
178ee1e801
Notes:
git
2021-09-17 19:05:26 +09:00
4 changed files with 80 additions and 30 deletions
43
class.c
43
class.c
|
@ -248,6 +248,12 @@ rb_class_new(VALUE super)
|
||||||
return rb_class_boot(super);
|
return rb_class_boot(super);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_class_s_alloc(VALUE klass)
|
||||||
|
{
|
||||||
|
return rb_class_boot(0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clone_method(VALUE old_klass, VALUE new_klass, ID mid, const rb_method_entry_t *me)
|
clone_method(VALUE old_klass, VALUE new_klass, ID mid, const rb_method_entry_t *me)
|
||||||
{
|
{
|
||||||
|
@ -345,12 +351,35 @@ copy_tables(VALUE clone, VALUE orig)
|
||||||
|
|
||||||
static bool ensure_origin(VALUE klass);
|
static bool ensure_origin(VALUE klass);
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
RMODULE_UNINITIALIZED(VALUE module)
|
||||||
|
{
|
||||||
|
return RCLASS_SUPER(module) == rb_cBasicObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_module_check_initialiable(VALUE mod)
|
||||||
|
{
|
||||||
|
if (!RMODULE_UNINITIALIZED(mod)) {
|
||||||
|
rb_raise(rb_eTypeError, "already initialized module");
|
||||||
|
}
|
||||||
|
RB_OBJ_WRITE(mod, &RCLASS(mod)->super, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* :nodoc: */
|
/* :nodoc: */
|
||||||
VALUE
|
VALUE
|
||||||
rb_mod_init_copy(VALUE clone, VALUE orig)
|
rb_mod_init_copy(VALUE clone, VALUE orig)
|
||||||
{
|
{
|
||||||
if (RB_TYPE_P(clone, T_CLASS)) {
|
switch (BUILTIN_TYPE(clone)) {
|
||||||
|
case T_CLASS:
|
||||||
|
case T_ICLASS:
|
||||||
class_init_copy_check(clone, orig);
|
class_init_copy_check(clone, orig);
|
||||||
|
break;
|
||||||
|
case T_MODULE:
|
||||||
|
rb_module_check_initialiable(clone);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!OBJ_INIT_COPY(clone, orig)) return clone;
|
if (!OBJ_INIT_COPY(clone, orig)) return clone;
|
||||||
|
|
||||||
|
@ -774,6 +803,15 @@ rb_define_class_id_under(VALUE outer, ID id, VALUE super)
|
||||||
return klass;
|
return klass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_module_s_alloc(VALUE klass)
|
||||||
|
{
|
||||||
|
VALUE mod = class_alloc(T_MODULE, klass);
|
||||||
|
RCLASS_M_TBL_INIT(mod);
|
||||||
|
RB_OBJ_WRITE(mod, &RCLASS(mod)->super, rb_cBasicObject);
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_module_new(void)
|
rb_module_new(void)
|
||||||
{
|
{
|
||||||
|
@ -878,6 +916,9 @@ ensure_includable(VALUE klass, VALUE module)
|
||||||
{
|
{
|
||||||
rb_class_modify_check(klass);
|
rb_class_modify_check(klass);
|
||||||
Check_Type(module, T_MODULE);
|
Check_Type(module, T_MODULE);
|
||||||
|
if (RMODULE_UNINITIALIZED(module)) {
|
||||||
|
rb_raise(rb_eArgError, "uninitialized module");
|
||||||
|
}
|
||||||
if (!NIL_P(rb_refinement_module_get_refined_class(module))) {
|
if (!NIL_P(rb_refinement_module_get_refined_class(module))) {
|
||||||
rb_raise(rb_eArgError, "refinement module is not allowed");
|
rb_raise(rb_eArgError, "refinement module is not allowed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,9 @@ void rb_class_subclass_add(VALUE super, VALUE klass);
|
||||||
void rb_class_remove_from_super_subclasses(VALUE);
|
void rb_class_remove_from_super_subclasses(VALUE);
|
||||||
int rb_singleton_class_internal_p(VALUE sklass);
|
int rb_singleton_class_internal_p(VALUE sklass);
|
||||||
VALUE rb_class_boot(VALUE);
|
VALUE rb_class_boot(VALUE);
|
||||||
|
VALUE rb_class_s_alloc(VALUE klass);
|
||||||
|
VALUE rb_module_s_alloc(VALUE klass);
|
||||||
|
void rb_module_check_initialiable(VALUE module);
|
||||||
VALUE rb_make_metaclass(VALUE, VALUE);
|
VALUE rb_make_metaclass(VALUE, VALUE);
|
||||||
VALUE rb_include_class_new(VALUE, VALUE);
|
VALUE rb_include_class_new(VALUE, VALUE);
|
||||||
void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE);
|
void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE);
|
||||||
|
|
24
object.c
24
object.c
|
@ -1766,20 +1766,7 @@ rb_mod_cmp(VALUE mod, VALUE arg)
|
||||||
return INT2FIX(1);
|
return INT2FIX(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE rb_mod_initialize_exec(VALUE module);
|
||||||
rb_module_s_alloc(VALUE klass)
|
|
||||||
{
|
|
||||||
VALUE mod = rb_module_new();
|
|
||||||
|
|
||||||
RBASIC_SET_CLASS(mod, klass);
|
|
||||||
return mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
|
||||||
rb_class_s_alloc(VALUE klass)
|
|
||||||
{
|
|
||||||
return rb_class_boot(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
|
@ -1809,6 +1796,13 @@ rb_class_s_alloc(VALUE klass)
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_mod_initialize(VALUE module)
|
rb_mod_initialize(VALUE module)
|
||||||
|
{
|
||||||
|
rb_module_check_initialiable(module);
|
||||||
|
return rb_mod_initialize_exec(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_mod_initialize_exec(VALUE module)
|
||||||
{
|
{
|
||||||
if (rb_block_given_p()) {
|
if (rb_block_given_p()) {
|
||||||
rb_mod_module_exec(1, &module, module);
|
rb_mod_module_exec(1, &module, module);
|
||||||
|
@ -1879,7 +1873,7 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass)
|
||||||
RCLASS_SET_SUPER(klass, super);
|
RCLASS_SET_SUPER(klass, super);
|
||||||
rb_make_metaclass(klass, RBASIC(super)->klass);
|
rb_make_metaclass(klass, RBASIC(super)->klass);
|
||||||
rb_class_inherited(super, klass);
|
rb_class_inherited(super, klass);
|
||||||
rb_mod_initialize(klass);
|
rb_mod_initialize_exec(klass);
|
||||||
|
|
||||||
return klass;
|
return klass;
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,19 +404,20 @@ class TestModule < Test::Unit::TestCase
|
||||||
assert_equal([:MIXIN, :USER], User.constants.sort)
|
assert_equal([:MIXIN, :USER], User.constants.sort)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_self_initialize_copy
|
def test_initialize_copy
|
||||||
bug9535 = '[ruby-dev:47989] [Bug #9535]'
|
mod = Module.new { define_method(:foo) {:first} }
|
||||||
m = Module.new do
|
klass = Class.new { include mod }
|
||||||
def foo
|
instance = klass.new
|
||||||
:ok
|
assert_equal(:first, instance.foo)
|
||||||
end
|
new_mod = Module.new { define_method(:foo) { :second } }
|
||||||
initialize_copy(self)
|
assert_raise(TypeError) do
|
||||||
|
mod.send(:initialize_copy, new_mod)
|
||||||
end
|
end
|
||||||
assert_equal(:ok, Object.new.extend(m).foo, bug9535)
|
4.times { GC.start }
|
||||||
|
assert_equal(:first, instance.foo) # [BUG] unreachable
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_initialize_copy_empty
|
def test_initialize_copy_empty
|
||||||
bug9813 = '[ruby-dev:48182] [Bug #9813]'
|
|
||||||
m = Module.new do
|
m = Module.new do
|
||||||
def x
|
def x
|
||||||
end
|
end
|
||||||
|
@ -426,12 +427,11 @@ class TestModule < Test::Unit::TestCase
|
||||||
assert_equal([:x], m.instance_methods)
|
assert_equal([:x], m.instance_methods)
|
||||||
assert_equal([:@x], m.instance_variables)
|
assert_equal([:@x], m.instance_variables)
|
||||||
assert_equal([:X], m.constants)
|
assert_equal([:X], m.constants)
|
||||||
m.module_eval do
|
assert_raise(TypeError) do
|
||||||
initialize_copy(Module.new)
|
m.module_eval do
|
||||||
|
initialize_copy(Module.new)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
assert_empty(m.instance_methods, bug9813)
|
|
||||||
assert_empty(m.instance_variables, bug9813)
|
|
||||||
assert_empty(m.constants, bug9813)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_dup
|
def test_dup
|
||||||
|
@ -3094,6 +3094,18 @@ class TestModule < Test::Unit::TestCase
|
||||||
assert_match(/::Foo$/, mod.name, '[Bug #14895]')
|
assert_match(/::Foo$/, mod.name, '[Bug #14895]')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_include_allocated
|
||||||
|
assert_raise(ArgumentError) do
|
||||||
|
Module.new {include Module.allocate}
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) do
|
||||||
|
Module.new {prepend Module.allocate}
|
||||||
|
end
|
||||||
|
assert_raise(ArgumentError) do
|
||||||
|
Object.new.extend Module.allocate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def assert_top_method_is_private(method)
|
def assert_top_method_is_private(method)
|
||||||
|
|
Loading…
Add table
Reference in a new issue