Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/njonsson/autoloaded
Eliminates the drudgery of handcrafting an `autoload` statement for each Ruby source code file in your project
https://github.com/njonsson/autoloaded
api fluid metaprogramming ruby rubygem
Last synced: 13 days ago
JSON representation
Eliminates the drudgery of handcrafting an `autoload` statement for each Ruby source code file in your project
- Host: GitHub
- URL: https://github.com/njonsson/autoloaded
- Owner: njonsson
- License: other
- Created: 2014-10-24T14:40:31.000Z (about 10 years ago)
- Default Branch: main
- Last Pushed: 2024-04-06T07:49:58.000Z (7 months ago)
- Last Synced: 2024-09-21T13:38:22.880Z (about 2 months ago)
- Topics: api, fluid, metaprogramming, ruby, rubygem
- Language: Ruby
- Homepage: https://njonsson.github.io/autoloaded
- Size: 158 KB
- Stars: 50
- Watchers: 3
- Forks: 3
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: History.md
- License: License.md
Awesome Lists containing this project
README
[![Autoloaded graphic]][spider-gear-image]
# Autoloaded
[![Travis CI build status] ][Travis-CI-build-status]
[![Code Climate quality report] ][Code-Climate-report]
[![Code Climate coverage report]][Code-Climate-report][![Inch CI build status] ][Inch-CI-build-status]
[![RubyGems release] ][RubyGems-release]If you like the [*Module#autoload*][Ruby-Core-Module-autoload] feature of the
Ruby Core library, you may have wished for *Autoloaded*. It eliminates the
drudgery of handcrafting an `autoload` statement for each Ruby source code file
in your project. It also avoids the limitations of rigid convention-driven
facilities such as those provided by the [ActiveSupport][ActiveSupport-Autoload]
RubyGem.*Autoloaded* assumes, but does not enforce, `CamelCase`-to-`snake_case`
correspondence between the names of constants and source files. You can combine
conventions, even putting multiple autoloaded constants in a single source file.## Installation
Install [the RubyGem][RubyGems-release].
$ gem install autoloaded
Use *Autoloaded* in your RubyGem project by making it a runtime dependency.
```ruby
# my_awesome_gem.gemspecGem::Specification.new do |spec|
# ...
spec.add_dependency 'autoloaded', '~> 2'
# ...
end
```Or you may want to make *Autoloaded* a dependency of your project by using
[Bundler][Bundler].```ruby
# Gemfilesource 'https://rubygems.org'
gem 'autoloaded', '~> 2'
```## Usage
Suppose you have the following source files.
lib/
├─ my_awesome_gem/
│ ├─ db/
│ │ ├─ MicroSoft.rb
│ │ ├─ SELF-DESTRUCT!.rb
│ │ ├─ mysql.rb
│ │ ├─ oracle.rb
│ │ └─ postgre_sql.rb
│ ├─ db.rb
│ └─ version.rb
└─ my_awesome_gem.rb### The *Autoloaded.module* or *Autoloaded.class* method
The *Autoloaded.module* and *Autoloaded.class* method calls below invoke
[*Module#autoload*][Ruby-Core-Module-autoload] for each source file in the
calling module’s corresponding directory. Note that these methods must receive a
block, even if it’s an empty block.The file paths used are abbreviated, if possible, using a directory of the Ruby
load path (`$:`). They are also rendered without their *.rb* extension.```ruby
# lib/my_awesome_gem.rb
module MyAwesomeGemAutoloaded.module { }
# The above is the equivalent of:
#
# autoload :Db, 'my_awesome_gem/db'
# autoload :Version, 'my_awesome_gem/version'end
# lib/my_awesome_gem/db.rb
module MyAwesomeGemclass DB
# The 'class' and 'module' methods are aliases -- use either one.
Autoloaded.class { }# The above is the equivalent of:
#
# autoload :MicroSoft, 'my_awesome_gem/db/MicroSoft'
# autoload :SELF_DESTRUCT_, 'my_awesome_gem/db/SELF-DESTRUCT!'
# autoload :Mysql, 'my_awesome_gem/db/mysql'
# autoload :Oracle, 'my_awesome_gem/db/oracle'
# autoload :PostgreSql, 'my_awesome_gem/db/postgre_sql'end
end
```The code above is succinct, but it’s not exactly correct. The constants
`MyAwesomeGem::DB`, `MyAwesomeGem::DB::MySQL`, and others are not set up to
autoload properly because they are misspelled (case-sensitively speaking).```ruby
MyAwesomeGem.autoload? :DB # => nil
MyAwesomeGem.const_defined? :DB # => false
MyAwesomeGem.constants.include? :DB # => falseMyAwesomeGem::DB # Raises NameError because lib/my_awesome_gem/db.rb does not
# get autoloaded!MyAwesomeGem.autoload? :Db # => 'my_awesome_gem/db' (a lie!)
MyAwesomeGem.const_defined? :Db # => true (a lie!)
MyAwesomeGem.constants.include? :Db # => true (a lie!)MyAwesomeGem::Db # Raises NameError because lib/my_awesome_gem/db.rb defines
# MyAwesomeGem::DB, not MyAwesomeGem::Db!#################################################################################
require 'my_awesome_gem/db'
MyAwesomeGem::DB.autoload? :MySQL # => nil
MyAwesomeGem::DB.const_defined? :MySQL # => false
MyAwesomeGem::DB.constants.include? :MySQL # => falseMyAwesomeGem::DB::MySQL # Raises NameError because
# lib/my_awesome_gem/db/mysql.rb does not get
# autoloaded!MyAwesomeGem::DB.autoload? :Mysql # => 'my_awesome_gem/db/mysql' (a lie!)
MyAwesomeGem::DB.const_defined? :Mysql # => true (a lie!)
MyAwesomeGem::DB.constants.include? :Mysql # => true (a lie!)MyAwesomeGem::DB::Mysql # Raises NameError because
# lib/my_awesome_gem/db/mysql.rb defines
# MyAwesomeGem::DB::MySQL, not MyAwesomeGem::DB::Mysql!
```### The `with` specification
*Autoloaded* needs hints from you concerning unpredictable spellings,
stylization, and organization of constant names and/or source file names. You can
specify `with` as:* A symbol or array of symbols representing constants to autoload
* A hash of symbols and strings representing constants and the source filename(s)
from which to autoload them
* A combination of the aboveA symbol provided to `with` signifies the name of a constant, and a string
signifies the name of a source file.Specifying `with` does not filter the source files; it maps the source files to
different constants, or tweaks the names of constants.You can specify `with` multiple times, and its effects are cumulative.
```ruby
# lib/my_awesome_gem.rb
module MyAwesomeGemAutoloaded.module do |autoloading|
autoloading.with :DB, :VERSION
# Or:
# autoloading.with :DB
# autoloading.with :VERSION
# Or:
# autoloading.with DB: 'db', VERSION: 'version'
# Or:
# autoloading.with DB: 'db'
# autoloading.with VERSION: 'version'
# Or:
# autoloading.with 'db' => :DB, 'version' => :VERSION
# Or:
# autoloading.with 'db' => :DB
# autoloading.with 'version' => :VERSION
end# The above is the equivalent of:
#
# autoload :DB, 'my_awesome_gem/db'
# autoload :VERSION, 'my_awesome_gem/version'end
# lib/my_awesome_gem/db.rb
module MyAwesomeGemclass DB
Autoloaded.class do |autoloading|
autoloading.with :MySQL, :PostgreSQL, [:Access, :SQLServer] => 'MicroSoft'
# Or:
# autoloading.with :MySQL,
# :PostgreSQL,
# Access: 'MicroSoft',
# SQLServer: 'MicroSoft'
# Or:
# autoloading.with :MySQL,
# :PostgreSQL,
# 'MicroSoft' => [:Access, :SQLServer]
# Or:
# autoloading.with :MySQL,
# :PostgreSQL,
# 'MicroSoft' => :Access,
# 'MicroSoft' => :SQLServer
# Or ...
end# The above is the equivalent of:
#
# autoload :Access, 'my_awesome_gem/db/MicroSoft'
# autoload :SQLServer, 'my_awesome_gem/db/MicroSoft'
# autoload :SELF_DESTRUCT_, 'my_awesome_gem/db/SELF-DESTRUCT!'
# autoload :MySQL, 'my_awesome_gem/db/mysql'
# autoload :Oracle, 'my_awesome_gem/db/oracle'
# autoload :PostgreSQL, 'my_awesome_gem/db/postgre_sql'end
end
```Now you’re autoloading all the constants you want to be autoloading.
```ruby
MyAwesomeGem.autoload? :DB # => 'my_awesome_gem/db'
MyAwesomeGem.const_defined? :DB # => true
MyAwesomeGem.constants.include? :DB # => trueMyAwesomeGem::DB # => MyAwesomeGem::DB
MyAwesomeGem.autoload? :Db # => nil
MyAwesomeGem.const_defined? :Db # => false
MyAwesomeGem.constants.include? :Db # => falseMyAwesomeGem::Db # Raises NameError as expected.
#################################################################################
MyAwesomeGem::DB.autoload? :MySQL # => 'my_awesome_gem/db/mysql'
MyAwesomeGem::DB.const_defined? :MySQL # => true
MyAwesomeGem::DB.constants.include? :MySQL # => trueMyAwesomeGem::DB::MySQL # => MyAwesomeGem::DB::MySQL
MyAwesomeGem::DB.autoload? :Mysql # => nil
MyAwesomeGem::DB.const_defined? :Mysql # => false
MyAwesomeGem::DB.constants.include? :Mysql # => falseMyAwesomeGem::DB::Mysql # Raises NameError as expected.
```### The `except` and `only` specifications
What about source files you **don’t** want to be autoloaded?
```ruby
MyAwesomeGem::DB::SELF_DESTRUCT_ # Loading this file does something bad, so
# let's not.
```If you really want to avoid loading *lib/my_awesome_gem/db/SELF-DESTRUCT!.rb*, so
much so that you don’t want an `autoload` statement made for it, specify
`except`.```ruby
# lib/my_awesome_gem/db.rbmodule MyAwesomeGem
class DB
Autoloaded.class do |autoloading|
autoloading.with :MySQL, :PostgreSQL, [:Access, :SQLServer] => 'MicroSoft'autoloading.except 'SELF-DESTRUCT!'
# Or:
# autoloading.except :SELF_DESTRUCT_
# Or ...
end# The above is the equivalent of:
#
# autoload :Access, 'my_awesome_gem/db/MicroSoft'
# autoload :SQLServer, 'my_awesome_gem/db/MicroSoft'
# autoload :MySQL, 'my_awesome_gem/db/mysql'
# autoload :Oracle, 'my_awesome_gem/db/oracle'
# autoload :PostgreSQL, 'my_awesome_gem/db/postgre_sql'end
end
``````ruby
MyAwesomeGem::DB.autoload? :SELF_DESTRUCT_ # => nil
MyAwesomeGem::DB.const_defined? :SELF_DESTRUCT_ # => false
MyAwesomeGem::DB.constants.include? :SELF_DESTRUCT_ # => falseMyAwesomeGem::DB::SELF_DESTRUCT_ # Raises NameError as expected.
```You can specify `except` as:
* A symbol or array of symbols representing constants to avoid autoloading
* A string or array of strings representing source filenames to avoid autoloading
* A hash of symbols and/or strings representing constants and/or source filenames
to avoid autoloading
* A combination of the aboveThe `only` specification is like `except` but it has the opposite effect, namely,
that **only** specified constants and/or source files will be autoloaded.You can specify `only` as:
* A symbol or array of symbols representing constants to autoload
* A string or array of strings representing source filenames to autoload
* A hash of symbols and/or strings representing constants and the source
filename(s) from which to autoload them
* A combination of the aboveA symbol provided to `except` or `only` signifies the name of a constant, and a
string signifies the name of a source file.You can specify `except` and `only` multiple times, and their effects are
cumulative.### The `from` specification
It’s recommended that you call *Autoloaded.module* or *Autoloaded.class* from
within the source file where your module or class is defined. This practice
allows *Autoloaded* to assume that the source files to be autoloaded are in a
directory of the same name (and in the same location) as the module’s defining
source file.There are circumstances, however, in which you cannot rely on the computed
directory for autoloading. Perhaps the directory has a different name from the
module’s defining source file. Or perhaps you are autoloading a library that you
didn’t author. In these situations you can specify `from` with the path from
which source files should be autoloaded.```ruby
# somewhere_else.rbmodule MyAwesomeGem
Autoloaded.module do |autoloading|
# The following code is not actually very useful since the installed location
# of a RubyGem varies with the operating system and user preferences. How to
# compute the path properly is outside the scope of this readme and is left
# as an exercise for the reader.
autoloading.from '/absolute/path/to/my_awesome_gem'
endend
```A path provided to `from` cannot be relative; it must start with the filesystem
root.If you specify `from` multiple times in an *Autoloaded* block, only the last one
takes effect.### The *Autoloaded.warn* method
There are two circumstances under which *Autoloaded* by default will write
warnings to stderr:* Overriding an established autoload
* Establishing an autoload for a defined constantYou can silence these warnings by passing `false` to *Autoloaded.warn*. (Passing
`true` turns warnings on if they are off.)```ruby
# lib/my_awesome_gem/db.rbmodule MyAwesomeGem
class DB
Autoloaded.warn false # Turn off Autoloaded warnings.
autoload :SQLServer, 'my_awesome_gem/db/MicroSoft'
class Oracle; end
Autoloaded.class { } # This duplicates the 'autoload' statement and class
# definition above, but no Autoloaded warnings will be
# displayed.Autoloaded.warn true # Turn on Autoloaded warnings again.
end
end
```Use the block form if you want to ensure warnings get toggled on or off for a
series of statements.```ruby
# lib/my_awesome_gem/db.rbmodule MyAwesomeGem
class DB
autoload :SQLServer, 'my_awesome_gem/db/MicroSoft'
class Oracle; end
Autoloaded.warn false do
Autoloaded.class { } # This duplicates the 'autoload' statement and class
# definition above, but no Autoloaded warnings will
# be displayed.
end# Autoloaded warnings are turned on again automatically.
end
end
```### How to debug autoloading
The *Autoloaded.module* or *Autoloaded.class* method returns an ordered list of
arguments it has passed to `autoload`.```ruby
# lib/my_awesome_gem/db.rbmodule MyAwesomeGem
class DB
results = Autoloaded.class do |autoloading|
autoloading.with :MySQL,
:PostgreSQL,
[:Access, :SQLServer] => 'MicroSoft'
autoloading.except 'SELF-DESTRUCT!'
end
STDOUT.puts results.inspect # See output below.end
end
# [[:Access, 'my_awesome_gem/db/MicroSoft' ],
# [:SQLServer, 'my_awesome_gem/db/MicroSoft' ],
# [:MySQL, 'my_awesome_gem/db/mysql' ],
# [:Oracle, 'my_awesome_gem/db/oracle' ],
# [:PostgreSQL, 'my_awesome_gem/db/postgre_sql']]
```You can also hook [*Module#autoload*][Ruby-Core-Module-autoload] and
[*Kernel#autoload*][Ruby-Core-Kernel-autoload] via monkeypatching or other means
in order to see what’s happening.### Source filenames are relative to the `from` specification
You may have noticed that source filenames in the above examples are not
absolute. They are relative to the *Autoloaded* block’s `from` specification
(which I recommend that you allow to be computed for you —
[see above](#the-from-specification)).### Recursive autoloading not supported
*Autoloaded* does not perform deep autoloading of nested namespaces and
directories. This is by design.## Contributing
1. [Fork][fork-Autoloaded] the official repository.
2. Create your feature branch: `git checkout -b my-new-feature`.
3. Commit your changes: `git commit -am 'Add some feature'`.
4. Push to the branch: `git push origin my-new-feature`.
5. [Create][compare-Autoloaded-branches] a new pull request.Development
-----------After cloning the repository, `bin/setup` to install dependencies. Then `rake` to
run the tests. You can also `bin/console` to get an interactive prompt that will
allow you to experiment.To install this gem onto your local machine, `bundle exec rake install`. To
release a new version, update the version number in *lib/autoloaded/version.rb*,
and then `bundle exec rake release`, which will create a Git tag for the version,
push Git commits and tags, and push the *.gem* file to
[RubyGems.org](RubyGems-release).## License
Released under the [MIT License][MIT-License].
[Autoloaded graphic]: https://farm5.staticflickr.com/4134/4941065976_54737fe145.jpg
[Travis CI build status]: https://app.travis-ci.com/njonsson/autoloaded.svg?branch=main
[Code Climate quality report]: https://codeclimate.com/github/njonsson/autoloaded/badges/gpa.svg
[Code Climate coverage report]: https://codeclimate.com/github/njonsson/autoloaded/badges/coverage.svg
[Inch CI build status]: https://www.inch-ci.org/github/njonsson/autoloaded.svg?branch=master
[RubyGems release]: https://badge.fury.io/rb/autoloaded.svg[spider-gear-image]: https://www.flickr.com/photos/dongkwan/4941065976 "spider gear image by Ernesto Andrade"
[Travis-CI-build-status]: https://app.travis-ci.com/github/njonsson/autoloaded "Travis CI build status for Autoloaded"
[Code-Climate-report]: https://codeclimate.com/github/njonsson/autoloaded "Code Climate report for Autoloaded"
[Inch-CI-build-status]: https://www.inch-ci.org/github/njonsson/autoloaded "Inch CI build status for Autoloaded"
[RubyGems-release]: https://rubygems.org/gems/autoloaded "RubyGems release of Autoloaded"
[Ruby-Core-Module-autoload]: https://ruby-doc.org/core/Module.html#method-i-autoload "‘Module#autoload’ method in the Ruby Core Library"
[ActiveSupport-Autoload]: https://api.rubyonrails.org/classes/ActiveSupport/Autoload.html "‘ActiveSupport::Autoload’ module in the Rails API"
[Bundler]: https://bundler.io/
[Ruby-Core-Kernel-autoload]: https://ruby-doc.org/core/Kernel.html#method-i-autoload "‘Kernel#autoload’ method in the Ruby Core Library"
[fork-Autoloaded]: https://github.com/njonsson/autoloaded/fork "Fork the official repository of Autoloaded"
[compare-Autoloaded-branches]: https://github.com/njonsson/autoloaded/compare "Compare branches of Autoloaded repositories"
[MIT-License]: https://github.com/njonsson/autoloaded/blob/master/License.md "MIT License claim for Autoloaded"