Rack::Unreloader

Rack::Unreloader is a rack library that reloads application files when it
detects changes, unloading constants defined in those files before
reloading. Like other rack libraries for reloading, this can make
application development much faster, as you don't need to restart the
whole application when you change a single file. Unlike most other rack
libraries for reloading, this unloads constants before requiring files,
avoiding issues when loading a file is not idempotent.

The block you pass to Rack::Unreloader.new should return the rack
application to use. If you make any changes to app.rb,
Rack::Unreloader will remove any constants defined by
requiring app.rb, and rerequire the file.

Note that this causes problems if app.rb loads any new
libraries that define constants, as it will unload those constants first.
This is why the example code requires the roda library
normally before requiring app.rb using
Rack::Unreloader.

However, if app.rb requires more than a single file, it is
more practical to tell Rack::Unreloader to only unload
specific subclasses:

Only Reload in Development Mode

In general, you are only going to want to reload code in development mode.
To simplify things, you can use rack-unreloader both in development and
production, and just not have it reload in production by setting
:reload to false if not in development:

By running the App instead of Unreloader in production mode, there is no
performance penalty. The advantage of this approach is you can use
Unreloader.require to require files regardless of whether you are using
development or production mode.

Modules

This reloader also handles modules. Since modules do not have
superclasses, if you are using the :subclasses option to
specify specific subclasses, you need to specify the module name if you
want to reload it:

Dependencies

To correctly handle modules and superclasses, if a change is made to a
module or superclass, you generally want to reload all classes that include
the module or subclass the superclass, so they they pick up the change to
the module or superclass.

If lib/module_file.rb is changed, rack-unreloader will reload
models/mod1.rb and models/mod2.rb after reloading lib/module_file.rb.

You can provide directories when requiring dependencies. For example:

Unreload.record_dependency('helpers',%w'app.rb')

will make it so the addition of any ruby files to the helpers directory
will trigger a reload of app.rb, and future changes to any of
those files will also trigger of reload of app.rb.
Additionally, deleting any ruby files in the helpers directory will also
trigger a reload of app.rb.

You can also use a directory as the second argument:

Unreload.record_dependency('mod.rb','models')

With this, any change to mod.rb will trigger a reload of all
ruby files in the models directory, even if such files are added later.

When using record_dependencies with a directory, you should
also call require with that directory, as opposed to
specifically requiring individual files inside the directory.

Classes Split Into Multiple Files

Rack::Unreloader handles classes split into multiple files, where there is
a main file for the class that requires the other files that define the
class. Assuming the main class file is app.rb, and other
files that make up the class are in helpers:

If app.rb is changed or any of the ruby files in
helpers is changed, it will reload app.rb and all
of the files in helpers. This makes it so if you remove a
method from one of the files in helpers, it will reload the
entire class so that the method is no longer defined. Likewise, if you
delete one of the files in helpers, it will reload the class so that the
methods that were defined in that file will no longer be defined on the
class.

Requiring

Rack::Unreloader#require is a little different than require in that it
takes a file glob, not a normal require path. For that reason, you must
specify the extension when requiring the file, and it will only look in the
current directory by default:

Unreloader.require'app.rb'

If you want to require a file in a different directory, you need to provide
the full path:

Unreloader.require'/path/to/app.rb'

You can use the usual file globbing to load multiple files:

Unreloader.require'models/*.rb'

If you want to load all files in a given directory you should just give the
directory path:

Unreloader.require'models'

The advantage for doing this is that new files added to the directory will
be picked up automatically, and files deleted from the directory will be
removed automatically. This applies to files in subdirectories of that
directory as well.

Speeding Things Up

By default, Rack::Unreloader uses ObjectSpace
before and after requiring each file that it monitors, to see which classes
and modules were defined by the require. This is slow for large numbers of
files. In general use it isn't an issue as generally only a single
file will be changed at a time, but it can significantly slow down startup
when all files are being loaded at the same time.

If you want to speed things up, you can provide a block to
Rack::Unreloader#require, which will take the file name, and should return
the name of the constants or array of constants to unload. If you do this,
Rack::Unreloader will no longer need to use
ObjectSpace, which substantially speeds up startup. For
example, if all of your models just use a capitalized version of the
filename:

In some cases, you may want to pass a block to require, but inside the
block decide that instead of specifying the constants, ObjectSpace should
be used to automatically determine the constants loaded. You can specify
this by having the block return the :ObjectSpace symbol.

Usage Outside Rack

While Rack::Unreloader is usually in the development of rack
applications, it doesn't depend on rack. You can just instantiate an
instance of Unreloader and use it to handle reloading in any ruby
application, just by using the require and
record_dependency to set up the metadata, and calling
reload! manually to reload the application.

History

Rack::Unreloader was derived from Padrino's reloader. The
Padrino-specific parts were removed, and it now requires the user manually
specify which files to monitor. It has additional features, improvements,
and bug fixes.

Caveats

Unloading constants and reloading files has a ton of corner cases that this
will not handle correctly. If it isn't doing what you expect, add a
logger:

Unloading constants causes issues whenever references to the constant are
cached anywhere instead of looking up the constant by name. This is fairly
common, and using this library can cause a memory leak or unexpected
behavior in such a case.

Approaches that load a fresh environment for every request (or a fresh
environment anytime there are any changes) are going to be more robust than
this approach, but probably slower. Be aware that you are trading
robustness for speed when using this library.

Implementation Support

Rack::Unreloader works correctly on Ruby 1.8.7+ and Rubinius. It only
works on JRuby if you use a proc to specify the constants to unload.