Forum: Ruby adding local variables via block

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.
B8e48899be4fbcc29b4b9bbae87a965a?d=identicon&s=25 Paul Danese (Guest)
on 2007-02-20 19:33
(Received via mailing list)
Hi,



i'm a roob noob and I'm trying to grasp procs/blocks/etc.



specifically, I'd like to pass a piece of code into a method.

the piece of code will contain a variable name and an assignment



e.g.



####################

def lamb_test

    cond = 'hello'

    yield

    puts cond + ' ' + name

  end

lamb_test {name = 'bob'}

###################



When I do this, I get the following error:

"undefined local variable or method `name' for main:Object...



is it possible to define a local variable like this on the fly with
blocks?

obviously, this is an oversimplified case but I want to be able to
dynamically insert a local variable and an assignment to that variable
into the "generic" function lamb_test

Is there a better way?



TIA!
4d5b5dd4e263d780a5dfe7ac8b8ac98c?d=identicon&s=25 Tim Pease (Guest)
on 2007-02-20 19:52
(Received via mailing list)
On 2/20/07, Paul Danese <pdanese@rib-x.com> wrote:
> the piece of code will contain a variable name and an assignment
>
> ###################
> blocks?
>
> obviously, this is an oversimplified case but I want to be able to
> dynamically insert a local variable and an assignment to that variable
> into the "generic" function lamb_test
>
> Is there a better way?
>
>

yield will return the value from the block it executes. Just have your
block return the name 'bob' ...

def lamb_test
  cond = 'hello'
  name = yield
  puts cond + ' ' + name
end

lamb_test { 'bob' }    #=> 'hello bob'

In the more general case, you would need to use one of the 'eval'
methods in order to create a new local variable in a local namespace.
However, (1) the 'eval' methods work only on strings and not blocks,
and (2) they are mostly evil and should be handled with great care.

Blessings,
TwP
617b624fa01db9f6440439f3740b35e9?d=identicon&s=25 Marcello Barnaba (Guest)
on 2007-02-20 19:54
(Received via mailing list)
Hi,

On Tuesday 20 February 2007 19:33, Paul Danese wrote:
> ####################
> def lamb_test  
>     cond = 'hello'
>     yield
>     puts cond + ' ' + name
>   end
>
> lamb_test {name = 'bob'}
>
> ###################

the local variables defined in the block live only in the block's scope.
if a
local variable is defined out of the block, a closure is made and you
can
access (and redefine) that variable in the block:

>> a = 1
=> 1
>> p = proc { a = 2; b = 3 }
=> #<Proc:0xb7ae7150@(irb):8>
>> p.call
=> 2
>> a
=> 2
>> b
=> NameError: ...

> Is there a better way?

well

def lamb_test
  cond = 'hello'
  name = yield
  puts cond + ' ' + name
end

better:

def lamb_test
  cond = hello
  puts cond + ' ' + yield
end

better:

def lamb_test
  puts ['hello', yield].join(' ')
end

even better:

def lamb_test
  ['hello', yield].join(' ')
end

puts lamb_test { 'world' }

if "puts" is not strictly necessary in your method, take it out, and
just
return a string. this way, when you need to print that string on
something
different than a text terminal, you don't need to mess with the class
you've
written earlier.

HTH! :)
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-02-20 20:13
(Received via mailing list)
On Feb 20, 2007, at 12:52 PM, Tim Pease wrote:

> In the more general case, you would need to use one of the 'eval'
> methods in order to create a new local variable in a local namespace.
> However, (1) the 'eval' methods work only on strings and not blocks,
> and (2) they are mostly evil and should be handled with great care.

eval() introduces a new scope, so local variables created in that
context do not leak into the calling scope:

 >> def test_eval
 >>   eval("name = 'James'", binding)
 >>   name
 >> end
=> nil
 >> tes
test       test_eval
 >> test_eval
NameError: undefined local variable or method `name' for main:Object
         from (irb):3:in `test_eval'
         from (irb):5
         from :0

James Edward Gray II
2c51fec8183a5d21c4e11b430beabb47?d=identicon&s=25 Patrick Hurley (Guest)
on 2007-02-20 21:03
(Received via mailing list)
On 2/20/07, James Edward Gray II <james@grayproductions.net> wrote:
> eval() introduces a new scope, so local variables created in that
> context do not leak into the calling scope:

I am not recommending this, but you can force a binding into an eval.
However, due to how the Ruby parser identifies local variables, they
need to be referenced in "code" before you can use them normally.

def foo(binding)
  eval("x = 42", binding)
end

foo(binding)
x = x
puts "x = #{x}"

Good luck
pth
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-02-20 21:11
(Received via mailing list)
Hi --

On Wed, 21 Feb 2007, Tim Pease wrote:

> In the more general case, you would need to use one of the 'eval'
> methods in order to create a new local variable in a local namespace.
> However, (1) the 'eval' methods work only on strings and not blocks,
> and (2) they are mostly evil and should be handled with great care.

Actually the only one that works only on strings is eval.
instance_eval and class_eval work on blocks too.


David
617b624fa01db9f6440439f3740b35e9?d=identicon&s=25 Marcello Barnaba (Guest)
on 2007-02-20 21:12
(Received via mailing list)
Hi,

On Tuesday 20 February 2007 21:02, Patrick Hurley wrote:
> I am not recommending this, but you can force a binding into an eval.
> However, due to how the Ruby parser identifies local variables, they
> need to be referenced in "code" before you can use them normally.

my irb disagrees:

 vjt@neutrino:~$ irb
/home/vjt| irb(main):001:0> eval 'x = 42', binding
42
/home/vjt| irb(main):002:0> x
42
/home/vjt| irb(main):003:0> RUBY_VERSION
"1.8.5"
/home/vjt| irb(main):004:0>
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2007-02-20 21:14
(Received via mailing list)
On Wed, 21 Feb 2007, Marcello Barnaba wrote:

> /home/vjt| irb(main):001:0> eval 'x = 42', binding
> 42
> /home/vjt| irb(main):002:0> x
> 42
> /home/vjt| irb(main):003:0> RUBY_VERSION
> "1.8.5"
> /home/vjt| irb(main):004:0>

try writing that in a script.  in irb you are __already__ in eval.
google the
archives for more info.

cheers.

-a
617b624fa01db9f6440439f3740b35e9?d=identicon&s=25 Marcello Barnaba (Guest)
on 2007-02-20 21:28
(Received via mailing list)
Hi,

On Tuesday 20 February 2007 21:14, ara.t.howard@noaa.gov wrote:
> > vjt@neutrino:~$ irb
> > /home/vjt| irb(main):001:0> eval 'x = 42', binding
> > 42
> > /home/vjt| irb(main):002:0> x
> > 42
> > /home/vjt| irb(main):003:0> RUBY_VERSION
> > "1.8.5"
> > /home/vjt| irb(main):004:0>
>
> try writing that in a script.

vjt@neutrino:~$ ruby -e "eval('x=42',binding); x"
-e:1: undefined local variable or method `x' for main:Object (NameError)

> in irb you are __already__ in eval.  google the archives for more info.

gotcha! :) thanks
This topic is locked and can not be replied to.