[ANN] 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.

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

···

2009/11/24 David Masover <ninja@slaphack.com>:

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.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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.

···

On Tue, Nov 24, 2009 at 12:34 AM, David Masover <ninja@slaphack.com> 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.

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

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 Tuesday 24 November 2009 06:43:20 am Robert Klemme wrote:

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

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 11/24/2009 07:06 PM, David Masover wrote:

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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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.

···

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

On 11/24/2009 07:06 PM, David Masover wrote:
> On Tuesday 24 November 2009 06:43:20 am Robert Klemme 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:

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:

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

···

On 25.11.2009 03:36, David Masover wrote:

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

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

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

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/