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:
parent
ee2ac58e4d
commit
91a079cc86
3 changed files with 77 additions and 16 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
70
variable.c
70
variable.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue