I saw this line of code somewhere and i felt kind of confuse about it and intimidate. That's why, i'll try to explain what i've found so far (if there is any errors, feel free to point them out).
This alien thing $:
is a shortcut referencing the $LOAD_PATH
. What is the $LOAD_PATH
?
The $LOAD_PATH
is a global variable as you can tell from $
at the beginning. A global variable is a variable which
is accessible from everywhere in a given context. For example take a look at the function below :
$global = 1
def sum(a, b)
$global += a + b #Same as $global = $global + a + b
end
p increment(2,3) # 6
Here, the context is the file you're in. The variable $global
is callable from anywhere in the code because of the $
.
Reciprocally, a global variable like $LOAD_PATH
is accessible from anywhere in your command line environnement and
that can be helpful to shorten some actions that can be laborious is you're working on a big project.This why we're using the $LOAD_PATH
here.
The $LOAD_PATH
variable contains an array of path which mostly point to lib/
sub-directories :
>> $LOAD_PATH
=> ["/home/Mansa/.rbenv/rbenv.d/exec/gem-rehash",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/did_you_mean-1.3.0/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/coderay-1.1.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/method_source-0.9.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-0.12.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/yard-0.9.19/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-doc-1.0.0/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-rails-0.3.9/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0/x86_64-linux",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0/x86_64-linux",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-linux"]
>> $:
=> ["/home/Mansa/.rbenv/rbenv.d/exec/gem-rehash",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/did_you_mean-1.3.0/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/coderay-1.1.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/method_source-0.9.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-0.12.2/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/yard-0.9.19/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-doc-1.0.0/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/pry-rails-0.3.9/lib",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby/2.6.0/x86_64-linux",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/site_ruby",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby/2.6.0/x86_64-linux",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/vendor_ruby",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/2.6.0",
"/home/Mansa/.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-linux"]
>> $: == $LOAD_PATH
=> true
We can see that the $:
notation is obviously a shortened version of $LOAD_PATH
Now we see that things are starting to fall into place but still, there is quite a bit cover to get the full picture.
We saw earlier that the $LOAD_PATH
was an array containing several path. It means that $:.unshift
is calling
to a Array#unshift
(which is the Ruby notation refering to an instance method from a Ruby classes) method on the $:
array :
# $:.unshift ... >> $LOAD_PATH.unshift >> Array#unshift
The Array#unshift
method is adding a elements pass in argument to the beginning of an array :
>> [1,2,3].unshift(0)
=> [0,1,2,3]
Read the Official Ruby Doc for more info.
The File#expand_path
method is used to convert a relative path to an absolute path. Relative path are relative, which
means that there defined in the context they we're in.
$ pwd #show the current directory
~/code/Rails
$ ls #show all the public access file in a directory
my_app my_app2
$ cd myapp/ #change the directory
With the cd
command we've used the relative path to the myapp/
directory instead of absolute path which is
~/code/Rails/my_app
What the File#expand_path
method allow us to reconstruct the path from the root directory. The first argument specify
the relative path to a file or directory. The second argument set the starting point from where we want to start reconstructing
the path.
>> __FILE__
=> my_app/Gemfile
>> File.expand_path("../my_app2/Gemfile", __FILE__)
=> ~/code/Rails/my_app2/Gemfile
Here the second argument is set to __FILE__
which is a variable returning the current file or directory we're in. You can
replace __FILE__
by any file or directory you want.
Not so complicated huh ? If you want a sharp explaination about how the File#expand_path
method work, i suggest you take
a look at the first awswer of this Stackoverflow post
Now with all pieces together we can start reconstructing the puzzle.
As we know now, $:.unshift
represents an array method call. We can deduce from that File.expand_path(path, __FILE__)
is the argument we're passin in(Note: In Ruby, parenthesis are optional if there is only one argument).
It means that through the $:.unshift
method call we've plan to add File.expand_path(path, __FILE__)
to the
$:
array.
By doing so, we're adding the path generate by File.expand_path(path, __FILE__)
in the $LOAD_PATH
array which allows
our command line environnment to have access to the specified path from anywhere. And why it is that helpful ? Because it allow
us to call require "directory"
instead of require "../../../path/to/directory
to require a specified directory in
our Ruby project.
Viewing like this it may not be seem that helpful, but in real life substantial projects, this can time/energy saver. Because
things like this require "../../../../../directory
aren't particulary fun to do in my opinion :). Moreover, when you have a tons of files/directories to require,, it can be tremendously laborious.
That's all :)
Let's review what we've seen so far :
a - We saw that the $:
notation was a shorcut for $LOAD_PATH
and that $LOAD_PATH
is global variable containing
an array of path.
b - We saw that $:.unshift
was an Array
method which serve to add elements to the beginning of an array.
c - We saw that File.expand_path(path, __FILE__)
serve to reconstruct an absolute path from a relative path.
d - We saw that $:.unshift File.expand_path(path, __FILE__)
serve to add an absolute path generate by with
File.expand_path(path, __FILE__)
to the beginning of the $:
array, which allow us to require file and directories
without specifing the absolute path for it.
I hope that you get a clearer understanding now or a least that you're not as confused as the first time you saw this code :)
Peace ☥