Basics of Require

M

Mike Stephens

I don't have access to an instance of Ruby at the moment and I am not
clear what is being said in The Ruby Programming Language (Flanagan &
Matsumoto). It says require code is executed immediately. It also says
you can't insert the require code in the middle of something as if you
are copy-and-pasting, so can you explain some basics of what actually
happens?

If I have a file myprog.rb and libfile1.rb, and I run myprog:

myprog1.rb========
statement_1
require libfile1
==============

libfile1.rb=======
statement_2
==============

... I believe Ruby will run statement 1 and then run statement 2

Now if I change this to:

myprog2.rb========
statement_1
require libfile2
==============

libfile2.rb=================
Module Libfilemod
statement_2
end
======================

...I assume Ruby only runs statement 1 and stops

Now if I change myprog:

myprog3=========
statement_1
def calllibfile
require libfile1
end
================

...well, can you do that? If you can, presumably Ruby reads libfile1 but
doesn't execute it?

Also does require get executed in the order of text encountered in the
file or does the Ruby runtime pick out the keyword require up front and
expand it before the native code?

myprog1.rb========
statement_1
require libfile1
==============

libfile1.rb=======
statement_2
==============

Does this do 1 then 2 or 2 first?

What are the differences between wrapping require code in 'Module',
'Def' and 'Class'?

The final question is in typical web environments like webrick, apache
or eruby, does the require code get loaded and 'compiled' everytime any
program refers to it or is there some mechanism to cache common code in
'compiled' form?
 
P

Phlip

Mike said:
I don't have access to an instance of Ruby at the moment

You might ought to explain that one. It even runs on wrist watches these days!
and I am not
clear what is being said in The Ruby Programming Language (Flanagan &
Matsumoto). It says require code is executed immediately. It also says
you can't insert the require code in the middle of something as if you
are copy-and-pasting, so can you explain some basics of what actually
happens?

If I have a file myprog.rb and libfile1.rb, and I run myprog:

myprog1.rb========
statement_1
require libfile1
==============

libfile1.rb=======
statement_2
==============

.. I believe Ruby will run statement 1 and then run statement 2
Ya.


Now if I change this to:

myprog2.rb========
statement_1
require libfile2
==============

libfile2.rb=================
Module Libfilemod
statement_2
end
======================

..I assume Ruby only runs statement 1 and stops

it runs statement_2 while compiling module Libfilemod.
Now if I change myprog:

myprog3=========
statement_1
def calllibfile
require libfile1
end
================

..well, can you do that? If you can, presumably Ruby reads libfile1 but
doesn't execute it?

When you call calllibfile, the libfile1 gets evaluated and inserted into the
current environment (unless if someone else already required it).

However, the contents of libfile1 do not get inserted into the current scope
(inside calllibfile). They insert into the top-level context. This is so you can
delay requiring them, but get their symbols with the correct scope.
Also does require get executed in the order of text encountered in the
file or does the Ruby runtime pick out the keyword require up front and
expand it before the native code?

The Ruby parser always runs top-to-bottom in each context
myprog1.rb========
statement_1
require libfile1
==============

libfile1.rb=======
statement_2
==============

Does this do 1 then 2 or 2 first?

You already asked that!

And get used to:

require 'libfile1'

require is nothing more than a method that takes a string. It's not a magic
keyword with its own parsing rules (like its equivalents are in certain other
languages.)
What are the differences between wrapping require code in 'Module',
'Def' and 'Class'?

Nope - your tutorials cover that. Read on!
The final question is in typical web environments like webrick, apache
or eruby, does the require code get loaded and 'compiled' everytime any
program refers to it or is there some mechanism to cache common code in
'compiled' form?

The second require simply does not happen (if the string argument is the same!).
So all the same symbols remain in the same Ruby environment.
 
K

Ken Bloom

I don't have access to an instance of Ruby at the moment and I am not
clear what is being said in The Ruby Programming Language (Flanagan &
Matsumoto). It says require code is executed immediately. It also says
you can't insert the require code in the middle of something as if you
are copy-and-pasting, so can you explain some basics of what actually
happens?
What are the differences between wrapping require code in 'Module',
'Def' and 'Class'?

def method
require 'foo'
end

