Don't like reading? Watch the video here.
If you have Ruby installed on your computer, we know that you can execute .rb
files with the ruby <file name>.rb
command. This is not what we are talking about in this article.
This article is about executing ruby programs without typing ruby
, ./
, or an .rb
extension and being able to execute the command from anywhere in your file system.
Just like when you type gem
, rails
, or irb
, and your console immediately recognizes and runs a program, we want to do this with our own custom-built Ruby file.
Writing the program
Create a new directory anywhere. Name it favorite_color
. This new Ruby program is going to do one thing, tell us our favorite color.
Make two sub-directories inside favorite_color
. Name them lib
, and bin
. The lib directory will house the logic of the program. The bin directory will house the executable file that requires and calls the program in lib.
By the way, 'lib' stands for 'library', and 'bin' stands for 'binaries' (executable files). You could also name the bin folder 'exe' for 'executables. Housing your program source code in lib
and your executable in bin
or exe
is standard for Ruby gem packages.
Name the lib file favorite_color.rb
, and name the bin file fav-color.rb
. (We will eventually remove the .rb
extension.)
~ mkdir -p favorite_color/{lib,bin} && touch favorite_color/lib/favorite_color.rb favorite_color/bin/fav-color.rb
Your file tree should look like this:
favorite_color
├── bin
│ └── fav-color.rb
└── lib
└── favorite_color.rb
2 directories, 2 files
Now, add some logic to favorite_color.rb
. Here's what my class will look like. Write this however you want.
1 class FavoriteColor
2 def initialize color
3 @color = color
4 end
5
6 def declaration
7 "Your favorite color is #{@color}"
8 end
9
10 def declare
11 puts declaration
12 end
13 end
The executable file inside the bin
directory is responsible for loading the FavoriteColor class, initializing it, and calling it.
1 require_relative "../lib/favorite_color.rb"
2
3 favorite_color = FavoriteColor.new("teal") #insert your real favorite color.
4
5 favorite_color.declare
At this point, if you cd
into bin
you can execute the fav-color.rb
file like you normally would and it should print the output to your console.
ruby fav-color.rb
Your favorite color is teal
At this point, we could implement functionality in fav-color.rb
to read an argument passed in which sets the color of the class, but for now we only want to focus on making this file a true executable.
Adding the shebang
A shebang refers to the characters #!
. It's the prefix used when referencing the path to the interpreter that the shell should use to execute a script from the terminal. For instance, if you look at some of the executables in your /bin
directories that are written in shell scripts, you will see #!/bin/sh
at the top, or something similar. For Ruby scripts, you should reference /usr/bin/env
. Why is that? Because the env
command here is going to search for the first ruby
interpreter in your PATH
. The full line will look like this.
#!/usr/bin/env ruby
You might be able to just add #! ruby
or #!/usr/bin/ruby
, but the safest way is to do the full reference so that the executable will work on the maximum amount of machines.
At this point, your fav-color.rb
file should look something like this.
1 #!/usr/bin/env ruby
2
3 require_relative "../lib/favorite_color.rb"
4
5 favorite_color = FavoriteColor.new("red")
6
7 favorite_color.declare
Now, go ahead and try to execute the file. (Hint: at this point, with the shebang line, it is a true executable). You can still use the ruby
command, but in order to take advantage of the shebang you need to type ./<file-name>
. Did it work?
Most likely not. You probably don't have permission to execute the file. Each file on your machine has permissions set for reading ('r'), writing ('w'), and executing ('x'). When you first create a file, it defaults to allow you as the creator to read and write to it, and others to read it. In order to see those permissions, you need to use the shell commands ls -l
, the -l
flag standing for long format
. If you use ZSH, you can simply type the shortcut to this which is ll
. You should see something like this.
total 8
-rw-r--r-- 1 jvon1904 staff 132B Oct 30 20:47 fav-color
The total 8
refers to the total size of the directory in kilobytes.
On the second line, first column, you see -rw-r--r--
.
Although cryptic at first, this is a very simple designation for the file permissions.
The first character is either -
meaning it's a file. It could also be d
for directory.
The next three characters are permissions for the owner, which in this case are read
and write
.
The fourth character is the slot for execute
, x
. If the owner could execute the file, it would be -rwx-r--r--
.
The 5th-7th characters are for the group, which on my computer is called 'staff', and the 8th-10th characters are for others.
Changing the permissions for the file
In order to change the permissions, you need to use the chmod
command.
The most straightforward way to add user permissions is to type chmod
followed by a letter representing who is receiving the permission (u
, the user/owner, g
, the group, o
others, or a
all) followed by a +
or -
(adding/removing permissions) followed by the permission (r
, w
, or x
) and finally the file name.
For us it would look like this.
chmod u+x fav-color
ls -l
total 8
-rwxr--r-- 1 jvon1904 staff 132 Oct 30 21:00 fav-color
There happens to be another fantastic way to set all permissions for all people with only three numbers! For instance, if you want all people to have all permissions, you would type chmod 777 <file-name>
.
If you type 000
you will remove all permissions completely. Can you figure out why?
The three numbers represent the three entities being permitted (u, g, and o).
0 -> no permissions
1 -> execute permission
2 -> write permission
4 -> read permission
Then add up those numbers for any combination of the three. So a 7 means all three permissions because 7 = 1 + 2 + 4. Cool right?!
In our case, you could type chmod 744 fav-color.rb
and nothing should change.
Now that we've changed the permissions, try executing the file like ./fav-color.rb
and it should work!
Adding the executable to your path
At this point, we should go ahead and take off the .rb
extension because it's not needed now that we've added our shebang directive and turned the file into an executable.
mv fav-color.rb fav-color
The problem now is that you must reference the entire path of the file in order to execute it.
If you are inside the directory that contains fav-color
you must type ./
before hand.
If you are inside the favorite_color
root directory, you must execute it as bin/fav-color
. This is not ideal. We want to be able to type fav-color
from anywhere.
There are two ways to accomplish this.
Exporting the full path to the executable to your
$PATH
variable, orAdding a link to the executable to one of your
/bin
directories already loaded into the$PATH
.
If you are familiar with adding to your PATH, feel free to use the first option (adding export PATH=$PATH:path/to/favorite_color/bin
to .zshrc
, .zprofile
or .bash_profile
, etc.)
The recommended option in this case is to make the executable a binary in one of your bin
directories.
You've probably noticed that when you venture underneath your HOME ~ directory, there are more than one 'bin' folder.
In order to not confound system critical binaries, you should place a custom binary in /usr/local/bin
. We can do this by linking the file to that directory.
sudo ln -s ~/favorite_colors/bin/fav-color /usr/local/bin
When using the ln
(link) command, make sure to reference both the executable and the bin directory as abosolute paths.
You can cd
into /usr/local/bin to make sure it's there.
I have a line like this.
lrwxr-xr-x 1 root wheel 44B Oct 30 22:26 fav-color -> /Users/jvon1904/favorite_color/bin/fav-color
It appears that linking the file to /usr/local/bin automatically allows everyone to execute it.
Give it a shot. Execute the file from anywhere in your file system simply as fav-color
.
Top comments (3)
This is not a exectuable bro!
Executable means to execute it without installing ruby
ruby is the presquite here
That's good to hear. Thanks @miguelargentina!
Thanks! Great explanation of every step, really useful!