Where does instance_eval _magically_ set the variable to?

A

Andrew Chen

Hi,

I use the instance_eval to merge template file and parameter files.
cat param.txt name="John"
cat tmpl.txt
my name is: said:
cat template.rb
#!/usr/bin/env ruby
require 'erb'

instance_eval(File.read('param.txt'))
puts ERB.new(File.read("tmpl.txt")).result(binding)

puts name
template.rb
my name is: John
template.rb:7: undefined method `name' for main:Object (NoMethodError)


Where is the variable "name" set to? How to access it?
It must be somewhere, since it is used in the tmpl.txt file.

Is there any "magic" namespace in Ruby?

Thanks
~Andrew Chen
 
T

Todd Benson

Hi,

I use the instance_eval to merge template file and parameter files.


#!/usr/bin/env ruby
require 'erb'

name = nil
instance_eval(File.read('param.txt'))
puts ERB.new(File.read("tmpl.txt")).result(binding)

puts name

my name is: John
template.rb:7: undefined method `name' for main:Object (NoMethodError)


Where is the variable "name" set to? How to access it?
It must be somewhere, since it is used in the tmpl.txt file.

Is there any "magic" namespace in Ruby?

It's just a scope issue. If you use name = nil like I did above you
should be okay. I wonder, though, why you would want to
#instance_eval instead of using #load.

Also, some rubyists advocate using the block method of File.open as
well. I'm not sure if File.read closes the file automatically.

hth,
Todd
 
A

Andrew Chen

Jeri,
How about:
load 'param.txt'

Load doesn't get the variable into the current namespace. Maybe I
used it wrong?
cat param.txt name='John'
cat load.rb
#!/usr/bin/env ruby

load 'param.txt'

puts name
./load.rb
../load.rb:5: undefined local variable or method `name' for main:Object
(NameError)
 
T

Todd Benson

On Thu, Feb 21, 2008 at 2:04 PM, Todd Benson
I wonder, though, why you would want to
#instance_eval instead of using #load.

If those are just parameters, you might consider using the YAML
library. Just a thought...

Todd
 
T

Todd Benson

Jeri,



Load doesn't get the variable into the current namespace. Maybe I
used it wrong?

Nope, you didn't. I'm sure there's a reason for that; probably to
prevent accidental corruption of namespace. If you must use load,
you'll have to build methods in the loaded file instead of
variables...

def name; 'John'; end

...which may or may not work for you.

I suggest going the YAML route. I suppose there are other ways to
serialize data, too.

Todd
 
A

Andrew Chen

Todd,
Yes, load more proper here than instance_eval.
Also, I will use File.open block instead of File.read.

However, this is still a mystery:
In the original code, where did the variable "name" go? How to access
that?

When I use load 'param.txt', how to access variables loaded from the
param.txt file?
cat param.txt Name='John'
Name='John'
last="smith"
./load.rb
../param.txt:2: warning: already initialized constant Name
John
../load.rb:6: undefined local variable or method `last' for main:Object
(NameError)
Thanks
~Andrew Chen
 
A

Andrew Chen

Todd,
"I suggest going the YAML route. I suppose there are other ways to
serialize data, too."

I thought about yaml.

However, I want to make a parameter file for easy template. Maybe I
can do a pre-transformation from ruby data to yaml, then from yaml to
data.

My goal is to read data from a parameter file (ruby data format) into
memory, without @, $, Uppercase_name.

Thanks
~Andrew Chen
 
A

Andrew Chen

Todd,
There are some subtle difference between load and instance_eval.
In this case, instance_eval works, the load doesn't.

I still have no idea where the instance_eval put the variables at.
cat param.txt name="John"
cat tmpl.txt
my name is: said:
cat erb_instance_eval.rb
#!/usr/bin/env ruby

require 'erb'

instance_eval(File.read("param.txt"))
#load "param.txt"
puts ERB.new(File.read("tmpl.txt")).result(binding)
./erb_instance_eval.rb
my name is: John

cat erb_load.rb
#!/usr/bin/env ruby

require 'erb'

#instance_eval(File.read("param.txt"))
load "param.txt"
puts ERB.new(File.read("tmpl.txt")).result(binding)
./erb_load.rb
(erb):1: undefined local variable or method `name' for main:Object
(NameError)
from ./erb_load.rb:7
Also, the load_yaml won't work, because I need to setup variables
dynamically.

Thanks
~Andrew Chen
 
J

Jari Williamsson

Strange. The REALLY interesting stuff starts to happen when you
encapsulate the code in a module. (name becomes the name of the module)


Best regards,

Jari Williamsson
 
T

Todd Benson

Todd,
Yes, load more proper here than instance_eval.
Also, I will use File.open block instead of File.read.

However, this is still a mystery:
In the original code, where did the variable "name" go? How to access
that?

It's signed up for garbage collection when you exit the #instance_eval
or #load method (I think). In other words, it has a temporary
existence. There's nothing holding on to it (referencing it).

Todd
 
A

Arlen Cuss

[Note: parts of this message were removed to make it a legal post.]

Hi all,

The reason is it's a local variable inside a block. Have a look at this, for
example:
1
4
9
16
25
=> 1NameError: undefined local variable or method `j' for main:Object
from (irb):2
j is undefined after the block's execution. If we let j be defined before
the block, however, ...
1
4
9
16
25
=> 1=> 25

Since j is already defined, Ruby uses that instead. Confusing, but could be
useful.

Arlen
 
T

Todd Benson

Also, the load_yaml won't work, because I need to setup variables
dynamically.

You want to do variable assignment via a file, right? Is it not
possible to do this?

$ cat a.yml
name: John
$ cat a.rb
h = YAML.load_file('a.yml')
puts h['name']

Todd
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,284
Messages
2,571,413
Members
48,106
Latest member
JamisonDev

Latest Threads

Top