only loads 'foo' when you call the method. The contents of 'foo' are
visible globally. (Unlike a #include in C)

module Foo
require 'foo'
end

class Foo
require 'foo'
end

These are exactly the same. They both load 'foo', and the contents of
'foo' are NOT wrapped in the module or class Foo.
The final question is in typical web environments like webrick, apache
or eruby, does the require code get loaded and 'compiled' everytime any
program refers to it or is there some mechanism to cache common code in
'compiled' form?

That depends on the environment. Webrick, which is a web server written
in Ruby, keeps the same ruby interpreter running the whole time your
server is running, so if you 'require' once, then the code stays loaded
the whole time the server is running. With apache, it would depend on how
you've set up apache to run the ruby interpreter. Eruby is a library that
runs within a ruby interpreter, so it's not really relevant to this
question.
 
R

Rick DeNatale

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

There's a very nice, underused method of module which can help with loading
code on demand. Despite being quite fluent in Ruby, I only found out about
it a few weeks ago, thanks to Chad Fowler.

It's Module#autoload. It takes two arguments. The first is the NAME of a
constant as either a String or a Symbol, the second is a string with the
same meaning of the argument to require. What it does is to associate the
first argument with the second, and if and when an undefined constant
matching the first argument is encountered in the scope of the module, to
effectively require the file named by the path argument. It can be used at
the top level to autoload definitions of contstants in the global scope.
For example

# at top level
autoload :Foo, 'lib/foo' # this will load lib/foo.rb the first time anyone
references ::Foo

require 'something.rb'

# in file lib/foo.rb
class Foo
autoload :Bar, 'lib/foo/bar' # loads lib/foo/bar.rb when ::Foo::Bar is
referenced when undefined
end

# in file 'lib/foo/bar.rb'
module Foo::Bar
# code
end

# in file 'something.rb'

class MyClass < Foo
#...
end

When the 'class Myclass < Foo' is executed, Foo will be undefined, this will
trigger the load of 'lib/foo.rb' which is expected to define the constant
Foo which it does. Similarly lib/foo/bar.rb would be loaded if an when some
code defined ::Foo::Bar as an undefined constant.

This is somewhat similar to the automatic class loading built into Rails
(actually the ActiveSupport component of rails) using constant_missing, but
it's actually built into Ruby, and has been for quite a while. In fact
ActiveSupport and the rest of rails is evolving to implement automatic class
loading using autoload, which is how I learned about it. Chad was doing a
walkthrough of ActiveRecord at RubyRx and showed the new code.

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
M

Mike Stephens

Ken said:
def method
require 'foo'
end

only loads 'foo' when you call the method. The contents of 'foo' are
visible globally. (Unlike a #include in C)

module Foo
require 'foo'
end

class Foo
require 'foo'
end

These are exactly the same. They both load 'foo', and the contents of
'foo' are NOT wrapped in the module or class Foo.

I can't see the logic there. You're saying if the require is inside a
method, Ruby will not doing anything until your program calls that
method. However if the require is inside a class, Ruby will go and fetch
the code before you ever refer to that class?
 
M

matt neuburg

Mike Stephens said:
I can't see the logic there. You're saying if the require is inside a
method, Ruby will not doing anything until your program calls that
method. However if the require is inside a class, Ruby will go and fetch
the code before you ever refer to that class?

The thing to grok here that is a class or module definition is itself
executable code. That, after all, is how the class gets defined! When
you say:

class MyClass
end

you really are executing code in order to bring the class into existence
(the constant name is created, etc).

When you think about it this way, you realize, aha! That's how stuff
like attr works. A big hunk of the coolness of Ruby depends upon this
very fact.

class MyClass
attr :howdy # executes right now!
end

Similarly if you say

class MyClass
puts "howdy"
end

.... then "howdy" is output as soon as this code is encountered. It is
executable code.

But a method definition just defines a method. So when you say:

class MyClass
def howdy
puts "howdy"
end
end

then "howdy" is not output, because all you did was define a method -
you haven't called it yet. The "def" is executed right now (i.e. the
method is indeed brought into existence) but its *contents* are not
executed (though of course the interpreter is applied to them, to make
sense of them). m.
 

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
473,780
Messages
2,569,611
Members
45,267
Latest member
WaylonCogb

Latest Threads

Top