Hi~

On Aug 23, 2007, at 4:40 PM, Thomas Gantner wrote:

> Hi
>
> I stumbled upon a problem with 'instance_eval' (using ruby 1.8.5 on
> linux-x86_64). Simplified code example:
>
>   irb:01> S = Struct.new(:a)
>   => S
>   irb:02> s = S.new(1)
>   => #<struct S a=1>
>   irb:03> s.a
>   => 1
>   irb:04> s.a = 2
>   => 2
>   irb:05> s
>   => #<struct S a=2>
>   irb:06> s.instance_eval { puts a }
>   2
>   => nil
>   irb:07> s.instance_eval { a = 3 }
>   => 3
>   irb:08> s
>   => #<struct S a=2>
>   irb:09> s.instance_eval { self.a = 3 }
>   => 3
>   irb:10> s
>   => #<struct S a=3>
>
> My problem is in line 07: it seems that the 'a' in the block is  
> treated as a
> local variable, therefore all the writer-accessor methods ('a=')  
> are hidden
> within the block. I get the same result when instance_eval-ing the
> string "a = 3" instead of the block variant.
>
> Is there a way to avoid this behaviour without using 'self.a' or  
> passing the
> struct as a parameter into the block (which quite obsoletes the  
> meaning of
> instance_eval)?
>
> My real world use of this pattern is using a block with 'initialize 
> ()':
>
>   class C
>     def initialize(&blk)
>       @format = Struct.new( ... many, many elements with default  
> values ...)
>       @format.instance_eval(&blk)
>     end
>   end
>
> To explicitly override some default format-values I want to use
>
>   c = C.new { elem8 = 8; elem17 = 'test'; ... }
>
> This won't work as explained above. I know I can use
>
>   c = C.new {|format| format.elem8 = 8; format.elem17 = 'test'; ... }
>
> or
>
>   c = C.new { self.elem8 = 8; self.elem17 = 'test'; ... }
>
> but both seem somewhat redundant and need too much typing (yeah I  
> know I'm
> lazy ;-).
>
> Thanks for any suggestions.
>
> -Thomas
>
> -- 
> <sig. under construction>


	No unfortunately you are stuck with the behavior you observed.  
Whenever ruby sees 'a = b'  it assumes it is a local variable  
assignment. This happens at parse time so there is no way to affect  
it at runtime. It's a tradeoff in order to allow local variables to  
look like method calls and visca versca. So you have to prefix an  
assignment with self. or another object, otherwise it is a local  
variable assignment and you cannot work around it since it happens at  
parse time.

Cheers-
-- Ezra Zygmuntowicz-- Founder & Ruby Hacker
-- ez / engineyard.com
-- Engine Yard, Serious Rails Hosting
-- (866) 518-YARD (9273)