Adding local variables via block

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!

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

···

On 2/20/07, Paul Danese <pdanese@rib-x.com> wrote:

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?

Hi,

####################
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! :slight_smile:

···

On Tuesday 20 February 2007 19:33, Paul Danese wrote:
--
pub 1024D/8D2787EF 723C 7CA3 3C19 2ACE 6E20 9CC1 9956 EB3C 8D27 87EF

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

James Edward Gray II

···

On Feb 20, 2007, at 12:52 PM, Tim Pease wrote:
         from :0

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

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

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

···

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:

Hi,

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>

···

On Tuesday 20 February 2007 21:02, Patrick Hurley wrote:

--
pub 1024D/8D2787EF 723C 7CA3 3C19 2ACE 6E20 9CC1 9956 EB3C 8D27 87EF

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

cheers.

-a

···

On Wed, 21 Feb 2007, Marcello Barnaba wrote:

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>

--
we can deny everything, except that we have the possibility of being better.
simply reflect on that.
- the dalai lama

Hi,

> Hi,
>
>> 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>

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! :slight_smile: thanks

···

On Tuesday 20 February 2007 21:14, ara.t.howard@noaa.gov wrote:

On Wed, 21 Feb 2007, Marcello Barnaba wrote:
> On Tuesday 20 February 2007 21:02, Patrick Hurley wrote:

--
pub 1024D/8D2787EF 723C 7CA3 3C19 2ACE 6E20 9CC1 9956 EB3C 8D27 87EF