|
View:
New views
6 Messages
—
Rating Filter:
Alert me
|
|
|
|
|
|
[ruby-dev:39585] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detectまつもと ゆきひろです
In message "Re: [ruby-dev:39584] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detect" on Fri, 30 Oct 2009 15:12:02 +0900, Nobuyoshi Nakada <nobu@...> writes: |At Thu, 29 Oct 2009 13:55:12 +0900 (JST), |matz@... wrote in [ruby-cvs:32774]: |> * eval.c (rb_check_funcall): new function with method existence |> check. returns Qundef when the method does not exist. | |この変更で、to_aryやto_str内部でのNoMethodErrorがわからなくなっ |ています。 |ついでに、-dをつけたときの警告の山もあまり嬉しくありません。 |--- vm_eval.c (revision 25565) |+++ vm_eval.c (working copy) 気にはなっていたので、歓迎します。コミットしてください。 |
|
|
[ruby-dev:39589] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detectまつもと ゆきひろです
In message "Re: [ruby-dev:39585] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detect" on Fri, 30 Oct 2009 16:04:00 +0900, Yukihiro Matsumoto <matz@...> writes: ||この変更で、to_aryやto_str内部でのNoMethodErrorがわからなくなっ ||ています。 |気にはなっていたので、歓迎します。コミットしてください。 と思ったのですが、 test_range_numeric_string(TestRange) [/home/matz/work/ruby/test/ruby/test_range.rb:18] <["9", "10"]> expected but was <[]>. というエラーが増えていました。これはSimpleDelegatorのto_str メソッドがmethod_missingで実装されているため、このコミットに よって、method_missingが呼ばれなくなってしまった、ということ のようです。 うーむ。 * revertしてrescueの条件を厳しくする(receiverとidが一致し た場合だけキャッチする、とか) * method_missingが再定義されている時にはそれを呼ぶ。ちゃん と動作するかどうかはよくわからない いずれにせよ、現状ではまずそうです。 |
|
|
[ruby-dev:39591] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detectなかだです。
At Fri, 30 Oct 2009 18:40:53 +0900, Yukihiro Matsumoto wrote in [ruby-dev:39589]: > * method_missingが再定義されている時にはそれを呼ぶ。ちゃん > と動作するかどうかはよくわからない こっちを実装してみました。 Index: vm_eval.c =================================================================== --- vm_eval.c (revision 25576) +++ vm_eval.c (working copy) @@ -118,5 +118,5 @@ vm_call0(rb_thread_t* th, VALUE recv, VA RB_GC_GUARD(new_args); rb_ary_unshift(new_args, ID2SYM(id)); - return rb_funcall2(recv, rb_intern("method_missing"), + return rb_funcall2(recv, idMethodMissing, argc+1, RARRAY_PTR(new_args)); } @@ -235,13 +235,15 @@ rb_call0(VALUE recv, ID mid, int argc, c } -VALUE -rb_check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +static VALUE +check_funcall(rb_method_entry_t *me, VALUE recv, ID mid, int argc, VALUE *argv) { - rb_method_entry_t *me = rb_search_method_emtry(recv, mid); rb_thread_t *th = GET_THREAD(); int call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef); if (call_status != NOEX_OK) { - return Qundef; + me = rb_method_entry(CLASS_OF(recv), idMethodMissing); + if (!me || (me->flag & NOEX_BASIC) || !rb_obj_respond_to(recv, mid, TRUE)) + return Qundef; + return method_missing(recv, mid, argc, argv, call_status); } stack_check(); @@ -250,8 +252,13 @@ rb_check_funcall(VALUE recv, ID mid, int VALUE +rb_check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +{ + return check_funcall(rb_search_method_emtry(recv, mid), recv, mid, argc, argv); +} + +VALUE rb_funcall_no_recursive(VALUE recv, ID mid, int argc, VALUE *argv, VALUE (*func)()) { rb_method_entry_t *me = rb_search_method_emtry(recv, mid); - rb_thread_t *th = GET_THREAD(); int call_status; @@ -260,10 +267,5 @@ rb_funcall_no_recursive(VALUE recv, ID m me->def->body.cfunc.func == func) return Qundef; - call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef); - if (call_status != NOEX_OK) { - return Qundef; - } - stack_check(); - return vm_call0(th, recv, mid, argc, argv, me); + return check_funcall(rb_search_method_emtry(recv, mid), recv, mid, argc, argv); } -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦 |
|
|
[ruby-dev:39594] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detectまつもと ゆきひろです
In message "Re: [ruby-dev:39591] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detect" on Fri, 30 Oct 2009 20:51:46 +0900, Nobuyoshi Nakada <nobu@...> writes: |At Fri, 30 Oct 2009 18:40:53 +0900, |Yukihiro Matsumoto wrote in [ruby-dev:39589]: |> * method_missingが再定義されている時にはそれを呼ぶ。ちゃん |> と動作するかどうかはよくわからない | |こっちを実装してみました。 コードレビュー。 * emtry -> entry * check_funcallの中でrb_search_method_emtry()を呼んでも問 題なさそう * method_missingを呼ぶ条件は |+ if (!me || (me->flag & NOEX_BASIC) || !rb_obj_respond_to(recv, mid, TRUE)) になっているが、rb_method_basic_definition_p()だけでよい のではないか。 * 私の理解が正しければ、正しい(と思われる)ロジックは + meがあればそれを呼ぶ + method_missingが再定義されていなければQundef + 再定義されていれば、rescueした上でmethod_missingを呼ぶ + 例外が起きたら、以下の条件を満たすときだけ、Qundef。 満たさなければ、同じ例外をそのままあげる - レシーバが同じ - メソッド名が同じ どうでしょう? |
|
|
[ruby-dev:39595] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detectまつもと ゆきひろです
In message "Re: [ruby-dev:39594] Re: [ruby-cvs:32774] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detect" on Fri, 30 Oct 2009 23:10:15 +0900, Yukihiro Matsumoto <matz@...> writes: | * 私の理解が正しければ、正しい(と思われる)ロジックは | | + meがあればそれを呼ぶ | + method_missingが再定義されていなければQundef | + 再定義されていれば、rescueした上でmethod_missingを呼ぶ | + 例外が起きたら、以下の条件を満たすときだけ、Qundef。 | 満たさなければ、同じ例外をそのままあげる | - レシーバが同じ | - メソッド名が同じ | |どうでしょう? この方針に従い、こんなパッチを作ってみました。添付のようなプ ログラムを実行すると挙動の違いがわかるかもしれません。 diff --git a/vm_eval.c b/vm_eval.c index 86aa52e..c749d1d 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -117,7 +117,7 @@ vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv, RB_GC_GUARD(new_args); rb_ary_unshift(new_args, ID2SYM(id)); - return rb_funcall2(recv, rb_intern("method_missing"), + return rb_funcall2(recv, idMethodMissing, argc+1, RARRAY_PTR(new_args)); } case VM_METHOD_TYPE_OPTIMIZED: { @@ -201,7 +201,7 @@ stack_check(void) } } -static inline rb_method_entry_t *rb_search_method_emtry(VALUE recv, ID mid); +static inline rb_method_entry_t *rb_search_method_entry(VALUE recv, ID mid); static inline int rb_method_call_status(rb_thread_t *th, rb_method_entry_t *me, call_type scope, VALUE self); #define NOEX_OK NOEX_NOSUPER @@ -223,7 +223,7 @@ static inline VALUE rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope, VALUE self) { - rb_method_entry_t *me = rb_search_method_emtry(recv, mid); + rb_method_entry_t *me = rb_search_method_entry(recv, mid); rb_thread_t *th = GET_THREAD(); int call_status = rb_method_call_status(th, me, scope, self); @@ -234,41 +234,81 @@ rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv, return vm_call0(th, recv, mid, argc, argv, me); } -VALUE -rb_check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +struct rescue_funcall_args { + VALUE recv; + VALUE sym; + int argc; + VALUE *argv; +}; + +static VALUE +check_funcall_exec(struct rescue_funcall_args *args) +{ + VALUE new_args = rb_ary_new4(args->argc, args->argv); + + RB_GC_GUARD(new_args); + rb_ary_unshift(new_args, args->sym); + return rb_funcall2(args->recv, idMethodMissing, + args->argc+1, RARRAY_PTR(new_args)); +} + +static VALUE +check_funcall_failed(struct rescue_funcall_args *args, VALUE e) +{ + VALUE sym = rb_funcall(e, rb_intern("name"), 0, 0); + + if (args->sym != sym) + rb_exc_raise(e); + return Qundef; +} + +static VALUE +check_funcall(rb_method_entry_t *me, VALUE recv, ID mid, int argc, VALUE *argv) { - rb_method_entry_t *me = rb_search_method_emtry(recv, mid); rb_thread_t *th = GET_THREAD(); int call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef); if (call_status != NOEX_OK) { - return Qundef; + if (rb_method_basic_definition_p(CLASS_OF(recv), idMethodMissing)) { + return Qundef; + } + else { + struct rescue_funcall_args args; + + args.recv = recv; + args.sym = ID2SYM(mid); + args.argc = argc; + args.argv = argv; + return rb_rescue2(check_funcall_exec, (VALUE)&args, + check_funcall_failed, (VALUE)&args, + rb_eNoMethodError, (VALUE)0); + } } stack_check(); return vm_call0(th, recv, mid, argc, argv, me); } VALUE +rb_check_funcall(VALUE recv, ID mid, int argc, VALUE *argv) +{ + return check_funcall(rb_search_method_entry(recv, mid), recv, mid, argc, argv); +} + +VALUE rb_funcall_no_recursive(VALUE recv, ID mid, int argc, VALUE *argv, VALUE (*func)()) { - rb_method_entry_t *me = rb_search_method_emtry(recv, mid); - rb_thread_t *th = GET_THREAD(); + rb_method_entry_t *me = rb_search_method_entry(recv, mid); int call_status; if (!me) return Qundef; if (me->def && me->def->type == VM_METHOD_TYPE_CFUNC && me->def->body.cfunc.func == func) return Qundef; - call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef); - if (call_status != NOEX_OK) { - return Qundef; - } - stack_check(); - return vm_call0(th, recv, mid, argc, argv, me); + return check_funcall(me, recv, mid, argc, argv); } static inline rb_method_entry_t * -rb_search_method_emtry(VALUE recv, ID mid) +rb_search_method_entry(VALUE recv, ID mid) { VALUE klass = CLASS_OF(recv); class A include Comparable def <=>(b) self.object_id <=> b.object_id end def method_missing(s, *a) if s == :to_str foo(5) "8" else super end end end p (A.new.."9").to_a |
| Free embeddable forum powered by Nabble | Forum Help |