>>>>> "Y" == Yukihiro Matsumoto <matz / ruby-lang.org> writes: Y> Do you mean you've implemented private instance variable, even if it's Y> incomplete? If so, show me the code please. Well, here a quick diff (*WARNING* old 1.6.7 : you can see it with NODE_CVASGN) To understand what it do pigeon% cat b.rb #!./ruby class A def initialize @a = 12 @_m = [1,2] end end class B < A def initialize @_m = [2,4] @_n = 6 super end end Marshal.dump(B.new, File.new("aa", "w")) pigeon% pigeon% b.rb pigeon% pigeon% cat c.rb #!/usr/bin/ruby class A end class B < A def b puts "a = #{@a.inspect} - _m = #{@_m.inspect} - _n = #{@_n.inspect}" end end Marshal.load(IO.readlines("aa", nil)[0]).b pigeon% pigeon% c.rb a = 12 - _m = {B=>[2, 4], A=>[1, 2]} - _n = {B=>6} pigeon% Now the problems : 1) you need to have 2 hash access for a private variable, rather than one for a public variable 2) I use #define ID_PRIVATE 0x07 which is used for ID_JUNK in 1.7.* For 1.7 I see only a possibility #define ID_JUNK 0x00 #define ID_PRIVATE 0x07 but this means that *all* bits are used and it will not possible to add new types after this Guy Decoux diff -u ruby-1.6.7/env.h ruby-1.6.m/env.h --- ruby-1.6.7/env.h 2001-03-21 09:04:11.000000000 +0100 +++ ruby-1.6.m/env.h 2002-09-07 15:55:19.000000000 +0200 @@ -20,6 +20,7 @@ ID last_func; VALUE last_class; VALUE cbase; + VALUE curr_class; struct FRAME *prev; struct FRAME *tmp; char *file; diff -u ruby-1.6.7/eval.c ruby-1.6.m/eval.c --- ruby-1.6.7/eval.c 2002-02-27 05:50:29.000000000 +0100 +++ ruby-1.6.m/eval.c 2002-09-11 14:17:29.000000000 +0200 @@ -110,6 +110,8 @@ static VALUE rb_cUnboundMethod; static VALUE umethod_bind _((VALUE, VALUE)); static VALUE rb_mod_define_method _((int, VALUE*, VALUE)); +static VALUE remove_private_variable __((VALUE, VALUE)); +static VALUE rb_current_class __((void)); static int scope_vmode; #define SCOPE_PUBLIC 0 @@ -500,18 +502,19 @@ static struct FRAME *top_frame; static struct SCOPE *top_scope; -#define PUSH_FRAME() { \ - struct FRAME _frame; \ - _frame.prev = ruby_frame; \ - _frame.tmp = 0; \ - _frame.file = ruby_sourcefile; \ - _frame.line = ruby_sourceline; \ - _frame.iter = ruby_iter->iter; \ - _frame.cbase = ruby_frame->cbase; \ - _frame.argc = 0; \ - _frame.argv = 0; \ - _frame.flags = FRAME_ALLOCA; \ - ruby_frame = &_frame; \ +#define PUSH_FRAME() { \ + struct FRAME _frame; \ + _frame.prev = ruby_frame; \ + _frame.tmp = 0; \ + _frame.file = ruby_sourcefile; \ + _frame.line = ruby_sourceline; \ + _frame.iter = ruby_iter->iter; \ + _frame.cbase = ruby_frame->cbase; \ + _frame.curr_class = ruby_frame->curr_class; \ + _frame.argc = 0; \ + _frame.argv = 0; \ + _frame.flags = FRAME_ALLOCA; \ + ruby_frame = &_frame; #define POP_FRAME() \ ruby_sourcefile = _frame.file; \ @@ -1026,6 +1029,7 @@ rb_call_inits(); ruby_class = rb_cObject; ruby_frame->self = ruby_top_self; + ruby_frame->curr_class = rb_cObject; top_cref = rb_node_newnode(NODE_CREF,rb_cObject,0,0); ruby_cref = top_cref; ruby_frame->cbase = (VALUE)ruby_cref; @@ -1266,6 +1270,7 @@ ruby_top_self = rb_obj_clone(ruby_top_self); rb_extend_object(ruby_top_self, ruby_wrapper); PUSH_FRAME(); + ruby_frame->curr_class = ruby_class; ruby_frame->last_func = 0; ruby_frame->last_class = 0; ruby_frame->self = self; @@ -2708,7 +2713,12 @@ case NODE_IASGN: result = rb_eval(self, node->nd_value); - rb_ivar_set(self, node->nd_vid, result); + if (rb_is_instance_id(node->nd_vid)) { + rb_ivar_set(self, node->nd_vid, result); + } + else { + rb_pvar_set(self, rb_current_class(), node->nd_vid, result); + } break; case NODE_CDECL: @@ -2732,7 +2742,11 @@ case NODE_CVASGN: result = rb_eval(self, node->nd_value); - rb_cvar_set(ruby_cbase, node->nd_vid, result); + if (!FL_TEST(ruby_cbase, FL_SINGLETON)) { + rb_cvar_set(ruby_cbase, node->nd_vid, result); + break; + } + rb_cvar_set(rb_iv_get(ruby_cbase, "__attached__"), node->nd_vid, result); break; case NODE_LVAR: @@ -2751,7 +2765,12 @@ break; case NODE_IVAR: - result = rb_ivar_get(self, node->nd_vid); + if (rb_is_instance_id(node->nd_vid)) { + result = rb_ivar_get(self, node->nd_vid); + } + else { + result = rb_pvar_get(self, rb_current_class(), node->nd_vid); + } break; case NODE_CONST: @@ -2941,7 +2960,13 @@ if (ruby_frame->argc != 1) rb_raise(rb_eArgError, "wrong # of arguments(%d for 1)", ruby_frame->argc); - result = rb_ivar_set(self, node->nd_vid, ruby_frame->argv[0]); + if (rb_is_instance_id(node->nd_vid)) { + result = rb_ivar_set(self, node->nd_vid, ruby_frame->argv[0]); + } + else { + result = rb_pvar_set(self, rb_current_class(), node->nd_vid, + ruby_frame->argv[0]); + } break; case NODE_DEFN: @@ -3242,6 +3267,8 @@ PUSH_SCOPE(); PUSH_VARS(); + ruby_frame->curr_class = ruby_class; + if (node->nd_tbl) { VALUE *vars = TMP_ALLOC(node->nd_tbl[0]+1); *vars++ = (VALUE)node; @@ -3570,6 +3597,7 @@ ruby_dyna_vars = block->dyna_vars; } ruby_class = klass?klass:block->klass; + ruby_frame->curr_class = ruby_class; if (!klass) self = block->self; node = block->body; @@ -3826,7 +3854,11 @@ break; case NODE_CVASGN: - rb_cvar_set(ruby_cbase, lhs->nd_vid, val); + if (!FL_TEST(ruby_cbase, FL_SINGLETON)) { + rb_cvar_set(ruby_cbase, lhs->nd_vid, val); + break; + } + rb_cvar_set(rb_iv_get(ruby_cbase, "__attached__"), lhs->nd_vid, val); break; case NODE_MASGN: @@ -4362,6 +4394,9 @@ ruby_frame->self = recv; ruby_frame->argc = argc; ruby_frame->argv = argv; + if (nd_type(body) != NODE_CFUNC) { + ruby_frame->curr_class = klass; + } switch (nd_type(body)) { case NODE_CFUNC: @@ -4902,6 +4937,7 @@ if (TYPE(ruby_class) == T_ICLASS) { ruby_class = RBASIC(ruby_class)->klass; } + ruby_frame->curr_class = ruby_class; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { NODE *node; @@ -5043,6 +5079,7 @@ ruby_frame->last_class = _frame.prev->last_class; ruby_frame->argc = _frame.prev->argc; ruby_frame->argv = _frame.prev->argv; + ruby_frame->curr_class = ruby_class; if (ruby_cbase != under) { ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,under,0,ruby_frame->cbase); } @@ -5248,6 +5285,7 @@ ruby_frame->last_class = 0; ruby_frame->self = self; ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_class,0,0); + ruby_frame->curr_class = ruby_class; PUSH_SCOPE(); /* default visibility is private at loading toplevel */ SCOPE_SET(SCOPE_PRIVATE); @@ -6005,6 +6043,8 @@ rb_define_method(rb_mKernel, "send", rb_f_send, -1); rb_define_method(rb_mKernel, "__send__", rb_f_send, -1); rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1); + rb_define_private_method(rb_mKernel, "remove_private_variable", + remove_private_variable, 1); rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1); rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1); @@ -9091,3 +9131,16 @@ tt = tt->prev; } } + +static VALUE +rb_current_class() +{ + return ruby_frame->curr_class; +} + +static VALUE +remove_private_variable(obj, name) + VALUE obj, name; +{ + return rb_obj_remove_private_variable(obj, rb_current_class(), name); +} diff -u ruby-1.6.7/gc.c ruby-1.6.m/gc.c --- ruby-1.6.7/gc.c 2002-02-13 10:02:15.000000000 +0100 +++ ruby-1.6.m/gc.c 2002-09-07 16:11:11.000000000 +0200 @@ -911,6 +911,7 @@ { mark_locations_array(frame->argv, frame->argc); rb_gc_mark(frame->cbase); + rb_gc_mark(frame->curr_class); } #ifdef __GNUC__ diff -u ruby-1.6.7/intern.h ruby-1.6.m/intern.h --- ruby-1.6.7/intern.h 2002-02-27 05:50:30.000000000 +0100 +++ ruby-1.6.m/intern.h 2002-09-11 12:12:50.000000000 +0200 @@ -267,6 +267,7 @@ void rb_parser_while_loop _((int, int)); int rb_is_const_id _((ID)); int rb_is_instance_id _((ID)); +int rb_is_private_id _((ID)); int rb_is_class_id _((ID)); VALUE rb_backref_get _((void)); void rb_backref_set _((VALUE)); @@ -370,6 +371,11 @@ void rb_mark_generic_ivar _((VALUE)); void rb_mark_generic_ivar_tbl _((void)); void rb_free_generic_ivar _((VALUE)); +VALUE rb_pvar_get _((VALUE, VALUE, ID)); +VALUE rb_pvar_set _((VALUE, VALUE, ID, VALUE)); +VALUE rb_pvar_defined _((VALUE, VALUE, ID)); +VALUE rb_obj_private_variables _((VALUE, VALUE)); +VALUE rb_obj_remove_private_variable _((VALUE, VALUE, VALUE)); VALUE rb_ivar_get _((VALUE, ID)); VALUE rb_ivar_set _((VALUE, ID, VALUE)); VALUE rb_ivar_defined _((VALUE, ID)); diff -u ruby-1.6.7/marshal.c ruby-1.6.m/marshal.c --- ruby-1.6.7/marshal.c 2002-02-28 07:52:47.000000000 +0100 +++ ruby-1.6.m/marshal.c 2002-09-08 13:50:33.000000000 +0200 @@ -755,19 +755,41 @@ return v; } +struct obj_id { + VALUE obj; + ID id; +}; + +static VALUE +r_i_pvar(ary, st) + VALUE ary; + struct obj_id *st; +{ + rb_pvar_set(st->obj, RARRAY(ary)->ptr[0], st->id, RARRAY(ary)->ptr[1]); + return Qnil; +} + static void r_ivar(obj, arg) VALUE obj; struct load_arg *arg; { long len; + struct obj_id st; len = r_long(arg); if (len > 0) { while (len--) { ID id = r_symbol(arg); VALUE val = r_object(arg); - rb_ivar_set(obj, id, val); + if (rb_is_private_id(id)) { + st.obj = obj; + st.id = id; + rb_iterate(rb_each, val, r_i_pvar, (VALUE)&st); + } + else { + rb_ivar_set(obj, id, val); + } } } } diff -u ruby-1.6.7/object.c ruby-1.6.m/object.c --- ruby-1.6.7/object.c 2002-02-04 09:09:10.000000000 +0100 +++ ruby-1.6.m/object.c 2002-09-11 12:14:15.000000000 +0200 @@ -1165,7 +1165,7 @@ rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0); rb_define_private_method(rb_mKernel, "remove_instance_variable", rb_obj_remove_instance_variable, 1); - + rb_define_method(rb_mKernel, "private_variables", rb_obj_private_variables, 1); rb_define_method(rb_mKernel, "instance_of?", rb_obj_is_instance_of, 1); rb_define_method(rb_mKernel, "kind_of?", rb_obj_is_kind_of, 1); rb_define_method(rb_mKernel, "is_a?", rb_obj_is_kind_of, 1); diff -u ruby-1.6.7/parse.y ruby-1.6.m/parse.y --- ruby-1.6.7/parse.y 2002-02-20 05:28:51.000000000 +0100 +++ ruby-1.6.m/parse.y 2002-09-08 12:25:58.000000000 +0200 @@ -22,12 +22,14 @@ #define ID_SCOPE_SHIFT 3 #define ID_SCOPE_MASK 0x07 + #define ID_LOCAL 0x01 #define ID_INSTANCE 0x02 #define ID_GLOBAL 0x03 #define ID_ATTRSET 0x04 #define ID_CONST 0x05 #define ID_CLASS 0x06 +#define ID_PRIVATE 0x07 #define is_notop_id(id) ((id)>LAST_TOKEN) #define is_local_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL) @@ -36,6 +38,7 @@ #define is_attrset_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) #define is_const_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) #define is_class_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CLASS) +#define is_private_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_PRIVATE) NODE *ruby_eval_tree_begin = 0; NODE *ruby_eval_tree = 0; @@ -673,7 +676,7 @@ if ($2 == tOROP) { $<node>3->nd_value = $4; $$ = NEW_OP_ASGN_OR(gettable($1), $<node>3); - if (is_instance_id($1)) { + if (is_instance_id($1) || is_private_id($1)) { $$->nd_aid = $1; } } @@ -4182,7 +4185,7 @@ else if (is_global_id(id)) { return NEW_GVAR(id); } - else if (is_instance_id(id)) { + else if (is_instance_id(id) || is_private_id(id)) { return NEW_IVAR(id); } else if (is_const_id(id)) { @@ -4237,7 +4240,7 @@ else if (is_global_id(id)) { return NEW_GASGN(id, val); } - else if (is_instance_id(id)) { + else if (is_instance_id(id) || is_private_id(id)) { return NEW_IASGN(id, val); } else if (is_const_id(id)) { @@ -4955,6 +4958,8 @@ case '@': if (name[1] == '@') id |= ID_CLASS; + else if (name[1] == '_') + id |= ID_PRIVATE; else id |= ID_INSTANCE; break; @@ -5065,6 +5070,14 @@ return Qfalse; } +int +rb_is_private_id(id) + ID id; +{ + if (is_private_id(id)) return Qtrue; + return Qfalse; +} + static void special_local_set(c, val) char c; diff -u ruby-1.6.7/ruby.h ruby-1.6.m/ruby.h --- ruby-1.6.7/ruby.h 2002-02-26 14:08:17.000000000 +0100 +++ ruby-1.6.m/ruby.h 2002-09-08 14:00:04.000000000 +0200 @@ -466,6 +466,8 @@ VALUE rb_gv_get _((const char*)); VALUE rb_iv_get _((VALUE, const char*)); VALUE rb_iv_set _((VALUE, const char*, VALUE)); +VALUE rb_pv_get _((VALUE, VALUE, const char*)); +VALUE rb_pv_set _((VALUE, VALUE, const char*, VALUE)); VALUE rb_equal _((VALUE,VALUE)); diff -u ruby-1.6.7/variable.c ruby-1.6.m/variable.c --- ruby-1.6.7/variable.c 2002-02-19 05:48:04.000000000 +0100 +++ ruby-1.6.m/variable.c 2002-09-11 12:12:17.000000000 +0200 @@ -885,6 +885,7 @@ VALUE clone, obj; { st_table *tbl; + VALUE val; if (!generic_iv_tbl) return; if (st_lookup(generic_iv_tbl, obj, &tbl)) { @@ -892,6 +893,295 @@ } } +static void +check_valid_class(klass) + VALUE klass; +{ + switch (TYPE(klass)) { + case T_CLASS: + case T_ICLASS: + case T_MODULE: + case T_TRUE: + case T_FALSE: + case T_NIL: + break; + default: + rb_raise(rb_eArgError, "expected a class object"); + } +} + +static VALUE +private_ivar_get(obj, klass, id) + VALUE obj, klass; + ID id; +{ + st_table *tbl; + VALUE val; + + if (!generic_iv_tbl) return Qnil; + if (!st_lookup(generic_iv_tbl, obj, &tbl)) return Qnil; + if (st_lookup(tbl, id, &val) && TYPE(val) == T_HASH && + st_lookup(RHASH(val)->tbl, klass, &val)) { + return val; + } + return Qnil; +} + +VALUE +rb_pvar_get(obj, klass, id) + VALUE klass, obj; + ID id; +{ + VALUE val; + + check_valid_class(klass); + if (!rb_is_private_id(id)) { + rb_raise(rb_eNameError, "`%s' is not a private variable", + rb_id2name(id)); + } + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + if (ROBJECT(obj)->iv_tbl && + st_lookup(ROBJECT(obj)->iv_tbl, id, &val) && + TYPE(val) == T_HASH && st_lookup(RHASH(val)->tbl, klass, &val)) { + return val; + } + break; + default: + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) { + return private_ivar_get(obj, klass, id); + } + break; + } + if (ruby_verbose) { + rb_warning("private variable %s not initialized", rb_id2name(id)); + } + return Qnil; +} + +static void +private_ivar_set(obj, klass, id, val) + VALUE obj, klass; + ID id; + VALUE val; +{ + st_table *tbl; + VALUE stbl; + + if (rb_special_const_p(obj)) { + special_generic_ivar = 1; + } + if (!generic_iv_tbl) { + generic_iv_tbl = st_init_numtable(); + } + + if (!st_lookup(generic_iv_tbl, obj, &tbl)) { + FL_SET(obj, FL_EXIVAR); + tbl = st_init_numtable(); + st_add_direct(generic_iv_tbl, obj, tbl); + } + if (!st_lookup(tbl, id, &stbl)) { + stbl = rb_hash_new(); + st_add_direct(tbl, id, stbl); + } + if (TYPE(stbl) != T_HASH) { + rb_raise(rb_eNameError, "`%s' is not a private variable", + rb_id2name(id)); + } + rb_hash_aset(stbl, klass, val); +} + +VALUE +rb_pvar_set(obj, klass, id, val) + VALUE klass, obj; + ID id; + VALUE val; +{ + VALUE stbl; + + if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) + rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); + if (OBJ_FROZEN(obj)) rb_error_frozen("object"); + + check_valid_class(klass); + if (!rb_is_private_id(id)) { + rb_raise(rb_eNameError, "`%s' is not a private variable", + rb_id2name(id)); + } + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + if (!ROBJECT(obj)->iv_tbl) ROBJECT(obj)->iv_tbl = st_init_numtable(); + if (!st_lookup(ROBJECT(obj)->iv_tbl, id, &stbl)) { + stbl = rb_hash_new(); + st_add_direct(ROBJECT(obj)->iv_tbl, id, stbl); + } + if (TYPE(stbl) != T_HASH) { + rb_raise(rb_eNameError, "`%s' is not a private variable", + rb_id2name(id)); + } + rb_hash_aset(stbl, klass, val); + break; + default: + private_ivar_set(obj, id, val); + break; + } + return val; +} + +static VALUE +private_ivar_defined(obj, klass, id) + VALUE obj, klass; + ID id; +{ + st_table *tbl; + VALUE val; + + if (!generic_iv_tbl) return Qfalse; + if (st_lookup(generic_iv_tbl, obj, &tbl) && st_lookup(tbl, id, &val) && + TYPE(val) == T_HASH && st_lookup(RHASH(val)->tbl, klass, 0)) { + return Qtrue; + } + return Qfalse; +} + +VALUE +rb_pvar_defined(obj, klass, id) + VALUE obj, klass; + ID id; +{ + VALUE stbl; + + check_valid_class(klass); + if (!rb_is_private_id(id)) { + rb_raise(rb_eNameError, "`%s' is not a private variable", + rb_id2name(id)); + } + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + if (ROBJECT(obj)->iv_tbl && + st_lookup(ROBJECT(obj)->iv_tbl, id, &stbl) && + TYPE(stbl) == T_HASH && st_lookup(RHASH(stbl)->tbl, klass, 0)) + return Qtrue; + break; + default: + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) { + return private_ivar_defined(obj, klass, id); + } + break; + } + return Qfalse; +} + +struct ary_class { + VALUE ary; + VALUE klass; +}; + +static int +pvar_i(key, val, st) + ID key; + VALUE val; + struct ary_class *st; +{ + if (rb_is_private_id(key) && TYPE(val) == T_HASH && + st_lookup(RHASH(val)->tbl, st->klass, 0)) { + rb_ary_push(st->ary, rb_str_new2(rb_id2name(key))); + } + return ST_CONTINUE; +} + +VALUE +rb_obj_private_variables(obj, klass) + VALUE obj, klass; +{ + VALUE ary; + struct ary_class st; + + check_valid_class(klass); + ary = rb_ary_new(); + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + if (ROBJECT(obj)->iv_tbl) { + st.ary = ary; + st.klass = klass; + st_foreach(ROBJECT(obj)->iv_tbl, pvar_i, &st); + } + break; + default: + if (!generic_iv_tbl) break; + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) { + st_table *tbl; + + if (st_lookup(generic_iv_tbl, obj, &tbl)) { + st.ary = ary; + st.klass = klass; + st_foreach(tbl, pvar_i, &st); + } + } + break; + } + return ary; +} + +static VALUE +generic_pvar_remove(obj, klass, id) + VALUE obj, klass; + ID id; +{ + st_table *tbl; + VALUE val, stbl; + + if (!generic_iv_tbl) return Qnil; + if (!st_lookup(generic_iv_tbl, obj, &tbl)) return Qnil; + if (!st_lookup(tbl, id, &stbl)) return Qnil; + if (TYPE(stbl) != T_HASH) return Qnil; + val = RHASH(stbl)->ifnone; + st_delete(RHASH(stbl)->tbl, &klass, &val); + return val; +} + +VALUE +rb_obj_remove_private_variable(obj, klass, name) + VALUE obj, klass, name; +{ + VALUE val = Qnil; + ID id = rb_to_id(name); + + if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) + rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); + if (OBJ_FROZEN(obj)) rb_error_frozen("object"); + if (!rb_is_private_id(id)) { + rb_raise(rb_eNameError, "`%s' is not a private variable", + rb_id2name(id)); + } + check_valid_class(klass); + + switch (TYPE(obj)) { + case T_OBJECT: + case T_CLASS: + case T_MODULE: + if (ROBJECT(obj)->iv_tbl && + st_lookup(ROBJECT(obj)->iv_tbl, id, &val) && + TYPE(val) == T_HASH) { + st_delete(RHASH(val)->tbl, &klass, &val); + } + break; + default: + if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) + return generic_pvar_remove(obj, klass, id); + break; + } + return val; +} + VALUE rb_ivar_get(obj, id) VALUE obj; @@ -899,6 +1189,9 @@ { VALUE val; + if (rb_is_private_id(id)) { + return rb_pvar_get(obj, 1, id); + } switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: @@ -926,6 +1219,9 @@ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); if (OBJ_FROZEN(obj)) rb_error_frozen("object"); + if (rb_is_private_id(id)) { + return rb_pvar_set(obj, 1, id, val); + } switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: @@ -945,6 +1241,9 @@ VALUE obj; ID id; { + if (rb_is_private_id(id)) { + return rb_pvar_defined(obj, 1, id); + } switch (TYPE(obj)) { case T_OBJECT: case T_CLASS: @@ -1549,3 +1848,24 @@ return rb_ivar_set(obj, id, val); } + +VALUE +rb_pv_get(obj, klass, name) + VALUE obj, klass; + const char *name; +{ + ID id = rb_intern(name); + + return rb_pvar_get(obj, klass, id); +} + +VALUE +rb_pv_set(obj, klass, name, val) + VALUE obj, klass; + const char *name; + VALUE val; +{ + ID id = rb_intern(name); + + return rb_pvar_set(obj, klass, id, val); +}