Forum: Ruby class_eval used inline vs within class definition

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Pat M. (Guest)
on 2006-04-22 13:30
(Received via mailing list)
I'm reading the Ruby for Rails book, and on page 350 it has the example

irb(main):001:0> var = "initialized variable"
=> "initialized variable"
irb(main):002:0> class C; end
=> nil
irb(main):003:0> C.class_eval { define_method("talk") { puts var } }
=> #<Proc:0x00355c30@(irb):3>
irb(main):004:0> C.new.talk
initialized variable
=> nil

So I wanted to see if I could do that within the class.  I've tried
the following approach:
irb(main):005:0> class A
irb(main):006:1> class_eval { define_method("talk") { puts var } }
irb(main):007:1> end
=> #<Proc:0x0033f0ac@(irb):6>
irb(main):008:0> A.new.talk
NameError: undefined local variable or method `var' for #<A:0x337c30>
        from (irb):6:in `talk'
        from (irb):8
        from :0


I've also tried it with self.class_eval within the class definition.
Can someone explain to me what the difference is between the inline
code example, and specifying it inside the class?  Obviously they're
not equivalent, otherwise my attempt would work...I just don't
understand what the difference is.

Pat
Sean O. (Guest)
on 2006-04-22 15:55
(Received via mailing list)
On 4/22/06, Pat M. <removed_email_address@domain.invalid> wrote:

> Can someone explain to me what the difference is between the inline
> code example, and specifying it inside the class?

A class definition introduces a new scope (similar to def) so for your
example to work you need to define the local variable ~within~ the
class definition for it to be visible from the closure, e.g.

  class A
    var = "initialized variable"
    class_eval { define_method(:talk) { puts var } }
  end

  A.new.talk

  #=> initialized variable

Regards,

Sean
Pat M. (Guest)
on 2006-04-22 16:20
(Received via mailing list)
On 4/22/06, Sean O'Halpin <removed_email_address@domain.invalid> wrote:
>     var = "initialized variable"
>
>

The point of this is to be able to access 'var' even though it's
normally outside of the class's scope.  See the very first example,
which does this.

Pat
unknown (Guest)
on 2006-04-22 17:22
(Received via mailing list)
Hi --

On Sat, 22 Apr 2006, Pat M. wrote:

>>   class A
>> Sean
>>
>>
>
> The point of this is to be able to access 'var' even though it's
> normally outside of the class's scope.  See the very first example,
> which does this.

But look closely at it:

irb(main):001:0> var = "initialized variable"
=> "initialized variable"
irb(main):002:0> class C; end
=> nil
irb(main):003:0> C.class_eval { define_method("talk") { puts var } }
=> #<Proc:0x00355c30@(irb):3>
irb(main):004:0> C.new.talk
initialized variable

The variable var is defined at the top level, and the call to
class_eval takes place at the top level.  So var is in scope, and can
be used inside the class_eval block.

In your example, var is on one side of a class keyword, and the use of
var is on the other.  What you've done is like:

   var = 1
   class C
     puts var
   end

which will give you the same error.


David

--
David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" PDF now on sale!  http://www.manning.com/black
Paper version coming in early May!
Pat M. (Guest)
on 2006-04-22 17:34
(Received via mailing list)
On 4/22/06, removed_email_address@domain.invalid 
<removed_email_address@domain.invalid> wrote:
> >> A class definition introduces a new scope (similar to def) so for your
> >>   #=> initialized variable
>
>
>    end
> "Ruby for Rails" PDF now on sale!  http://www.manning.com/black
> Paper version coming in early May!
>
>

Okay, that makes sense now.  I think that's what Sean was telling me
as well...I just didn't get it as quickly.  Thanks for the
explanation.

Pat
James G. (Guest)
on 2006-04-22 18:33
(Received via mailing list)
On Apr 22, 2006, at 6:52 AM, Sean O'Halpin wrote:

>     var = "initialized variable"
>     class_eval { define_method(:talk) { puts var } }
>   end
>
>   A.new.talk
>
>   #=> initialized variable

We might as well drop the class_eval { ... }, since we are already in
the class:

 >> class A
 >>   var = "initialized variable"
 >>   define_method(:talk) { puts var }
 >> end
=> #<Proc:0x0033307c@(irb):3>
 >> A.new.talk
initialized variable
=> nil

I believe this to be an example of Dave B.'s new refactoring,
Remove Unused Scope.

James Edward G. II
unknown (Guest)
on 2006-04-22 18:39
(Received via mailing list)
Hi --

On Sat, 22 Apr 2006, James Edward G. II wrote:

>>
> class:
> I believe this to be an example of Dave B.'s new refactoring, Remove Unused
> Scope.

To be fair to Sean, though, the question really had to do with
clarifying how the scope of class_eval worked -- so removing it kind
of defeats that particular purpose :-)


David

--
David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" PDF now on sale!  http://www.manning.com/black
Paper version coming in early May!
Sean O. (Guest)
on 2006-04-22 21:54
(Received via mailing list)
On 4/22/06, James Edward G. II <removed_email_address@domain.invalid> wrote:

> We might as well drop the class_eval { ... }, since we are already in
> the class:
>
> James Edward G. II

Quite right! The perils of cut and paste ;)

Sean
Sean O. (Guest)
on 2006-04-22 22:03
(Received via mailing list)
On 4/22/06, removed_email_address@domain.invalid 
<removed_email_address@domain.invalid> wrote:
>
> To be fair to Sean, though, the question really had to do with
> clarifying how the scope of class_eval worked -- so removing it kind
> of defeats that particular purpose :-)
>
>
> David
>
Thanks for leaping to my defence David but I think James is right.

Anyway, back to Pat's question. I'll try to be more explicit in future.

The main difference between

  var = "initialized variable"
  class C;end
  C.class_eval { define_method(:test) { puts var} }

and

  var = "initialized variable"
  class D
    define_method(:test) { puts var } # will fail
  end

is that the closure passed to define_method in D is
within a new scope, i.e. the class definition, which means
it does not have access to the local variables in the outer scope, i.e.
var.

You can access variables local to the class definition like this:

  class D
    var = "initialized variable"
    define_method(:test) { puts var } # will work
  end

which is quite interesting in its own right.

But if you want access to the outer scope, then use the first method.
Now you know why the code on page 350 of the RoR book was written that
way!

Regards,

Sean
This topic is locked and can not be replied to.