Loading classes in order

E

Elias Orozco

Hello guys,

I have a folder that contains several classes. There are some some
dependencies between them as one class could extend from another one
included in the folder. I am trying to require them all dynamically but
I get:

uninitialized constant <name of the class>

This happens because I try to require a class that extends from a class
I haven't require yet. So can anyone help or give me any hint on how to
load them all dynamically and deal with those dependencies?

Thanks,

Elías
 
J

Joel VanderWerf

Elias said:
Hello guys,

I have a folder that contains several classes. There are some some
dependencies between them as one class could extend from another one
included in the folder. I am trying to require them all dynamically but
I get:

uninitialized constant <name of the class>

This happens because I try to require a class that extends from a class
I haven't require yet. So can anyone help or give me any hint on how to
load them all dynamically and deal with those dependencies?

Thanks,

Elías

Can you insert requires in these files to make the dependencies explicit?
 
E

Elias Orozco

Hi Joel thanks for the reply. The idea is to load them at once. Without
specifying requires inside each class. I have seen that when I put a
series of classes on the rails lib folder everything loads without
problem. I have looked into rails itself, but I don't get how it does
that.

Thanks,

Elías
 
I

Iñaki Baz Castillo

El Viernes 03 Abril 2009, Elias Orozco escribi=C3=B3:
Hello guys,

I have a folder that contains several classes. There are some some
dependencies between them as one class could extend from another one
included in the folder. I am trying to require them all dynamically but
I get:

uninitialized constant <name of the class>

This happens because I try to require a class that extends from a class
I haven't require yet. So can anyone help or give me any hint on how to
load them all dynamically and deal with those dependencies?

path =3D File.dirname(__FILE__) + "/files_dir"

require "#{path}/required_file1"
require "#{path}/required_file2"
require "#{path}/required_file3"

Dir.chdir(path)
Dir["*.rb"].each do |file|
require "#{path}/#{file}"
end


=2D-=20
I=C3=B1aki Baz Castillo <[email protected]>
 
E

Elias Orozco

Iñaki Baz Castillo said:
El Viernes 03 Abril 2009, Elias Orozco escribió:
I haven't require yet. So can anyone help or give me any hint on how to
load them all dynamically and deal with those dependencies?

path = File.dirname(__FILE__) + "/files_dir"

require "#{path}/required_file1"
require "#{path}/required_file2"
require "#{path}/required_file3"

Dir.chdir(path)
Dir["*.rb"].each do |file|
require "#{path}/#{file}"
end

Thanks Inaki, but in that example I will have to specify the require
files and that's exactly what I don't want. A lot of classes will be
copied into that folder and I can't hard-code all those requires.
 
R

Robert Klemme

Iñaki Baz Castillo said:
El Viernes 03 Abril 2009, Elias Orozco escribió:
I haven't require yet. So can anyone help or give me any hint on how to
load them all dynamically and deal with those dependencies?
path = File.dirname(__FILE__) + "/files_dir"

require "#{path}/required_file1"
require "#{path}/required_file2"
require "#{path}/required_file3"

Dir.chdir(path)
Dir["*.rb"].each do |file|
require "#{path}/#{file}"
end

Thanks Inaki, but in that example I will have to specify the require
files and that's exactly what I don't want. A lot of classes will be
copied into that folder and I can't hard-code all those requires.

Personally I would prefer to make dependencies explicit and insert
require statements in all of those files. That's the most reasonable
solution and then the approach from above will work properly.

An alternative might be to rescue any exceptions and require files again.

Cheers

robert
 
I

Iñaki Baz Castillo

El Viernes 03 Abril 2009, Elias Orozco escribi=C3=B3:
I=C3=B1aki Baz Castillo said:
El Viernes 03 Abril 2009, Elias Orozco escribi=C3=B3:
I haven't require yet. So can anyone help or give me any hint on how to
load them all dynamically and deal with those dependencies?

path =3D File.dirname(__FILE__) + "/files_dir"

require "#{path}/required_file1"
require "#{path}/required_file2"
require "#{path}/required_file3"

