From: Nobuyoshi Nakada Date: 2008-05-13T14:07:06+09:00 Subject: [ruby-dev:34671] [ruby-Bugs:19377] Marshall.load of serialized instance of singleton class returns new instance なかだです。 # 出したつもりで忘れてたようです。 [ruby-Bugs:19377]の問題は、SingletonClassMethods#_loadがprivate になっているのでrb_respond_toがfalseを返すということが原因です。 singleton.rbからprivateを取り除くのでもいいのですが、実際に呼び 出すrb_funcallはprivateでも無関係に呼び出してしまうわけなので、 privateメソッドも探すべきなんではないでしょうか。 そもそも、こういった内部的に呼ばれるメソッドの可視性は、どうすべ きなのでしょうか。 Index: marshal.c =================================================================== --- marshal.c (revision 15931) +++ marshal.c (working copy) @@ -590,5 +590,5 @@ w_object(VALUE obj, struct dump_arg *arg } - if (rb_respond_to(obj, s_mdump)) { + if (rb_obj_respond_to(obj, s_mdump, Qtrue)) { VALUE v; @@ -599,5 +599,5 @@ w_object(VALUE obj, struct dump_arg *arg return; } - if (rb_respond_to(obj, s_dump)) { + if (rb_obj_respond_to(obj, s_dump, Qtrue)) { VALUE v; st_table *ivtbl2 = 0; @@ -746,5 +746,5 @@ w_object(VALUE obj, struct dump_arg *arg VALUE v; - if (!rb_respond_to(obj, s_dump_data)) { + if (!rb_obj_respond_to(obj, s_dump_data, Qtrue)) { rb_raise(rb_eTypeError, "no marshal_dump is defined for class %s", @@ -841,5 +841,5 @@ marshal_dump(int argc, VALUE *argv) arg.dest = 0; if (!NIL_P(port)) { - if (!rb_respond_to(port, s_write)) { + if (!rb_obj_respond_to(port, s_write, Qtrue)) { type_error: rb_raise(rb_eTypeError, "instance of IO needed"); @@ -847,5 +847,5 @@ marshal_dump(int argc, VALUE *argv) arg.str = rb_str_buf_new(0); arg.dest = port; - if (rb_respond_to(port, s_binmode)) { + if (rb_obj_respond_to(port, s_binmode, Qtrue)) { rb_funcall2(port, s_binmode, 0, 0); } @@ -1392,5 +1392,5 @@ r_object0(struct load_arg *arg, int *ivp VALUE data; - if (!rb_respond_to(klass, s_load)) { + if (!rb_obj_respond_to(klass, s_load, Qtrue)) { rb_raise(rb_eTypeError, "class %s needs to have method `_load'", rb_class2name(klass)); @@ -1419,5 +1419,5 @@ r_object0(struct load_arg *arg, int *ivp } } - if (!rb_respond_to(v, s_mload)) { + if (!rb_obj_respond_to(v, s_mload, Qtrue)) { rb_raise(rb_eTypeError, "instance of %s needs to have method `marshal_load'", rb_class2name(klass)); @@ -1445,5 +1445,5 @@ r_object0(struct load_arg *arg, int *ivp { VALUE klass = path2class(r_unique(arg)); - if (rb_respond_to(klass, s_alloc)) { + if (rb_obj_respond_to(klass, s_alloc, Qtrue)) { static int warn = Qtrue; if (warn) { @@ -1460,5 +1460,5 @@ r_object0(struct load_arg *arg, int *ivp } v = r_entry(v, arg); - if (!rb_respond_to(v, s_load_data)) { + if (!rb_obj_respond_to(v, s_load_data, Qtrue)) { rb_raise(rb_eTypeError, "class %s needs to have instance method `_load_data'", @@ -1558,10 +1558,11 @@ marshal_load(int argc, VALUE *argv) rb_scan_args(argc, argv, "11", &port, &proc); - if (rb_respond_to(port, rb_intern("to_str"))) { + v = rb_check_string_type(port); + if (!NIL_P(v)) { arg.taint = OBJ_TAINTED(port); /* original taintedness */ - StringValue(port); /* possible conversion */ + port = v; } - else if (rb_respond_to(port, s_getbyte) && rb_respond_to(port, s_read)) { - if (rb_respond_to(port, s_binmode)) { + else if (rb_obj_respond_to(port, s_getbyte, Qtrue) && rb_obj_respond_to(port, s_read, Qtrue)) { + if (rb_obj_respond_to(port, s_binmode, Qtrue)) { rb_funcall2(port, s_binmode, 0, 0); } Index: object.c =================================================================== --- object.c (revision 15931) +++ object.c (working copy) @@ -1893,5 +1893,5 @@ convert_type(VALUE val, const char *tnam m = rb_intern(method); - if (!rb_respond_to(val, m)) { + if (!rb_obj_respond_to(val, m, Qtrue)) { if (raise) { rb_raise(rb_eTypeError, "can't convert %s into %s", -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