... with __dir__ we can restore order in the Universe
“Defining paths relative to a file name has always hurt my soul, with __dir__ we can restore order in the Universe.” - by @fxn.
This post about the method in Ruby Programming Language Kernel#__dir__
and restoring order in the Universe.
Let’s take a look at the method Kernel#__dir__
.
__dir__ => string
Returns the canonicalized absolute path of the directory of the file from which this method is called. It means symlinks in the path is resolved. If __FILE__ is nil, it returns nil. The return value equals to File.dirname(File.realpath(__FILE__)).
This method was introduced in Ruby since version 2.0.0 (NEWS for Ruby 2.0.0).
More info about development of Kernel#__dir__
here: Feature #1961.
Since Ruby 2.0.0 it is time to define relative paths with __dir__
and refactor all definitions of relative paths with __FILE__
.
Why is __dir__
better than __FILE__
for a definition of path?
Imagine there is folder project/
that contains files: Rakefile
, application.rb
.
Inside the file Rakefile
need to get the path to the file application.rb
. We can do it by using __FILE__
:
File.expand_path('../application.rb', __FILE__)
There is the definition of path to the file application.rb
by using __dir__
:
File.expand_path('application.rb', __dir__)
By using __dir__
we get rid of redundant ../
. Looks better, isn’t it?
The result of these definitions is the same, but if we need number 5
, we don’t type 3+2
or 1+4
.
__FILE__
is definitely better than File.expand_path('Rakefile', __dir__)
when inside the file Rakefile
need to get the path to the file Rakefile
(the current file).
It is important not to do and get rid of needless things in a code!
Examples of refactoring with __dir__
:
-APP_PATH = File.expand_path('../../config/application', __FILE__)
+APP_PATH = File.expand_path('../config/application', __dir__)
-$:.unshift File.expand_path("..", __FILE__)
+$:.unshift __dir__
namespace :isolated do
task adapter => "test:env:#{adapter}" do
- dir = File.dirname(__FILE__)
- Dir.glob("#{dir}/test/cases/**/*_test.rb").all? do |file|
- sh(Gem.ruby, "-w", "-I#{dir}/lib", "-I#{dir}/test", file)
+ Dir.glob("#{__dir__}/test/cases/**/*_test.rb").all? do |file|
+ sh(Gem.ruby, "-w", "-I#{__dir__}/lib", "-I#{__dir__}/test", file)
end || raise("Failures")
end
end
-Dir[File.dirname(__FILE__) + "/stubs/*.rb"].each { |file| require file }
+Dir[File.expand_path("stubs/*.rb", __dir__)].each { |file| require file }
-$:.unshift(File.dirname(__FILE__) + "/lib")
-$:.unshift(File.dirname(__FILE__) + "/fixtures/helpers")
-$:.unshift(File.dirname(__FILE__) + "/fixtures/alternate_helpers")
+$:.unshift File.expand_path("lib", __dir__)
+$:.unshift File.expand_path("fixtures/helpers", __dir__)
+$:.unshift File.expand_path("fixtures/alternate_helpers", __dir__)
def self.base_root
- File.dirname(__FILE__)
+ __dir__
end
-source_root File.expand_path("../templates", __FILE__)
+source_root File.expand_path("templates", __dir__)
When I was investigating Rails’s sources, I found one wonderful commit related to the using of __dir__
for definition of relative path.
rails$ git show 5b8738c2df003a96f0e490c43559747618d10f5f
commit 5b8738c2df003a96f0e490c43559747618d10f5f
Author: Xavier Noria <fxn@hashref.com>
Date: Sat Mar 5 08:09:20 2016 +0100
define APP_PATH with __dir__
Defining paths relative to a file name has always hurt my soul,
with __dir__ we can restore order in the Universe.
diff --git a/railties/lib/rails/generators/rails/app/templates/bin/rails b/railties/lib/rails/generators/rails/app/templates/bin/rails
index 80ec808..513a2e0 100644
--- a/railties/lib/rails/generators/rails/app/templates/bin/rails
+++ b/railties/lib/rails/generators/rails/app/templates/bin/rails
@@ -1,3 +1,3 @@
-APP_PATH = File.expand_path('../../config/application', __FILE__)
+APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
I got inspiration from this commit and decided to “restore order” in Rails, Jekyll, and own projects.
I made 2 patches and they are already merged:
- Rails: Define path with __dir__
- Jekyll: Define path with __dir__
Also, I got applause from @fxn for my Pull Request in Rails:
Hope you got inspiration from my little story that related to __dir__
and you will find time for providing a patch with definitions of relative paths with __dir__
to projects that you often use, it will help to “restore order in the Universe”. I am sure that you will get applause too if you do it. ;)