Loading classes in order


#1

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

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


#2

Elias O. wrote:

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?


#3

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

Joel VanderWerf wrote:

Elias O. wrote:

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?


#4

Iñaki Baz C. wrote:

El Viernes 03 Abril 2009, Elias O. 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.


#5

On 03.04.2009 23:32, Elias O. wrote:

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


#6

El Viernes 03 Abril 2009, Elias O. 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


#7

El Viernes 03 Abril 2009, Elias O. 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

(It should be very improved however).


#8

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

On Friday 03 April 2009 16:18:55 Elias O. wrote:

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.


#9

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 C. wrote:

El Viernes 03 Abril 2009, Elias O. 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

(It should be very improved however).


#10

Robert K. wrote:

On 04.04.2009 00:31, Elias O. wrote:

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.

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


#11

On Fri, Apr 3, 2009 at 4:31 PM, Elias O. removed_email_address@domain.invalid wrote:

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.


#12

El Sábado 04 Abril 2009, Elias O. escribió:

that.
Another approach would be loading first a file containing all the
classes
“declaration”, this is:


class AAA ; end
class BBB ; end
[…]

and later load all the files with classes real “definition”.

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


#13

On 04.04.2009 00:31, Elias O. wrote:

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.


#14

El Sábado 04 Abril 2009, Tony A. escribió:

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.

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
and
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.


#15

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.

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.


#16

circular dependency comes to mind …


#17

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