Skip to content

Ruby Sourcefiles and Libraries

datanorris edited this page Apr 3, 2016 · 6 revisions

Ruby applications can be comprised of multiple Ruby sourcefiles, and they can access objects made available by Ruby libraries.

Ruby has a very simple mechanism to support this - Ruby code can use APIs to load and execute other Ruby files. These other files then may perform tasks, such as creating classes, modules, methods and constants. Once the loaded file completes executing, the original Ruby code resumes and it can use the objects that were created.

In addition, there are API methods such as require which will load (and execute) a file, but then if the file is require'd again it will not reload the file. This is so multiple sourcefiles can "require" that a certain file be loaded, and the effect will be that the file is only loaded once. It is typical for Ruby sourcefiles to begin with require method calls, effectively declaring what other files need to be loaded as a prerequisite.

There are 2 types of file that can be loaded in Ruby:

  • a Ruby sourcefile, whose name must end in ".rb"
  • a Ruby extension library, whose name must end with ".dll" on Windows platforms or ".so" on everything else. These components are typically written in C, conform to certain requirements for Ruby extension libraries, and when executed perform tasks (such as creating objects in the Ruby environment) using the Ruby C API - creating extension libraries is beyond the scope of this document.

A basic multi-file Ruby application therefore consists of a designated initial sourcefile, which is to be executed directly and is called the "main" sourcefile, and some other Ruby sourcefiles which are loaded in the course of executing the initial file (usually via require or related APIs).

A basic Ruby library consists of some Ruby sourcefiles or extension libraries that are intended to be require'd in order to enable their features, and perhaps some other sourcefiles that are loaded in the course of the library files' execution. Ruby has a "standard library" with this structure, which is pre-installed with Ruby.

Load file name resolution

Ruby resolves load file names very similarly to the way that command-line commands are resolved in unix or Windows environments.

There exists a Ruby "load path" which is a list of filesystem directories to be potentially searched when loading a file. The load path is defined in various ways when the Ruby environment is started up (e.g. via hard-coded paths, command-line switches and environment variables). There exist no core APIs to modify a load path during Ruby execution, although a library extension could provide such features.

Load file names (and, for that matter, load path names) may be absolute or relative filesystem paths as supported by the underlying operating system, including UNC paths and NTFS streams in Windows environments. Ruby also supports expanding "~" or "~name", if it's the first path element, into the current user's or named user's home directory.

The "standard" resolution procedure for load file names is as follows:

  • If the file name is an absolute path (or home directory relative path), it resolves directly
  • Otherwise, if it is explicitly relative to the current working directory (i.e. its first path element is "." or ".."), it is resolved against the current working directory
  • Otherwise, resolution is attempted against each load path in turn until an openable file is found.

If load path names are relative (even explicitly), they are resolved against the current working directory.

The require APIs permit you to specify load file names with no file extension, and they will search for matching files with ".rb" (by preference) or ".dll"/".so" extensions.

There exist the usual complications on Windows - relative paths specifying a drive letter (e.g. D:file.rb) are relative the current working directory on that drive or potentially load paths on that drive, and relative paths beginning with a "" or "/" are relative to the current working drive or a load path's drive or UNC share.

On Windows environments, paths may use "/" interchangeably with "", and load file names ending in ".so" will also search for ".dll" files. Therefore, it is recommended to use "/" and ".so" rather than "" and ".dll" for portability with non-Windows platforms.

There is a require_relative API method which is a wrapper around normal require functionality - it resolves a relative load file name against the location of the currently executing Ruby sourcefile before requiring it.

Executing Ruby sourcefiles

When a Ruby sourcefile is loaded (other than the main sourcefile) its execution context is similar to that of the main sourcefile, except that it has its own local variable context. A sourcefile can also be loaded with a "wrap=true" option which modifies its self and class reference stack. See the Execution Context section for details.

When a load API method is called to load a file, it will wait until the file completes executing before it returns.

Require mechanism

Ruby maintains an Array of files that have been require'd, which can be accessed via $LOADED_FEATURES. With a couple of Ruby-internal exceptions, they are absolute paths to the loaded files. It also maintains an internal list of files currently in the process of loading.

When a file is require'd, Ruby will determine whether the file is loaded, loading or not previously require'd with the following steps, stopping on the first successful match:

  • Search the loaded and loading lists for the load file name as-is, or with file extensions added if the load file name doesn't have on

  • Locate the file in the filesystem with the resolution procedure above (including adding file extensions), producing an absolute path to the file

  • Take certain steps to canonicalize the path:

  • On Windows, convert "" to "/"

  • Remove excess path separators, and "." and ".." path elements

  • On Windows, convert the file name to it's proper long file name and remove any reference to the ":$DATA" stream attribute

  • Search the loaded and loading lists again for the absolute path

  • Locking

Ruby C API extensions

  • require RB
  • require SO

API

  • to_path()

Clone this wiki locally