Have you ever wonder why you never needed to require any files or modules in the Rails work we've done so far? This is one of the nicesties of using Ruby on Rails framework: the auto-loading feature.
Rails will magically require and load the necessary files into the runtime when needed preventing the need for explicit require statements. Unfortunately, in pure Ruby no such concept exists, and developers must either specifically
load files into the Ruby runtime as the application executes.
So are we chained to Ruby's bhavacakra of runtime requirements and loading? Not necessarily, we can write a quick version of our own autoloading that can give us 80% of the results with minimal effort. To do so we will break up the responsibility of 1) loading our gems via Bundler and 2) loading application files. Let's tackle it below:
app.rb file we manually import the bundler gem and call the
Bundle.require ❶ method. Once called
Bundler will read through our
Gemfile and load the listed gems into our runtime environment without us having to require them.
Next, we set a Sinatra configuration setting for the app using the
set method. The set method creates an application wide attribute using the a setting name and value as arguments. These values are retrievable from the root class (e.g. App) or settings object for non-class based Sinatra applications. In our case we set the value root ❷ to as a relative file path to our project's root directory.
Once we have the root value set, we manually require a new file called config/autoload.rb ❸. This file will contain logic to load our application specific code into the runtime environment handling the part 2) of our autoloading scheme. Let's explore the file below:
So what is going on here? At the top of the file we are manually requiring a few Sinatra submodules ❶. We've seen the base module in our
app.rb file, and will soon be adding development reloading and route namespacing using the reloader and namespace modules respectively. Requiring these submodules here allows us to clean up the
app.rb file significantly and centralize our loading scheme.
Next we set up a list of
directories to load files from ❷ (our app being simple at the moment we only have the
config directory). The code then iterates through each directory and sets up a relative path to all the ruby files contained within ❸. Using this relative location, we then expand the file path to the project's root directory ❹ using the
App.root configuration we set up previously¹. Using this filepath, we then use the directory globbing function
 method is an alias for glob) to expand the wildcard path (.rb ) and grab all files that match this pattern in that directory. In our case the list of files after globbing with be
config/autoload.rb. Once we have an array of Ruby files in the directory we require them one by one ❼ unless the file name is
autoload.rb ❻ file which is already been required and therefore should be skipped.
It seems quite complex but it is really just a clever way to enable our laziness. As we add more application code we will return to this file to add new directories causing all the child ruby files to be automagically loaded in. That is surprisingly it for adding basic autoloading to our Sinatra app.
¹ Why are we able to access the App constant in our autoload file? The point is a bit nuanced but important to understand. Recall that our autoloading file is required in the
app.rb file. Therefore, the
config/autoload.rb file is executing in the context of the require statement inside the definition of App. Without going too far down the rabbit whole of Ruby constant definitions, the important point to understand here is that the order does matter. We need to require our autoload file after (in our case inside) the initial declaration of our App constant in order for this autoloading scheme to function.