なかだです。

Binding.of_callerとかBinding#callerとかbindingのオプショナル引数
とかを実装してみました。


Index: proc.c =================================================================== --- proc.c (revision 14286) +++ proc.c (working copy) @@ -174,18 +174,93 @@ binding_clone(VALUE self) } +static int +caller_level(int argc, VALUE *argv, int minimum) +{ + VALUE v; + int level; + + if (!argc) return minimum; + rb_scan_args(argc, argv, "1", &v); + level = NUM2INT(v); + if (level < 0) { + rb_raise(rb_eArgError, "negative caller level: %d", level); + } + if (level < minimum) { + rb_raise(rb_eArgError, "caller level out of range: %d", level); + } + return level; +} + +VALUE +rb_binding_caller(VALUE self, int level) +{ + rb_thread_t *th = GET_THREAD(); + rb_control_frame_t *cfp; + rb_binding_t *bind; + VALUE envval, bindval; + + GetBindingPtr(self, bind); + envval = bind->env; + cfp = bind->cfp; + do { + cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); + cfp = vm_get_ruby_level_cfp(th, cfp); + if (!cfp) return Qnil; + } while (level-- > 0); + + bindval = binding_alloc(rb_obj_class(self)); + GetBindingPtr(bindval, bind); + bind->env = vm_make_env_object(th, cfp); + bind->cref_stack = vm_get_cref(th, cfp->iseq, cfp); + bind->cfp = cfp; + return bindval; +} + +static VALUE +binding_caller(int argc, VALUE *argv, VALUE self) +{ + return rb_binding_caller(self, caller_level(argc, argv, 1)); +} + VALUE rb_binding_new(void) { + return rb_binding_at(0); +} + +static VALUE +binding_at(VALUE klass, int level) +{ rb_thread_t *th = GET_THREAD(); - rb_control_frame_t *cfp = vm_get_ruby_level_cfp(th, th->cfp); - VALUE bindval = binding_alloc(rb_cBinding); + rb_control_frame_t *cfp = th->cfp; + VALUE bindval; rb_binding_t *bind; + for (;;) { + cfp = vm_get_ruby_level_cfp(th, cfp); + if (!cfp) return Qnil; + if (level-- <= 0) break; + cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); + } + bindval = binding_alloc(klass); GetBindingPtr(bindval, bind); bind->env = vm_make_env_object(th, cfp); - bind->cref_stack = ruby_cref(); + bind->cref_stack = vm_get_cref(th, cfp->iseq, cfp); + bind->cfp = cfp; return bindval; } +VALUE +rb_binding_at(int level) +{ + return binding_at(rb_cBinding, level); +} + +static VALUE +rb_binding_of_caller(int argc, VALUE *argv, VALUE klass) +{ + return binding_at(klass, caller_level(argc, argv, 1)); +} + /* * call-seq: @@ -205,7 +280,7 @@ rb_binding_new(void) static VALUE -rb_f_binding(VALUE self) +rb_f_binding(int argc, VALUE *argv, VALUE self) { - return rb_binding_new(); + return rb_binding_at(caller_level(argc, argv, 0)); } @@ -1604,5 +1679,7 @@ Init_Binding(void) rb_define_method(rb_cBinding, "dup", binding_dup, 0); rb_define_method(rb_cBinding, "eval", bind_eval, -1); - rb_define_global_function("binding", rb_f_binding, 0); + rb_define_method(rb_cBinding, "caller", binding_caller, -1); + rb_define_singleton_method(rb_cBinding, "of_caller", rb_binding_of_caller, -1); + rb_define_global_function("binding", rb_f_binding, -1); } Index: vm_core.h =================================================================== --- vm_core.h (revision 14286) +++ vm_core.h (working copy) @@ -509,4 +509,5 @@ typedef struct { VALUE env; NODE *cref_stack; + rb_control_frame_t *cfp; } rb_binding_t; Index: include/ruby/intern.h =================================================================== --- include/ruby/intern.h (revision 14286) +++ include/ruby/intern.h (working copy) @@ -254,4 +254,6 @@ VALUE rb_proc_call(VALUE, VALUE); int rb_proc_arity(VALUE); VALUE rb_binding_new(void); +VALUE rb_binding_at(int); +VALUE rb_binding_caller(VALUE, int); VALUE rb_obj_method(VALUE, VALUE); VALUE rb_method_call(int, VALUE*, VALUE);
-- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