Why class_eval evaluates the string and block differently?

Viewed 94

I am new to ruby and today I found some different behaviour of class_eval for string and block. For example

class A
end

class C
  A.class_eval("print Module.nesting") # [A, C]
  A.class_eval{print Module.nesting} # [C]
end

As you can see in the case of the string Module.nesting prints [A,C], while in the case of block it prints only C.

Could you please tell me the reason for this?

1 Answers

In the first case, you stuff a string into class_eval, and this class_eval is invoked on the class A. Hence, when the expression is evaluated, Module.nesting - which needs produce its nesting levels - finds itself inside an A, which in turn is evaluated inside a C.

In the second case, you pass a block, which is similar to a proc object. The effect is comparable to have a

 class C
   p = Proc.new { print Module.nesting }
   do_something(p)
 end

The Proc represents a closure, i.e. the context is that of creating the Proc. It is clear, that the nesting here is only C, and this does not change, if you evaluate p inside do_something.

This is a good thing. Imagine the following situation:

def f(p)
  x = 'f'
  p.call
end

def g
  x = 'g'
  p = Proc.new { puts x }
  f(p)
end

Because the binding for p occurs inside method g, the x referenced in the block refers to the local value x inside g, although f has a local variable of the same name. Hence, g is printed here. In the same way, the nesting at the point of block definition is reproduced in your example.

Related