How a Ruby program is put together

The layout

A Ruby program of more than one file follows one convention everywhere: the code lives in lib/, the commands in bin/. The command is a small file that loads the library and calls it; the library knows nothing about the command.

hello ├── bin │ └── hello.rb └── lib └── greeter.rb

lib/greeter.rb

class Greeter def initialize(name) @name = name end def greeting "Hello, #{@name}" end end

bin/hello.rb

#!/usr/bin/env ruby require_relative "../lib/greeter" puts Greeter.new("Ada").greeting

ruby bin/hello.rb

Hello, Ada

require and require_relative

require "json" asks Ruby for a library by name: it searches the load path, then the gems. require_relative "../lib/greeter" asks for a file relative to the file that writes the line, so the command works from any folder.

The relative form is what a command uses for its own code; the plain form is for gems and the standard library. Mixing them is the usual reason a script works from the project folder and fails from anywhere else.

The load path

-Ilib adds a folder to $LOAD_PATH, which is the list of folders a plain require searches. That makes the library requireable by name, the way a gem is:

ruby -Ilib -e 'require "greeter"; puts Greeter.new("Ada").greeting'

Hello, Ada

The list has eight entries in a bare Ruby: the standard library folders and the gem folders. -I puts yours at the front, so a name in the project wins over a gem with the same name.

ruby -e 'puts $LOAD_PATH.length'

8

Run only as a program

A file that both defines methods and runs something should run the code only when it is the program, not when it is required by a test or by another file. The test compares __FILE__ with $PROGRAM_NAME:

def run puts "run as a program" end run if __FILE__ == $PROGRAM_NAME

ruby lib/cli.rb

run as a program

ruby -r ./lib/cli -e 'puts "required"'

required

The second command requires the file and prints only its own line: the guard was false, so run stayed a method. Without the guard, requiring the file would print the line and then the caller would carry on, which in a test suite means noise at the top of the run.

What to watch for

A command file starts with a shebang and chmod +x, or the reader runs it through ruby. Both are fine; pick one and say it in the README.

The guard uses $PROGRAM_NAME, which is the same as $0. Under ruby -e it is -e, so a library required from a one-liner never runs its own code by accident.

Next: Variables

Article author: Arthur Isaev