Dir.chdir(path)
Dir["*.rb"].each do |file|
require "#{path}/#{file}"
end

Thanks Inaki, but in that example I will have to specify the require
files and that's exactly what I don't want. A lot of classes will be
copied into that folder and I can't hard-code all those requires.

When failing due to a non existing class, Ruby raises a NameError exception.
Then you can add something as:

=2D--------------------------
failed_files=3D[]

path =3D xxxxxx
Dir.chdir(path)

Dir["*.rb"].each do |file|
begin
require "#{path}/#{file}"
rescue NameError
failed_files << file
end
end

failed_files.each do |file|
require "#{path}/#{file}"
end
=2D---------------------------

(It should be very improved however).

=2D-=20
I=C3=B1aki Baz Castillo <[email protected]>
 
E

Elias Orozco

Hey Inaki thanks,

I think I'll have to go that way. I wonder if that is how rails does to
load classes when the server is initialize. I wandered around the
initializer file but couldn't get how it was done. Thanks again,

Elias

Iñaki Baz Castillo said:
El Viernes 03 Abril 2009, Elias Orozco escribió:
Dir.chdir(path)
Dir["*.rb"].each do |file|
require "#{path}/#{file}"
end

Thanks Inaki, but in that example I will have to specify the require
files and that's exactly what I don't want. A lot of classes will be
copied into that folder and I can't hard-code all those requires.

When failing due to a non existing class, Ruby raises a NameError
exception.
Then you can add something as:

---------------------------
failed_files=[]

path = xxxxxx
Dir.chdir(path)

Dir["*.rb"].each do |file|
begin
require "#{path}/#{file}"
rescue NameError
failed_files << file
end
end

failed_files.each do |file|
require "#{path}/#{file}"
end
 
D

David Masover

Hey, top-posting is annoying. You're replying above what everyone else wrote,
which means people have no context.

Hi Joel thanks for the reply. The idea is to load them at once. Without
specifying requires inside each class.

Requires don't need to be inside classes, just files. You can have more than
one class per file, or a file that takes up multiple classes.
I have seen that when I put a
series of classes on the rails lib folder everything loads without
problem. I have looked into rails itself, but I don't get how it does
that.

Rails intercepts Object#cost_missing, and uses that to load anything with the
same name. Basically, this means that the first time you try to use a class, it
gets loaded.

I wrote a little library that does something similar, but with Kernel#autoload
instead -- it's slightly faster and more flexible:

http://github.com/masover/autoloader

You can install that, and it will either use activesupport (from Rails), or
extlib (used by Merb), depending what's available (or what you already
loaded).

If it doesn't work for you, it should be small enough to be readable.
 
R

Robert Klemme

I think I'll have to go that way.

I do not understand why you seem to be so reluctant to declare
dependencies properly via "require". Can you explain that? The time it
takes to discuss this and search Rails source code is almost certainly
more than what it takes to simply use "require" the way it was intended to.
I wonder if that is how rails does to
load classes when the server is initialize. I wandered around the
initializer file but couldn't get how it was done. Thanks again,

Are you sure you can throw a number of files with dependencies into a
folder and Rails will somehow figure the load order?

Regards

robert


PS: Please do not top post.
 
E

Elias Orozco

Robert said:
I do not understand why you seem to be so reluctant to declare
dependencies properly via "require". Can you explain that? The time it
takes to discuss this and search Rails source code is almost certainly
more than what it takes to simply use "require" the way it was intended
to.


Are you sure you can throw a number of files with dependencies into a
folder and Rails will somehow figure the load order?

Regards

robert


PS: Please do not top post.

