diff options
-rw-r--r-- | class.c | 43 | ||||
-rw-r--r-- | internal/class.h | 3 | ||||
-rw-r--r-- | object.c | 24 | ||||
-rw-r--r-- | test/ruby/test_module.rb | 40 |
4 files changed, 80 insertions, 30 deletions
@@ -248,6 +248,12 @@ rb_class_new(VALUE super) return rb_class_boot(super); } +VALUE +rb_class_s_alloc(VALUE klass) +{ + return rb_class_boot(0); +} + static void 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 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: */ VALUE 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); + break; + case T_MODULE: + rb_module_check_initialiable(clone); + break; + default: + break; } if (!OBJ_INIT_COPY(clone, orig)) return clone; @@ -775,6 +804,15 @@ rb_define_class_id_under(VALUE outer, ID id, VALUE super) } 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 rb_module_new(void) { VALUE mdl = class_alloc(T_MODULE, rb_cModule); @@ -878,6 +916,9 @@ ensure_includable(VALUE klass, VALUE module) { rb_class_modify_check(klass); 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))) { rb_raise(rb_eArgError, "refinement module is not allowed"); } diff --git a/internal/class.h b/internal/class.h index 00ee62facf..a7f7e56340 100644 --- a/internal/class.h +++ b/internal/class.h @@ -113,6 +113,9 @@ void rb_class_subclass_add(VALUE super, VALUE klass); void rb_class_remove_from_super_subclasses(VALUE); int rb_singleton_class_internal_p(VALUE sklass); 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_include_class_new(VALUE, VALUE); void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE); @@ -1766,20 +1766,7 @@ rb_mod_cmp(VALUE mod, VALUE arg) return INT2FIX(1); } -static VALUE -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); -} +static VALUE rb_mod_initialize_exec(VALUE module); /* * call-seq: @@ -1810,6 +1797,13 @@ rb_class_s_alloc(VALUE klass) static VALUE 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()) { 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); rb_make_metaclass(klass, RBASIC(super)->klass); rb_class_inherited(super, klass); - rb_mod_initialize(klass); + rb_mod_initialize_exec(klass); return klass; } diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 98c9128406..bbe84cd9ff 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -404,19 +404,20 @@ class TestModule < Test::Unit::TestCase assert_equal([:MIXIN, :USER], User.constants.sort) end - def test_self_initialize_copy - bug9535 = '[ruby-dev:47989] [Bug #9535]' - m = Module.new do - def foo - :ok - end - initialize_copy(self) + def test_initialize_copy + mod = Module.new { define_method(:foo) {:first} } + klass = Class.new { include mod } + instance = klass.new + assert_equal(:first, instance.foo) + new_mod = Module.new { define_method(:foo) { :second } } + assert_raise(TypeError) do + mod.send(:initialize_copy, new_mod) end - assert_equal(:ok, Object.new.extend(m).foo, bug9535) + 4.times { GC.start } + assert_equal(:first, instance.foo) # [BUG] unreachable end def test_initialize_copy_empty - bug9813 = '[ruby-dev:48182] [Bug #9813]' m = Module.new do def x end @@ -426,12 +427,11 @@ class TestModule < Test::Unit::TestCase assert_equal([:x], m.instance_methods) assert_equal([:@x], m.instance_variables) assert_equal([:X], m.constants) - m.module_eval do - initialize_copy(Module.new) + assert_raise(TypeError) do + m.module_eval do + initialize_copy(Module.new) + end end - assert_empty(m.instance_methods, bug9813) - assert_empty(m.instance_variables, bug9813) - assert_empty(m.constants, bug9813) end def test_dup @@ -3094,6 +3094,18 @@ class TestModule < Test::Unit::TestCase assert_match(/::Foo$/, mod.name, '[Bug #14895]') 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 def assert_top_method_is_private(method) |