Newbie: require 'filename' - undefined local variable or me


#1

I have one line of code in a file called ‘stuff.rb’:
myhash = { “a” => “ay”, “b” => “bee”, “c” => “sea” }

and I wish to include it in another program called ‘mainprog.rb’ thus:

 require 'stuff'

 puts " a = " + myhash["a"]

when I run it I get an error message:
mainprog.rb:4: undefined local variable or method `myhash’ for
main:Object (NameError)

I guess I must be doing something dumb - I am basing this code on
examples in ‘Why’s (poignant) guide to Ruby’. I am using the very
latest Windows version under XP Pro:
C:\rubysrcs>ruby -v
ruby 1.8.2 (2004-12-25) [i386-mswin32]

which I installed using the exe file: ruby182-15.exe

everything else I’ve tried seems to be working fine. Thanks.


#2

Grehom wrote:

I have one line of code in a file called ‘stuff.rb’:
myhash = { “a” => “ay”, “b” => “bee”, “c” => “sea” }

and I wish to include it in another program called ‘mainprog.rb’ thus:

 require 'stuff'

 puts " a = " + myhash["a"]

when I run it I get an error message:
mainprog.rb:4: undefined local variable or method `myhash’ for
main:Object (NameError)

I guess I must be doing something dumb - I am basing this code on
examples in ‘Why’s (poignant) guide to Ruby’. I am using the very
latest Windows version under XP Pro:
C:\rubysrcs>ruby -v
ruby 1.8.2 (2004-12-25) [i386-mswin32]

which I installed using the exe file: ruby182-15.exe

everything else I’ve tried seems to be working fine. Thanks.

myhash is a local variable in stuff.rb and will thus not
be available when you #require the file. There are a few
options you have: you could either make it a constant
(MY_HASH), a global ($my_hash) or you could wrap it inside
a method and then call the method in your main file.

E


#3

The exact details of why this I’m not familiar w/ but it is a scope
issue. The require won’t make the local variable into global for you.

The ‘myhash’ isn’t global just because it is declared outside of other
things… prefix that myhash w/ a $ and make it a global.

$myhash = { “a” => “ay”, “b” => “bee”, “c” => “sea” }


puts $myhash[‘a’]

-dayne


#4

On Dec 18, 2005, at 12:02 PM, Grehom wrote:

mainprog.rb:4: undefined local variable or method `myhash' for

everything else I’ve tried seems to be working fine. Thanks.

Try using this instead:

load ‘stuff’

local variables outside of class like that will not be imported when
you require that file. Load should do what you want.

Cheers-

-Ezra


#5

Grehom wrote:

mainprog.rb:4: undefined local variable or method `myhash' for

everything else I’ve tried seems to be working fine. Thanks.
this is a common gotcha, ruby doesn’t include “.” in $LOAD_PATH, which
is different from perl @INC and python PYTHONPATH so you have to

$:.unshift Dir.pwd

or somehtin like that


#6

Grehom wrote:

