Autoloader, version 0.0.2

A couple of handy features to enhance Kernel#autoload.

Changes since 0.0.1: minor tweaks to the gem, and migrated to gemcutter.

Question: How do I add a choice of dependencies? Right now, I can use
either
extlib or activesupport for inflections.

Also: This is my first ever ruby-talk announcement. Someone please tell
me if
I am Doing It Wrong.

Pasted from the README:

Features

  • Fire Kernel#autoload at an entire directory
  • Fire it again at a subdirectory, for namespace’d models

Motivation/Examples

I was using Ramaze as a web framework, and discovered that the standard
Ramaze
way of loading a directory of files is to slurp them all (with
‘acquire’). I
decided I’d rather use autoload, and not load things I’m not using. But
I
wasn’t really looking forward to this:

autoload :User, ‘model/user’
autoload :Clan, ‘model/clan’
autoload :Item, ‘model/item’

…ad nauseum. So, the first feature is a shallow, directory-based
autoload:

AutoLoader << ‘model’

Of course, being a pedant, I like to namespace my models. I don’t want
to
slurp the entire directory tree. Instead, you can do this:

class User < MyFavoriteORM::Model
include AutoLoader

end

Now, all AutoLoaded paths will be searched for a subdirectory called
‘user’,
and all files within will be autoloaded. Just as if you’d done:

User.autoload :Anonymous, ‘model/user/anonymous’
User.autoload :Registered, ‘model/user/registered’

Of course, there’s no requirement that you have a base class, or
anything of
the sort. If you just want a namespace, you can always do:

module MyNamespace; include AutoLoader; end

And you’re done.

Compatibility

Currently, Merb’s extlib and Rails’ activesupport are supported. It
should be
trivial to interface with other libraries.

2009/11/24 David M. [email protected]:

A couple of handy features to enhance Kernel#autoload.

Changes since 0.0.1: minor tweaks to the gem, and migrated to gemcutter.

Question: How do I add a choice of dependencies? Right now, I can use either
extlib or activesupport for inflections.

Also: This is my first ever ruby-talk announcement. Someone please tell me if
I am Doing It Wrong.

Looks fine to me. But I do wonder how you generate the symbol names
for autoload files? Basically autoload needs a symbol name and a file
name. While the file names can be extracted from a directory how do
you find the symbol name? Maybe users should be able to customize
that algorithm in order to be able to autoload class “FooBar” from
file “foobar.rb” or “foo_bar.rb”. I would at least add a description
how you generate the symbol name from the file name.

Btw, one disadvantage of using a directory glob is that it is far more
expensive than the standard autoload because the standard autoload
does not need any file system IO before any file is loaded. Using
directory globbing on the other hand requires to at least read the
directory which may slow down startup of a script considerably.

Kind regards

robert

On Tue, Nov 24, 2009 at 12:34 AM, David M. [email protected]
wrote:

A couple of handy features to enhance Kernel#autoload.

Changes since 0.0.1: minor tweaks to the gem, and migrated to gemcutter.

Question: How do I add a choice of dependencies? Right now, I can use either
extlib or activesupport for inflections.

As far as I know, you can’t.

I’ve got a similar situation with ri_cal which needs either
activesupport or tzinfo. I asked about this on the rubygems list and
alternate dependencies seemed to be something which had come up from
time to time but hadn’t been addressed.

I just didn’t declare either as a dependency and rely on documentation
to let users know that they need one or the other.


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

On Tuesday 24 November 2009 06:43:20 am Robert K. wrote:

Looks fine to me. But I do wonder how you generate the symbol names
for autoload files? Basically autoload needs a symbol name and a file
name. While the file names can be extracted from a directory how do
you find the symbol name?

More or less the same way Rails does, which is why I support these
various
inflection libraries. Basically, I take the file name and munge it so it
looks
like a constant name.

Maybe users should be able to customize
that algorithm in order to be able to autoload class “FooBar” from
file “foobar.rb” or “foo_bar.rb”.

Right now, it’s specified to be foo_bar.rb. It uses
String#to_const_string
from extlib, or String#camelize from ActiveSupport. If neither of these
are
loaded, it tries to load extlib, then activesupport/inflector.

Maybe users should be able to customize it. The idea is, of course,
convention
over configuration. If there’s only a single exception (FooBar, for
example),
you could always manually autoload that one file.

