diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-06-27 07:48:50 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-06-27 07:48:50 +0000 |
commit | 8ddbbb33242f413845079b0274c28331cb4aa0f5 (patch) | |
tree | 522b12dada77b09073a58130c99c77d62c895b87 /class.c | |
parent | 8634544fa74be0995582bc8056763fcfd38a0702 (diff) | |
download | ruby-8ddbbb33242f413845079b0274c28331cb4aa0f5.tar.gz |
Module#prepend
* class.c (rb_prepend_module): prepend module into another module.
* eval.c (rb_mod_prepend): new method Module#prepend. [Feature #1102]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36234 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'class.c')
-rw-r--r-- | class.c | 42 |
1 files changed, 42 insertions, 0 deletions
@@ -56,6 +56,7 @@ class_alloc(VALUE flags, VALUE klass) RCLASS_CONST_TBL(obj) = 0; RCLASS_M_TBL(obj) = 0; RCLASS_SUPER(obj) = 0; + RCLASS_ORIGIN(obj) = (VALUE)obj; RCLASS_IV_INDEX_TBL(obj) = 0; return (VALUE)obj; } @@ -687,6 +688,8 @@ rb_include_module(VALUE klass, VALUE module) break; } } + if (c == klass) + c = RCLASS_ORIGIN(klass); c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c)); if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries) changed = 1; @@ -696,6 +699,45 @@ rb_include_module(VALUE klass, VALUE module) if (changed) rb_clear_cache(); } +void +rb_prepend_module(VALUE klass, VALUE module) +{ + VALUE p, c, origin; + + rb_frozen_class_p(klass); + if (!OBJ_UNTRUSTED(klass)) { + rb_secure(4); + } + + Check_Type(module, T_MODULE); + + OBJ_INFECT(klass, module); + c = RCLASS_SUPER(klass); + if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module)) + rb_raise(rb_eArgError, "cyclic include detected"); + for (p = c; p; p = RCLASS_SUPER(p)) { + if (BUILTIN_TYPE(p) == T_ICLASS) { + if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) { + rb_raise(rb_eArgError, "already prepended module"); + } + } + } + origin = RCLASS_ORIGIN(klass); + if (origin == klass) { + origin = class_alloc(T_ICLASS, rb_cClass); + RCLASS_SUPER(origin) = RCLASS_SUPER(klass); + RCLASS_SUPER(klass) = origin; + RCLASS_ORIGIN(klass) = origin; + RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass); + RCLASS_M_TBL(klass) = 0; + c = origin; + } + RCLASS_SUPER(klass) = include_class_new(module, c); + if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries) { + rb_clear_cache_by_class(klass); + } +} + /* * call-seq: * mod.included_modules -> array |