Backport #5731
closedenum_for を使うと method_missing にブロックが渡されない
Description
次のスクリプトを 1.9.3 で実行すると enum_for の方は block が nil になります。
1.8.7 では両方とも block が渡されました。
class A
def method_missing(name, *args, &block)
p block
end
end
a = A.new
a.hoge{|l| p l} # ブロックが渡される
a.enum_for(:hoge).each{|l| p l} # ブロックが渡されない
% /usr/local/ruby187/bin/ruby -v a.rb
ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-linux]
#Proc:0xb76dbb60@a.rb:9
#Proc:0xb76db8e0@a.rb:10
% ruby -v a.rb
ruby 1.9.3p0 (2011-10-30) [i686-linux]
#Proc:0x8829080@a.rb:9
nil
使い方が間違ってるだけだったらすいません¶
Updated by ktsj (Kazuki Tsujimoto) over 12 years ago
=begin
今のmethod_missing関数の実装はpassed_blockを無条件に0クリアするようになっています。
同関数ではmethod_missingメソッドを呼び出す前に色々と処理を行っており
その際にraiseされる可能性があるので0クリアしておくことは必要ですが、
前処理が終わった時点でpassed_blockを再設定しておかないといけないという話ではないかと思います。
以下のパッチでどうでしょうか。
diff --git a/vm_eval.c b/vm_eval.c
index 44edf6f..d653e4e 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -563,6 +563,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status)
{
VALUE *nargv, result, argv_ary = 0;
rb_thread_t *th = GET_THREAD();
-
const rb_block_t *blockptr = th->passed_block;
th->method_missing_reason = call_status;
th->passed_block = 0;
@@ -589,6 +590,7 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status)
if (rb_method_basic_definition_p(CLASS_OF(obj) , idMethodMissing)) {
raise_method_missing(th, argc+1, nargv, obj, call_status | NOEX_MISSING);
} -
th->passed_block = blockptr;
result = rb_funcall2(obj, idMethodMissing, argc + 1, nargv);
if (argv_ary) rb_ary_clear(argv_ary);
return result;
=end
Updated by matz (Yukihiro Matsumoto) over 12 years ago
- ruby -v changed from ruby 1.9.3p0 (2011-10-30) [i686-linux] to -
まつもと ゆきひろです
In message "Re: [ruby-dev:45003] [ruby-trunk - Bug #5731] enum_for を使うと method_missing にブロックが渡されない"
on Sun, 18 Dec 2011 00:33:10 +0900, Kazuki Tsujimoto kazuki@callcc.net writes:
|=begin
|今のmethod_missing関数の実装はpassed_blockを無条件に0クリアするようになっています。
|
|同関数ではmethod_missingメソッドを呼び出す前に色々と処理を行っており
|その際にraiseされる可能性があるので0クリアしておくことは必要ですが、
|前処理が終わった時点でpassed_blockを再設定しておかないといけないという話ではないかと思います。
|
|以下のパッチでどうでしょうか。
このパッチを確認してくださる方はいらっしゃいませんか?
問題が内容なら積極的に取り込みたいのですが。
Updated by shiba (satoshi shiba) over 12 years ago
芝と申します。
パッチが正しいかどうかは分かりませんが、passing_block の設定が抜けてる関数は method_missing 以外にもあるので、一緒に対処してはどうでしょうか。
例えば、vm_call0 での passing_block の設定忘れは次のコードで確認できます。
問題となるコード(vm_call0 のほう)¶
missing.rb¶
def respond_to_missing?(*args)
true
end
def method_missing(mid, *args)
yield
end
m = method(:call_missing)
m.call(){ puts "passing block ok" }
追加パッチ¶
Index: vm_eval.c¶
--- vm_eval.c (revision 34071)
+++ vm_eval.c (working copy)
@@ -118,6 +118,7 @@
RB_GC_GUARD(new_args);
rb_ary_unshift(new_args, ID2SYM(id));
-
th->passed_block = blockptr; return rb_funcall2(recv, idMethodMissing, argc+1, RARRAY_PTR(new_args)); }
Index: vm_insnhelper.c¶
--- vm_insnhelper.c (revision 34071)
+++ vm_insnhelper.c (working copy)
@@ -555,6 +555,7 @@
argv[0] = ID2SYM(me->def->original_id);
MEMCPY(argv+1, cfp->sp - num, VALUE, num);
cfp->sp += - num - 1;
-
th->passed_block = blockptr; val = rb_funcall2(recv, rb_intern("method_missing"), num+1, argv); break; }
Updated by nobu (Nobuyoshi Nakada) over 12 years ago
- Status changed from Open to Closed
- % Done changed from 0 to 100
This issue was solved with changeset r34399.
Masahiro, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
- vm_eval.c (vm_call0): should pass block to enumerators. patched
by Kazuki Tsujimoto. [ruby-dev:44961][Bug #5731] - vm_eval.c (method_missing), vm_insnhelper.c (vm_call_method):
ditto. patched by satoshi shiba.
Updated by nobu (Nobuyoshi Nakada) over 12 years ago
- Tracker changed from Bug to Backport
- Project changed from Ruby master to Backport193
- Status changed from Closed to Open
Updated by kosaki (Motohiro KOSAKI) over 12 years ago
- Status changed from Open to Closed
This issue was solved with changeset r34450.
Masahiro, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
merge revision(s) r34399:
* vm_eval.c (vm_call0): should pass block to enumerators. patched
by Kazuki Tsujimoto. [ruby-dev:44961][Bug #5731]
* vm_eval.c (method_missing), vm_insnhelper.c (vm_call_method):
ditto. patched by satoshi shiba.
Updated by kosaki (Motohiro KOSAKI) over 12 years ago
- Project changed from Backport193 to Backport192
- Status changed from Closed to Open
たぶん 1.9.2 にもいるんじゃないかと推測
Updated by naruse (Yui NARUSE) over 8 years ago
- Status changed from Open to Rejected