I would at least add a description
how you generate the symbol name from the file name.

Neither of these are bad ideas.

If you can think of a way to customize the behavior without
overcomplicating
things, go for it. I’m not motivated, so patches welcome.

Btw, one disadvantage of using a directory glob is that it is far more
expensive than the standard autoload because the standard autoload
does not need any file system IO before any file is loaded. Using
directory globbing on the other hand requires to at least read the
directory which may slow down startup of a script considerably.

Except that standard autoload is more work for me, and nearly defeats
the
point. Trading requires for autoloads directly makes things harder to
debug
without making them easier to write – it only optimizes start time.

One possibility would be to write a script which attempts to
automatically
generate these autoload statements, but store them statically in a
single
file. The main reason I don’t like that is, you’ve now added a “compile”
step
to a script. It might work as an option, maybe a “development” vs
“production”
mode.

Another possibility is to override const_missing, but that gets complex
fast,
as Rails shows.

Also, keep in mind that the directory IO is shallow. That is, if you
tell it
to autoload foo, it won’t touch anything in foo/bar. If you create a
file
bar.rb which requires autoload, it will look at foo/bar, but only once
Bar is
autoloaded.

Thanks for the feedback!

On 11/24/2009 07:06 PM, David M. wrote:

On Tuesday 24 November 2009 06:43:20 am Robert K. wrote:

Btw, one disadvantage of using a directory glob is that it is far more
expensive than the standard autoload because the standard autoload
does not need any file system IO before any file is loaded. Using
directory globbing on the other hand requires to at least read the
directory which may slow down startup of a script considerably.

Except that standard autoload is more work for me, and nearly defeats the
point. Trading requires for autoloads directly makes things harder to debug
without making them easier to write – it only optimizes start time.

Yeah, absolutely. If your major goal is to simplify script writing this
is definitive a good option. I just wanted to point out that the
convenience comes at a price. :slight_smile:

One possibility would be to write a script which attempts to automatically
generate these autoload statements, but store them statically in a single
file. The main reason I don’t like that is, you’ve now added a “compile” step
to a script. It might work as an option, maybe a “development” vs “production”
mode.

Yeah, ugly.

Another possibility is to override const_missing, but that gets complex fast,
as Rails shows.

Also, keep in mind that the directory IO is shallow. That is, if you tell it
to autoload foo, it won’t touch anything in foo/bar. If you create a file
bar.rb which requires autoload, it will look at foo/bar, but only once Bar is
autoloaded.

Thanks for the feedback!

You’re welcome! Thanks for taking the time to digest it.

Kind regards

robert

On Tuesday 24 November 2009 04:21:03 pm Robert K. wrote:

debug without making them easier to write – it only optimizes start
time.

Yeah, absolutely. If your major goal is to simplify script writing this
is definitive a good option. I just wanted to point out that the
convenience comes at a price. :slight_smile:

Well, I want a sane balance. I want to optimize start time to where an
app
starts in under a second, versus thirty seconds – and I think I’ve done
that
without much additional complexity.

In other words, I think it’s the best of both worlds.

If I only wanted to simplify script writing, Ramaze has a much simpler
solution – they’ve defined Kernel#acquire, which requires every .rb
file in a
given directory tree. That’s easier to write and easier to use, but as
an app
gets bigger, it would get slower.

I know about some work on merb, it collects depenedencies, then tries to
load them in diffirent order, and sees which one ends properly, AFAIK
there’s no way to define alternative dependencies

On 25.11.2009 03:36, David M. wrote:

debug without making them easier to write – it only optimizes start
time.
Yeah, absolutely. If your major goal is to simplify script writing this
is definitive a good option. I just wanted to point out that the
convenience comes at a price. :slight_smile:

Well, I want a sane balance.

Fair enough.

I want to optimize start time to where an app
starts in under a second, versus thirty seconds – and I think I’ve done that
without much additional complexity.

Well, that sounds like a successful optimization operation. :slight_smile:

In other words, I think it’s the best of both worlds.

If I only wanted to simplify script writing, Ramaze has a much simpler
solution – they’ve defined Kernel#acquire, which requires every .rb file in a
given directory tree. That’s easier to write and easier to use, but as an app
gets bigger, it would get slower.

Good pointer! Thanks for sharing.

Cheers

robert