---
title: Following the Path
teaser: A journey into requiring files via $PATH and $LOAD_PATH.
tags: web,ruby,unix
author: Joël Quenneville
published_on: 2017-04-10
---

```ruby
require "user"
```

Where is the `user.rb` file located? Perhaps in the current directory? That's a
trick question. There isn't enough information to determine that from that
single line.

The answer is more complex, flexible, and involves some UNIX history.

## `$LOAD_PATH`

`$LOAD_PATH` is a global variable in Ruby that points to an array of path
strings. The following is the (truncated) result of viewing `$LOAD_PATH` in pry:

```ruby
[1] pry(main)> $LOAD_PATH
=>
["/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/did_you_mean-1.0.0/lib",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/slop-3.6.0/lib",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/method_source-0.8.2/lib",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/pry-0.10.4/lib",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/coderay-1.1.1/lib",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/pry-byebug-3.4.0/lib",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/byebug-9.0.6/lib",
...skipping...
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/vendor_ruby/2.3.0",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/vendor_ruby/2.3.0/x86_64-darwin14",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/vendor_ruby",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/2.3.0",
 "/Users/joelquenneville/.rbenv/versions/2.3.1/lib/ruby/2.3.0/x86_64-darwin14"]
```

The paths are mostly going to various gem's `lib/` directories or Ruby
installations. When executing `require "user`, Ruby looks for a file named
`user.rb` in all of these locations.

What if there's a `user.rb` in several of the locations? Ruby will load the
first one it finds.

Gems will automatically add themselves to your load path.

## Custom load path

That's all great but what about adding your own paths? This can be accomplished
by mutating the `$LOAD_PATH`. Using `Array#unshift` will prepend your path:

```ruby
$LOAD_PATH.unshift File.expand_path(".", "lib")
```

Now `require "user"` will first look for `./lib/user.rb`.

## Complex paths

The same logic applies to more complex requires:

```ruby
require "/api/client"
```

would look for `/api/client.rb` in all of the paths, starting with
`./lib/api/client.rb`

## UNIX

UNIX systems take a very similar approach with the environment variable `$PATH`.
A (truncated) path might look like:

```sh
$ echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/texbin:/usr/local/sbin
```

`$PATH` is a list of paths separated by colons. When you type a command into the
shell, it looks at all these locations for an executable matching the name you
typed and will execute the first one it finds.

This is why some tool installation guides ask you to modify `$PATH` in your
shell config.

You can see which path your shell is using for a given command with [`which`]

```sh
$ which ls
/bin/ls
```

Sometimes you will have multiple versions of a command installed. For example
`psql` from [Homebrew] and `psql` from [Postgres.app]. The `which` command is
great for finding out which one is being used. Use this info to tweak your
`$PATH` to ensure the right one loads. You can also use the `-a` flag on
`which` to show all installed executables:

```sh
% which -a psql
/Applications/Postgres.app/Contents/Versions/latest/bin/psql
/usr/local/bin/psql
```

## Wandering off the path

Ruby has another way of requiring code:

```ruby
require_relative "./lib/user"
```

Now where is `user.rb` located? This doesn't use `$LOAD_PATH`. Instead, it looks
for `./lib/user.rb` _relative to the location of the current file_.

Both `require` and `require_relative` take a path to a Ruby file without the
`.rb` extension.

A few UNIX shell commands are hard-coded into the shell and don't use the
`$PATH` lookup system. For example, where is the `which` executable?

```sh
$ which which
which: shell built-in command
```

Now you know a bit more about how Ruby locates files, and explored a bit of [UNIX]
history.

[`which`]: https://www.freebsd.org/cgi/man.cgi?which
[Postgres.app]: https://postgresapp.com/
[Homebrew]: https://brew.sh/
[UNIX]: https://thoughtbot.com/blog/tags/unix
