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