1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13604 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2007-10-03 06:48:06 +00:00
parent ee2ac58e4d
commit 91a079cc86
3 changed files with 77 additions and 16 deletions

View file

@ -1,3 +1,12 @@
Wed Oct 3 15:43:15 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
* 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@ruby-lang.org>
* ruby.c (ruby_process_options): push frame with program name.

View file

@ -25,7 +25,7 @@ class TestVariable < Test::Unit::TestCase
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 @@ class TestVariable < Test::Unit::TestCase
$_ = 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

View file

@ -1701,15 +1701,53 @@ rb_define_global_const(const char *name, VALUE val)
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 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
}\
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 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
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;
}