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.
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-04-22 11: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
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2006-04-22 13:55
(Received via mailing list)
On 4/22/06, Pat Maddox <pergesu@gmail.com> 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
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-04-22 14:20
(Received via mailing list)
On 4/22/06, Sean O'Halpin <sean.ohalpin@gmail.com> 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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-04-22 15:22
(Received via mailing list)
Hi --

On Sat, 22 Apr 2006, Pat Maddox 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 (dblack@wobblini.net)
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!
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-04-22 15:34
(Received via mailing list)
On 4/22/06, dblack@wobblini.net <dblack@wobblini.net> 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
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2006-04-22 16: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 Burt's new refactoring,
Remove Unused Scope.

James Edward Gray II
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-04-22 16:39
(Received via mailing list)
Hi --

On Sat, 22 Apr 2006, James Edward Gray II wrote:

>>
> class:
> I believe this to be an example of Dave Burt'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 (dblack@wobblini.net)
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!
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2006-04-22 19:54
(Received via mailing list)
On 4/22/06, James Edward Gray II <james@grayproductions.net> wrote:

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

Quite right! The perils of cut and paste ;)

Sean
E1d641bfe4071a5413bac781f06d3fd1?d=identicon&s=25 Sean O'halpin (sean)
on 2006-04-22 20:03
(Received via mailing list)
On 4/22/06, dblack@wobblini.net <dblack@wobblini.net> 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.