diff --git a/ChangeLog b/ChangeLog index 87cad170aa..b7ca593680 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Sun Nov 16 19:38:10 2014 Nobuyoshi Nakada + + * vm_eval.c (rb_current_receiver): new function to return the + receiver in the current control frame. [Feature #10195] + Sun Nov 16 19:11:04 2014 Nobuyoshi Nakada * lib/timeout.rb (Timeout::ExitException#exception): rescue diff --git a/README.EXT b/README.EXT index c8aafc4d55..145d922b10 100644 --- a/README.EXT +++ b/README.EXT @@ -442,6 +442,11 @@ you may rely on: VALUE rb_call_super(int argc, const VALUE *argv) +To achieve the receiver of the current scope (if no other way is +available), you can use: + + VALUE rb_current_receiver(void) + === Constant Definition We have 2 functions to define constants: diff --git a/README.EXT.ja b/README.EXT.ja index be76515cdc..e598c61979 100644 --- a/README.EXT.ja +++ b/README.EXT.ja @@ -473,6 +473,17 @@ funcはクラスを引数として受け取って,新しく割り当てられ ソースなどを含まない,できるだけ「空」のままにしておいたほう がよいでしょう. +継承したクラスにある既存のメソッドをオーバーライドしているな +ら,オーバーライドされたメソッドを呼び出すには以下の関数を使 +います. + + VALUE rb_call_super(int argc, const VALUE *argv) + +現在のスコープのレシーバは(他に方法がなければ),以下の関数で +得ることができます. + + VALUE rb_current_receiver(void) + === 定数定義 拡張ライブラリが必要な定数はあらかじめ定義しておいた方が良い diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 18183f787c..5b3ca8c0a8 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -1474,6 +1474,7 @@ VALUE rb_funcall_passing_block(VALUE, ID, int, const VALUE*); VALUE rb_funcall_with_block(VALUE, ID, int, const VALUE*, VALUE); int rb_scan_args(int, const VALUE*, const char*, ...); VALUE rb_call_super(int, const VALUE*); +VALUE rb_current_receiver(void); /* rb_scan_args() format allows ':' for optional hash */ #define HAVE_RB_SCAN_ARGS_OPTIONAL_HASH 1 diff --git a/test/-ext-/proc/test_bmethod.rb b/test/-ext-/proc/test_bmethod.rb index 32b31580d6..16927dcf7d 100644 --- a/test/-ext-/proc/test_bmethod.rb +++ b/test/-ext-/proc/test_bmethod.rb @@ -15,6 +15,7 @@ class TestProc::TestBMethod class Bound < Base define_method(:foo, Bug::Proc.make_call_super(42)) + define_method(:receiver, Bug::Proc.make_call_receiver(nil)) end def test_super_in_bmethod @@ -28,4 +29,9 @@ class TestProc::TestBMethod obj.foo(2) {|*a| result = a} assert_equal([2, 42], result) end + + def test_receiver_in_bmethod + obj = Bound.new + assert_same(obj, obj.receiver) + end end diff --git a/vm_eval.c b/vm_eval.c index 0d47aacf30..0f2b19053d 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -290,6 +290,16 @@ rb_call_super(int argc, const VALUE *argv) return vm_call_super(GET_THREAD(), argc, argv); } +VALUE +rb_current_receiver(void) +{ + rb_thread_t *th = GET_THREAD(); + rb_control_frame_t *cfp; + if (!th || !(cfp = th->cfp)) + rb_raise(rb_eRuntimeError, "no self, no life"); + return cfp->self; +} + static inline void stack_check(void) {