mainprog.rb:4: undefined local variable or method `myhash' for

main:Object (NameError)

Local vars are scoped to the file they are defined in, when you use
require or load. You could make it global, but unless this is just a
quick hack, it’s not a good solution.

Another option is to read and eval the file. If the myhash variable has
been assigned before you eval, then the assignment in stuff.rb will
propagate to the mainprog.rb. Like so:

myhash = nil
eval File.read(“stuff.rb”)
p myhash

This is ok for some purposes, but you have to know in advance which
variables the file is going to define. Also, you may have scope
collisions: any other local var in mainprog.rb can be affected by
assignments in stuff.rb.

My preference is to read the file as a string and use module_eval:

mainprog.rb

m = Module.new
m.module_eval(File.read(“stuff.rb”), File.expand_path(“stuff.rb”))
p m::Myhash

stuff.rb

Myhash = { “a” => “ay”, “b” => “bee”, “c” => “sea” }

Local vars stay local. Constants are accessible in the scope of the
newly defined module m. The second arg to module_eval means that errors
are reported with the correct file name.

This is the approach used by my “script” lib on raa. It adds some
sugar and features.


#7

On Dec 18, 2005, at 2:27 PM, Grehom wrote:

c:/ruby/lib/ruby/site_ruby

aforementioned tutorial book)!

Yeah I was wrong in thinking that load would load local vars. So like
others have said you will have to wrap your var in a method or class.
Or you could eval the file by reading the file in and running eval on
it.

#a.rb
a = [1,2,3,4,5,6]


#b.rb
a_contents = File.open(“a.rb”){|f| f.read}
eval a_contents
p a

=> [1, 2, 3, 4, 5]

-Ezra


#8

Thanks Joel, that worked but it’s way different from a number of
examples in the book ('Why’s (poignant) guide to Ruby), how did they
ever work there?


#9

Thanks Gene and Ezra, I tried your suggestions but with no luck. I
modified the main program ‘mainprog.rb’ as follows:
puts $:
load(“stuff.rb”, wrap=false)
puts myhash[“a”]

This produced following output:
C:\rubysrcs>ruby mainprog.rb
c:/ruby/lib/ruby/site_ruby/1.8
c:/ruby/lib/ruby/site_ruby/1.8/i386-msvcrt
c:/ruby/lib/ruby/site_ruby
c:/ruby/lib/ruby/1.8
c:/ruby/lib/ruby/1.8/i386-mswin32
.
mainprog.rb:5: undefined local variable or method `myhash’ for
main:Object (NameError)

and it seems the pwd ‘.’ is part of the Load Path already (without me
changing anything)

So I’m still puzzled (there are a few examples of code like this in
aforementioned tutorial book)!


#10

Ezra Z. wrote:

C:\rubysrcs>ruby mainprog.rb
changing anything)
#a.rb
-Ezra
[~/tmp] cat >a.rb
a = [1,2,3,4,5,6]
[~/tmp] cat >b.rb
a_contents = File.open(“a.rb”){|f| f.read}
eval a_contents
p a
[~/tmp] ruby b.rb
b.rb:3: undefined local variable or method `a’ for main:Object
(NameError)
[~/tmp] ruby -v
ruby 1.8.2 (2004-12-25) [i686-linux]

This only works if you assign to ‘a’ somewhere in b.rb before the eval.


#11

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 2005.12.19 07:27, “Grehom” removed_email_address@domain.invalid wrote:

c:/ruby/lib/ruby/site_ruby

aforementioned tutorial book)!
I think there may be a problem with the gateway again…

The problem you have is that myhash is local to stuff.rb and
will not be made available if you #require or #load the file.
Instead, you have a few options: either make myhash a constant
(MY_HASH), a global ($my_hash) or set up a method to retrieve
it (def my_hash(); …; end) and call the method from your
main file.

E
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDpe0rxvA1l6h+MUMRAsKyAJ43oioZaeoEZ8OD4omB8r9rIjEh9gCfWwTB
Lss8R5dkKElh589j7IT5RcE=
=w3Tl
-----END PGP SIGNATURE-----


#12

Grehom wrote:

Thanks Joel, that worked but it’s way different from a number of
examples in the book ('Why’s (poignant) guide to Ruby), how did they
ever work there?

I’m very sorry about this, Grehom. There is an update to the guide at:
http://qa.poignantguide.net/. This will all be rolled out soon with the
new design and the German and French editions of the Guide.

_why


#13

On Dec 18, 2005, at 2:46 PM, Joel VanderWerf wrote:

This produced following output:
and it seems the pwd ‘.’ is part of the Load Path already
Or you could eval the file by reading the file in and running eval

[~/tmp] ruby b.rb
b.rb:3: undefined local variable or method `a’ for main:Object
(NameError)
[~/tmp] ruby -v
ruby 1.8.2 (2004-12-25) [i686-linux]

This only works if you assign to ‘a’ somewhere in b.rb before the
eval.

Shows what I get for typing b.rb into irb instead of making it a real
file.

-Ezra


#14

Thanks _why,
I hate it when there is something like that I can’t get my head
around. I love the book, a little wierd as programming tutorials go,
but the programming stuff is very readable and I am finding it very
useful
G.