前田です。

At Fri, 29 Jun 2001 23:42:41 +0900,
matz / ruby-lang.org (Yukihiro Matsumoto) wrote:
> |eval(code, true, filename)
> |
> |で、ruby_wrapperを設定した状態でRubyスクリプトを評価できるように
> |してはどうでしょう。
> |# trueは:wrapなどのシンボルの方がよいかもしれません。
> 
> APIは考えた方が良いでしょうね。
> 
>   eval(aString[,aBinding[,file[,line]]])
> 
> なんで第2引数のtrueは適切ではないかも。

bindingとwrapの指定は排他的でいいかなと思ったのですが、いっそのこと
bindingにwrapperの情報を持たせる(本来そうであるべきかも)ようにして、
wrapper_binding(名前はもっといいのがあるかもしれませんが)でwrapper用
のbindingを返すようにするというのはどうでしょうか。

b = wrapper_binding
eval(str, b)

試しに実装してみたのでパッチを付けます。

前に石塚さんが空のbinding(?)がほしいといったことをおっしゃってた
ような気がしますが、wrapper_bindingが使えるかも。

-- 
前田 修吾

--- eval.c.orig Sat Jun 30 22:23:37 2001 +++ eval.c Sun Jul 1 10:51:15 2001 @@ -546,6 +546,7 @@ int flags; struct RVarmap *dyna_vars; VALUE orig_thread; + VALUE wrapper; struct BLOCK *prev; }; @@ -4843,6 +4844,7 @@ struct RVarmap * volatile old_dyna_vars; VALUE volatile old_cref; int volatile old_vmode; + volatile VALUE old_wrapper; struct FRAME frame; char *filesave = ruby_sourcefile; int linesave = ruby_sourceline; @@ -4874,6 +4876,8 @@ scope_vmode = data->vmode; old_cref = (VALUE)ruby_cref; ruby_cref = (NODE*)ruby_frame->cbase; + old_wrapper = ruby_wrapper; + ruby_wrapper = data->wrapper; self = data->self; ruby_frame->iter = data->iter; @@ -4909,6 +4913,7 @@ if (!NIL_P(scope)) { int dont_recycle = ruby_scope->flags & SCOPE_DONT_RECYCLE; + ruby_wrapper = old_wrapper; ruby_cref = (NODE*)old_cref; ruby_frame = frame.tmp; ruby_scope = old_scope; @@ -6079,6 +6084,7 @@ rb_gc_mark((VALUE)data->dyna_vars); rb_gc_mark((VALUE)data->klass); rb_gc_mark((VALUE)data->tag); + rb_gc_mark(data->wrapper); data = data->prev; } } @@ -6194,6 +6200,7 @@ *data = *ruby_block; data->orig_thread = rb_thread_current(); + data->wrapper = ruby_wrapper; data->iter = rb_f_block_given_p(); frame_dup(&data->frame); if (ruby_frame->prev) { @@ -6222,6 +6229,39 @@ return bind; } +static VALUE +rb_f_wrapper_binding(recv) + VALUE recv; +{ + VALUE bind, self; + VALUE wrapper = ruby_wrapper; + + PUSH_VARS(); + PUSH_CLASS(); + ruby_class = ruby_wrapper = rb_module_new(); + self = rb_obj_clone(ruby_top_self); + rb_extend_object(self, ruby_class); + + PUSH_FRAME(); + ruby_frame->last_func = 0; + ruby_frame->last_class = 0; + ruby_frame->self = self; + ruby_frame->cbase = (VALUE)rb_node_newnode(NODE_CREF,ruby_class,0,0); + PUSH_SCOPE(); + /* default visibility is private at loading toplevel */ + SCOPE_SET(SCOPE_PRIVATE); + + bind = rb_f_binding(self); + + POP_SCOPE(); + POP_FRAME(); + POP_CLASS(); + POP_VARS(); + ruby_wrapper = wrapper; + + return bind; +} + #define PROC_T3 FL_USER1 #define PROC_T4 FL_USER2 #define PROC_TMAX (FL_USER1|FL_USER2) @@ -6283,6 +6323,7 @@ *data = *ruby_block; data->orig_thread = rb_thread_current(); + data->wrapper = ruby_wrapper; data->iter = data->prev?Qtrue:Qfalse; frame_dup(&data->frame); if (data->iter) { @@ -6352,6 +6393,7 @@ int state; volatile int orphan; volatile int safe = ruby_safe_level; + volatile VALUE old_wrapper = ruby_wrapper; if (rb_block_given_p() && ruby_frame->last_func) { rb_warning("block for %s#%s is useless", @@ -6362,6 +6404,8 @@ Data_Get_Struct(proc, struct BLOCK, data); orphan = blk_orphan(data); + ruby_wrapper = data->wrapper; + /* PUSH BLOCK from data */ old_block = ruby_block; _block = *data; @@ -6387,6 +6431,7 @@ state &= TAG_MASK; } ruby_block = old_block; + ruby_wrapper = old_wrapper; ruby_safe_level = safe; switch (state) { @@ -6496,6 +6541,7 @@ int state; volatile int orphan; volatile int safe = ruby_safe_level; + volatile VALUE old_wrapper = ruby_wrapper; if (NIL_P(block)) { return rb_eval(self, node->nd_iter); @@ -6511,6 +6557,8 @@ Data_Get_Struct(block, struct BLOCK, data); orphan = blk_orphan(data); + ruby_wrapper = data->wrapper; + /* PUSH BLOCK from data */ old_block = ruby_block; _block = *data; @@ -6548,6 +6596,7 @@ } } ruby_block = old_block; + ruby_wrapper = old_wrapper; ruby_safe_level = safe; switch (state) {/* escape from orphan procedure */ @@ -6927,6 +6976,7 @@ rb_define_global_function("proc", rb_f_lambda, 0); rb_define_global_function("lambda", rb_f_lambda, 0); rb_define_global_function("binding", rb_f_binding, 0); + rb_define_global_function("wrapper_binding", rb_f_wrapper_binding, 0); rb_cBinding = rb_define_class("Binding", rb_cObject); rb_undef_method(CLASS_OF(rb_cBinding), "new"); rb_define_method(rb_cBinding, "clone", bind_clone, 0);