Forum: Ruby Include Module gives Uninitialized Constant error

B652a346f3c4834a953894194999c3e5?d=identicon&s=25 Daniel B. Davis (danielbdavis)
on 2014-06-14 07:01
Attachment: samp.erb (371 Bytes)
Attachment: sampMod.rb (2 KB)
Attachment: terminal.txt (708 Bytes)
I am learning Ruby, but no beginner in computers. If this belongs in
Ruby on Rails, then please move it, but since I am using Cuba, a
micro-framework, I did not put it into R-on-R. I seem to have tried
quite a number of alternatives to cure this problem, with no success.
This is a scaled-down sample which preserves the error. In the final
system the included module will be generated by algorithm. It contains
the data for drawing parts of a game, as an array of hashes. The
generated code works when it is manually copied to the equivalent of
"samp.erb". Now, I want to include it there automatically as sampMod.rb.
The files: 1. samp.erb:     the file which includes the module
           2. sampMod:      the file containing the module
           3. terminal.txt: the console output
54404bcac0f45bf1c8e8b827cd9bb709?d=identicon&s=25 7stud -- (7stud)
on 2014-06-15 19:32
> I am learning Ruby

Then you probably aren't going to understand this...

1) Get rid of 'require rubygems' unless you are using old versions of
ruby and rubygems.

2) Name the file that contains the module "samp_mod.rb"--it's ruby code
afterall.

3) You define a module with the 'module' keyword NOT "Module".

4) module definitions, like class definitions are terminated with the
"end" keyword.

5) @ variables attach themselves to whatever object is self at the
instant the @ variable is created.  Similarly, when you try to retrieve
the value of an @variable, ruby looks at whatever object is self at that
instant and tries to lookup the @ variable in self.


module A
  p self
  @x = 'hello'
end

p self
p @x

--output:--
A
main
nil

Based on that output, @x attaches itself to A, but when @x is retrieved
an object called 'main' is self, and 'main' does not have an @x instance
variable, so nil is returned.


6)  A def starts a new scope, and nothing outside the def can be seen
inside the def.  In your def here:

  def getsamp(index, attr)
    return @samp[index][attr]
  end

@samp will be looked up in whatever object is self when the def
executes, and when the def executes self will be the object that called
the def.  What object is that?  If you add some code to the erb
file, you can find out:

<% require './samp_mod'; include SampMod %>

self is equal to: <%= self %>

~/ruby_programs$ erb samp.erb > erb_result.txt
~/ruby_programs$ cat erb_result.txt

self is equal to: main

So you have the same problem as above with @x: namely, @samp is being
looked up
in an object called main, yet when you defined @samp it attached itself
to SampMod.

Note that in ruby, ALL methods are called by some object.  If no
object is explicitly specified to the left of the method call, then
ruby uses whatever object is self to call the method.

A first attempt to correct the problem might look something like this:

module SampMod
  @samp = ['hello']

  def getsamp
    return SampMod.samp
  end
end


But that will produce the error:

 `getsamp': undefined method `samp' for SampMod:Module (NoMethodError)

You get that error because @ variables are private by default, so you
need to provide an accessor for the variable:

module SampMod
  @samp = ["hello"]

  attr_reader :samp


  def getsamp
    return SampMod.samp
  end
end

--output:--
~/ruby_programs$ erb samp.erb > erb_result.txt
~/ruby_programs$ cat erb_result.txt

self is equal to: main
Result: ["hello"]

Because all of the above is probably too complicated to comprehend,
if you can, the easiest thing to do is just make @samp a constant:

module SampMod
  SAMP = ["hello"]

  def getsamp
    return SAMP
  end
end

Lookups for constants work differently: the lookup starts in the inner
scope (the def) and moves outwards to the surrounding scopes (the
module).  And you can always
specify the absolute constant name: SampMod::SAMP to retrieve the
constant from anywhere.
B652a346f3c4834a953894194999c3e5?d=identicon&s=25 Daniel B. Davis (danielbdavis)
on 2014-06-17 06:54
Thank you so very much. I am hard at work understanding this, and when I
do, I am sure it will be salutary to all of my future ruby efforts. I
may bring bad habits of thought to ruby from a long history with
assembly code, PL/I, C, C++, COBOL, FORTRAN, Perl Tcl/Tk, Objective C
and Java, and while I seem to understand the surface of all that you
have written (maybe some others I've forgotten), and believe it is
within my grasp to work through their implications, one thing baffles
me: why is it needed to remove the "require rubygems'; or
,alternatively, when is it required to add it?

Even more important than the code is the manner in which you have taken
the time to explain the underlying effects This Creates both extreme
gratitude and admiration. It is very easy to get a smattering of Ruby
from books, but without this sort of code practice, fluency will never
be achieved. We need to be allowed to stumble, hurt, get up, and retry.
Thanks so much again.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.