开发者

Ruby: how does running this block through instance_eval work?

I have recently seen some code that I do not completely understand. There is an array named foo that contains instances of Proc objects. Then, an env object is开发者_高级运维 used to setup an environment to work in:

env = Object.new
foo.each do |f|
    env.instance_eval &f # what happens here?
end

What exactly happens when you open the object with instance_eval and pass &f as an argument? What happens to env at this point and the Proc itself?


The scope is changed for the proc, which is then evaluated in that context. Internally, all procs are stored in memory as a C struct which includes the self of the proc (the scope in which the proc was made). When you call instance_eval, the self value is manually changed in memory to the object you are calling instance_eval on. If you explore the ruby source code, you will find that it boils down to this function:

static VALUE
yield_under(VALUE under, VALUE self, VALUE values)
{
    rb_thread_t *th = GET_THREAD();
    rb_block_t block, *blockptr;
    NODE *cref;

    if ((blockptr = GC_GUARDED_PTR_REF(th->cfp->lfp[0])) != 0) {
    block = *blockptr;
    block.self = self; // <- This is where the scope changes!
    th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
    }
    cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
    cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL;

    if (values == Qundef) {
    return vm_yield_with_cref(th, 1, &self, cref);
    }
    else {
    return vm_yield_with_cref(th, RARRAY_LENINT(values), RARRAY_PTR(values), cref);
    }
}

Note the line containing // <- This is where the scope changes!.


The Proc gets executed in the context of env. It is as if you are calling a method on env: the block has access to its instance variables and public and private methods.

env = Object.new

env.instance_variable_set :@test, "test"

class << env
  private
  def test
    @test
  end
end

env.instance_eval { @test } #=> "test"
env.instance_eval { test }  #=> "test"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