[前][次][番号順一覧][スレッド一覧]

ruby-changes:2113

From: ko1@a...
Date: 3 Oct 2007 15:48:32 +0900
Subject: [ruby-changes:2113] matz - Ruby:r13604 (trunk): * variable.c (rb_cvar_set): check whether class variable is

matz	2007-10-03 15:48:06 +0900 (Wed, 03 Oct 2007)

  New Revision: 13604

  Modified files:
    trunk/ChangeLog
    trunk/test/ruby/test_variable.rb
    trunk/variable.c

  Log:
    * variable.c (rb_cvar_set): check whether class variable is
      defined in superclasses.  root classes have higher priority.
      removes lower class variable entry from IV_TBL (if it's defined
      in classes, not modules).
    
    * variable.c (rb_cvar_get): ditto.

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/variable.c?r1=13604&r2=13603
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/ruby/test_variable.rb?r1=13604&r2=13603
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=13604&r2=13603

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 13603)
+++ ChangeLog	(revision 13604)
@@ -1,3 +1,12 @@
+Wed Oct  3 15:43:15 2007  Yukihiro Matsumoto  <matz@r...>
+
+	* variable.c (rb_cvar_set): check whether class variable is
+	  defined in superclasses.  root classes have higher priority.
+	  removes lower class variable entry from IV_TBL (if it's defined
+	  in classes, not modules).
+
+	* variable.c (rb_cvar_get): ditto.
+
 Wed Oct  3 10:06:53 2007  Nobuyoshi Nakada  <nobu@r...>
 
 	* ruby.c (ruby_process_options): push frame with program name.
Index: variable.c
===================================================================
--- variable.c	(revision 13603)
+++ variable.c	(revision 13604)
@@ -1701,15 +1701,53 @@
     rb_define_const(rb_cObject, name, val);
 }
 
+static VALUE
+original_module(c)
+    VALUE c;
+{
+    if (TYPE(c) == T_ICLASS)
+	return RBASIC(c)->klass;
+    return c;
+}
+
 void
 rb_cvar_set(VALUE klass, ID id, VALUE val)
 {
-    mod_av_set(klass, id, val, Qfalse);
+    VALUE tmp;
+    VALUE front = 0, target = 0;
+
+    tmp = klass;
+    while (tmp) {
+	if (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp),id,0)) {
+	    if (!front) front = tmp;
+	    target = tmp;
+	}
+	tmp = RCLASS_SUPER(tmp);
+    }
+    if (target) {
+	if (front && target != front) {
+	    ID did = id;
+
+	    if (RTEST(ruby_verbose)) {
+		rb_warning("class variable %s of %s is overtaken by %s",
+			   rb_id2name(id), rb_class2name(original_module(front)),
+			   rb_class2name(original_module(target)));
+	    }
+	    if (BUILTIN_TYPE(front) == T_CLASS) {
+		st_delete(RCLASS_IV_TBL(front),&did,0);
+	    }
+	}
+    }
+    else {
+	target = klass;
+    }
+
+    mod_av_set(target, id, val, Qfalse);
 }
 
 #define CVAR_LOOKUP(v,r) do {\
     if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),id,(v))) {\
-	return (r);\
+	r;\
     }\
     if (FL_TEST(klass, FL_SINGLETON) ) {\
 	VALUE obj = rb_iv_get(klass, "__attached__");\
@@ -1728,7 +1766,7 @@
     }\
     while (klass) {\
 	if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),id,(v))) {\
-	    return (r);\
+	    r;\
 	}\
 	klass = RCLASS_SUPER(klass);\
     }\
@@ -1737,20 +1775,34 @@
 VALUE
 rb_cvar_get(VALUE klass, ID id)
 {
-    VALUE value, tmp;
+    VALUE value, tmp, front = 0, target = 0;
 
     tmp = klass;
-    CVAR_LOOKUP(&value, value);
-    rb_name_error(id,"uninitialized class variable %s in %s",
-		  rb_id2name(id), rb_class2name(tmp));
-    return Qnil;		/* not reached */
+    CVAR_LOOKUP(&value, {if (!front) front = klass; target = klass;});
+    if (!target) {
+	rb_name_error(id,"uninitialized class variable %s in %s",
+		      rb_id2name(id), rb_class2name(tmp));
+    }
+    if (front && target != front) {
+	ID did = id;
+
+	if (RTEST(ruby_verbose)) {
+	    rb_warning("class variable %s of %s is overtaken by %s",
+		       rb_id2name(id), rb_class2name(original_module(front)),
+		       rb_class2name(original_module(target)));
+	}
+	if (BUILTIN_TYPE(front) == T_CLASS) {
+	    st_delete(RCLASS_IV_TBL(front),&did,0);
+	}
+    }
+    return value;
 }
 
 VALUE
 rb_cvar_defined(VALUE klass, ID id)
 {
     if (!klass) return Qfalse;
-    CVAR_LOOKUP(0,Qtrue);
+    CVAR_LOOKUP(0,return Qtrue);
     return Qfalse;
 }
 
Index: test/ruby/test_variable.rb
===================================================================
--- test/ruby/test_variable.rb	(revision 13603)
+++ test/ruby/test_variable.rb	(revision 13604)
@@ -25,7 +25,7 @@
   end
 
   class Titans < Gods
-    @@rule = "Cronus"			# do not affect @@rule in Gods
+    @@rule = "Cronus"			# modifies @@rule in Gods
     include Olympians
     def ruler4
       @@rule
@@ -44,13 +44,13 @@
     $_ = foobar
     assert_equal(foobar, $_)
 
-    assert_equal("Uranus", Gods.new.ruler0)
-    assert_equal("Uranus", Gods.ruler1)
-    assert_equal("Uranus", Gods.ruler2)
-    assert_equal("Uranus", Titans.ruler1)
-    assert_equal("Uranus", Titans.ruler2)
+    assert_equal("Cronus", Gods.new.ruler0)
+    assert_equal("Cronus", Gods.ruler1)
+    assert_equal("Cronus", Gods.ruler2)
+    assert_equal("Cronus", Titans.ruler1)
+    assert_equal("Cronus", Titans.ruler2)
     atlas = Titans.new
-    assert_equal("Uranus", atlas.ruler0)
+    assert_equal("Cronus", atlas.ruler0)
     assert_equal("Zeus", atlas.ruler3)
     assert_equal("Cronus", atlas.ruler4)
   end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]