The app I'm working on is an online editor where a user create classes
that connect to back-ends and fetch data. The users can create classes
and have them all in their personal folder (security issues with this
type of apps are high, I'm working on that too). So basically when the
user wants to initialize an object of a class that depends on another
one I don't want uninitialized constant errors. I could make require as
it is the way is intended to do as you say. But I have seen that when I
put all those classes in the rails lib folder, for example, they're all
loaded without problem when I initialize the server and I can make an
instance object of any class without any error. I want something like
that.

Thanks,

Elias
 
T

Tony Arcieri

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

Hey Inaki thanks,

I think I'll have to go that way. I wonder if that is how rails does to
load classes when the server is initialize. I wandered around the
initializer file but couldn't get how it was done. Thanks again,

Look at Merb. Don't go the horrible ActiveSupport route.

Merb's loader works somewhat similarly to what Inaki pasted, except it
loops, retrying the failed files. If it loops through the failed files and
no new ones are loaded it gives up.
 
I

Iñaki Baz Castillo

El S=C3=A1bado 04 Abril 2009, Elias Orozco escribi=C3=B3:
The app I'm working on is an online editor where a user create classes
that connect to back-ends and fetch data. The users can create classes
and have them all in their personal folder (security issues with this
type of apps are high, I'm working on that too). So basically when the
user wants to initialize an object of a class that depends on another
one I don't want uninitialized constant errors. I could make require as
it is the way is intended to do as you say. But I have seen that when I
put all those classes in the rails lib folder, for example, they're all
loaded without problem when I initialize the server and I can make an
instance object of any class without any error. I want something like
that.

Another approach would be loading first a file containing all the classes=20
"declaration", this is:

=2D---------
class AAA ; end
class BBB ; end
[...]
=2D---------

and later load all the files with classes real "definition".

Not sure if this option is suitable in your case however.

=2D-=20
I=C3=B1aki Baz Castillo <[email protected]>
 
I

Iñaki Baz Castillo

El S=C3=A1bado 04 Abril 2009, Tony Arcieri escribi=C3=B3:
Merb's loader works somewhat similarly to what Inaki pasted, except it
loops, retrying the failed files. If it loops through the failed files a= nd
no new ones are loaded it gives up.

Imagining a very complex case it could occur that class_A defined in file_A=
=20
depends on class_C defined in file_C, and class_C depends on class_B define=
d=20
in file_B.

So the correct loading order would be:

require "file_B"
require "file_C"
require "file_A"

Loading in alphabetic order (A, B, C) would load just file_B. So file_A and=
=20
file_C would require a new try. Trying again in alphabetic order (A, C) wou=
ld=20
load just file_C, and file_A would fail.
So a third attemp would load just file_A (succesfully now).

I wonder if could be a case in which this approach wouldn't work.


=2D-=20
I=C3=B1aki Baz Castillo <[email protected]>
 
D

Douglas Seifert

circular dependency comes to mind ...

El S=E1bado 04 Abril 2009, Tony Arcieri escribi=F3:

Imagining a very complex case it could occur that class_A defined in file= _A
depends on class_C defined in file_C, and class_C depends on class_B
defined
in file_B.

So the correct loading order would be:

require "file_B"
require "file_C"
require "file_A"

Loading in alphabetic order (A, B, C) would load just file_B. So file_A a= nd
file_C would require a new try. Trying again in alphabetic order (A, C)
would
load just file_C, and file_A would fail.
So a third attemp would load just file_A (succesfully now).

I wonder if could be a case in which this approach wouldn't work.
 
P

Phlip

Imagining a very complex case it could occur that class_A defined in file_A
Ruby can't require the classes so strictly. C++ could, and maybe Java could. But
a Duck Typing language simply cannot require that! A given implementation of
that design might have some mistake that forces the require order, but the
mistake itself is always fixable.

For example, don't include this above your first require 'test/unit':

module Test::Unit::Assertions
def test_my_awesome_assertion
end
end

The fix is very simple:

module Test; module Unit; module Assertions
def test_my_awesome_assertion
end
end; end; end

Now that can harmlessly appear above the original module Assertions.
 
R

Rick DeNatale

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

I finally got around to writing about the Kernel#autoload and
Module#autoload which comprise a little known feature of standard Ruby which
helps solve these kind of problems:
http://talklikeaduck.denhaven2.com/2009/04/06/all-that-you-might-require
--
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
 

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

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top