Yukihiro Matsumotoさんの <983261131.203795.1045.nullmailer / ev.netlab.zetabits.com>から > |実装上、特異クラスを作れない(あるいは作らない)クラスの > |インスタンスに対して、instance_evalの中で定数を参照すると > |死んでしまいます。(定数は定義していなくても同じ) > |誰も困る人はいないと思って、報告していませんでしたが。 > > そんなあ、気がついたら教えてくださいよお。 > > --- eval.c 2001/02/27 07:52:11 1.158 > +++ eval.c 2001/02/27 08:05:17 > @@ -1453,2 +1453,3 @@ > > + if (NIL_P(klass)) return rb_const_get(rb_cObject, id); > if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, &result)) { 直りきっていませんでした。 以下の場合が駄目です。 class Fixnum; X = 200; end 100.instance_eval { p X } # => # /home/kosako/ruby/test/single2.rb:3: uninitialized constant X (NameError) # from /home/kosako/ruby/test/single2.rb:3:in `instance_eval' # from /home/kosako/ruby/test/single2.rb:3:in `instance_eval' # from /home/kosako/ruby/test/single2.rb:3 修正は、特異クラスを生成するのが、 一番簡単なのではないでしょうか? --- ruby.h.orig Mon Feb 19 00:14:58 2001 +++ ruby.h Tue Mar 13 16:31:09 2001 @@ -340,6 +340,7 @@ #define RFILE(obj) (R_CAST(RFile)(obj)) #define FL_SINGLETON FL_USER0 +#define FL_INSTANCE_EVAL FL_USER1 #define FL_MARK (1<<6) #define FL_FINALIZE (1<<7) #define FL_TAINT (1<<8) --- eval.c.orig Mon Mar 12 20:45:08 2001 +++ eval.c Tue Mar 13 16:30:55 2001 @@ -1420,6 +1420,7 @@ } #define ruby_cbase (RNODE(ruby_frame->cbase)->nd_clss) +#define RESTRICTED_CLASS_P(c) FL_TEST(c, FL_INSTANCE_EVAL) static VALUE ev_const_defined(cref, id) @@ -1431,7 +1432,6 @@ while (cbase && cbase->nd_clss != rb_cObject) { struct RClass *klass = RCLASS(cbase->nd_clss); - if (NIL_P(klass)) return rb_const_defined(rb_cObject, id); if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, 0)) { return Qtrue; } @@ -1451,7 +1451,6 @@ while (cbase && cbase->nd_clss != rb_cObject) { struct RClass *klass = RCLASS(cbase->nd_clss); - if (NIL_P(klass)) return rb_const_get(rb_cObject, id); if (klass->iv_tbl && st_lookup(klass->iv_tbl, id, &result)) { return result; } @@ -2693,7 +2692,7 @@ break; case NODE_CDECL: - if (NIL_P(ruby_class)) { + if (RESTRICTED_CLASS_P(ruby_class)) { rb_raise(rb_eTypeError, "no class/module to define constant"); } result = rb_eval(self, node->nd_value); @@ -2701,7 +2700,7 @@ break; case NODE_CVDECL: - if (NIL_P(ruby_cbase)) { + if (RESTRICTED_CLASS_P(ruby_cbase)) { rb_raise(rb_eTypeError, "no class/module to define class variable"); } result = rb_eval(self, node->nd_value); @@ -2932,7 +2931,7 @@ VALUE origin; int noex; - if (NIL_P(ruby_class)) { + if (RESTRICTED_CLASS_P(ruby_class)) { rb_raise(rb_eTypeError, "no class/module to add method"); } if (ruby_class == rb_cObject && node->nd_mid == init) { @@ -3033,7 +3032,7 @@ break; case NODE_UNDEF: - if (NIL_P(ruby_class)) { + if (RESTRICTED_CLASS_P(ruby_class)) { rb_raise(rb_eTypeError, "no class to undef method"); } rb_undef(ruby_class, node->nd_mid); @@ -3041,7 +3040,7 @@ break; case NODE_ALIAS: - if (NIL_P(ruby_class)) { + if (RESTRICTED_CLASS_P(ruby_class)) { rb_raise(rb_eTypeError, "no class to make alias"); } rb_alias(ruby_class, node->nd_new, node->nd_old); @@ -3058,7 +3057,7 @@ { VALUE super, klass, tmp; - if (NIL_P(ruby_class)) { + if (RESTRICTED_CLASS_P(ruby_class)) { rb_raise(rb_eTypeError, "no outer class/module"); } if (node->nd_super) { @@ -3118,7 +3117,7 @@ { VALUE module; - if (NIL_P(ruby_class)) { + if (RESTRICTED_CLASS_P(ruby_class)) { rb_raise(rb_eTypeError, "no outer class/module"); } module = 0; @@ -5060,6 +5059,30 @@ } } +static VALUE +get_special_const_singleton_class(self) + VALUE self; +{ + static VALUE table = Qnil; + VALUE klass, singleton; + + if (table == Qnil) { + table = rb_hash_new(); + rb_global_variable(&table); + } + + klass = CLASS_OF(self); + singleton = rb_hash_aref(table, klass); + if (singleton == Qnil) { + singleton = rb_singleton_class_new(klass); + FL_SET(singleton, FL_INSTANCE_EVAL); + rb_singleton_class_attached(singleton, self); + rb_hash_aset(table, klass, singleton); + } + + return singleton; +} + VALUE rb_obj_instance_eval(argc, argv, self) int argc; @@ -5069,7 +5092,7 @@ VALUE klass; if (rb_special_const_p(self)) { - klass = Qnil; + klass = get_special_const_singleton_class(self); } else { klass = rb_singleton_class(self); ---- 小迫@ソフネック 渋谷区恵比寿1-15-1