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