Forum: Ruby Loading classes in order

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Elias O. (Guest)
on 2009-04-04 00:53
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
Joel VanderWerf (Guest)
on 2009-04-04 01:10
(Received via mailing list)
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?
Elias O. (Guest)
on 2009-04-04 01:19
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?
Iñaki Baz C. (Guest)
on 2009-04-04 01:25
(Received via mailing list)
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
Elias O. (Guest)
on 2009-04-04 01:33
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.
Robert K. (Guest)
on 2009-04-04 02:00
(Received via mailing list)
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
Iñaki Baz C. (Guest)
on 2009-04-04 02:01
(Received via mailing list)
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).
Elias O. (Guest)
on 2009-04-04 02:31
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).
David M. (Guest)
on 2009-04-04 03:33
(Received via mailing list)
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.
Robert K. (Guest)
on 2009-04-04 16:10
(Received via mailing list)
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.
Elias O. (Guest)
on 2009-04-04 22:24
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
Tony A. (Guest)
on 2009-04-04 22:49
(Received via mailing list)
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.
Iñaki Baz C. (Guest)
on 2009-04-04 22:57
(Received via mailing list)
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.
Iñaki Baz C. (Guest)
on 2009-04-04 23:08
(Received via mailing list)
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.
Douglas S. (Guest)
on 2009-04-05 18:48
(Received via mailing list)
circular dependency comes to mind ...
Phlip (Guest)
on 2009-04-05 19:06
(Received via mailing list)
>> 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.
Rick D. (Guest)
on 2009-04-07 00:40
(Received via mailing list)
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-...
--
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
This topic is locked and can not be replied to.