Inspired by "Getting the source directory of a Bash script from within", what's the Ruby way to do this?
For newer versions of Ruby, try:
__dir__
For older versions of Ruby (< 2.0), the script being run can be found using:
File.dirname(__FILE__) - relative path; or
File.expand_path(File.dirname(__FILE__)) - the absolute path.
Note: Using __dir__ will return the script path even after a call to Dir.chdir; whereas, using the older syntax may not return the path to the script.
Use __dir__
As of Ruby 2.0, __dir__ is the simplest way to get this. It
Returns the canonicalized absolute path of the directory of the file
from which this method is called.
See the __dir__ documentation, and "Why is __FILE__ uppercase and __dir__ lowercase?".
use __dir__
File.dirname(__FILE__) is not a proper way to get directory where script is stored.
At start working directory and directory with script file is the same, but it may change.
For example:
Dir.chdir('..') do
puts __dir__
puts File.expand_path(File.dirname(__FILE__))
end
for script file stored in /Desktop/tmp running it will give output
/home/mateusz/Desktop/tmp
/home/mateusz/Desktop
ENV["PWD"] seems the simplest way for me under Linux. I don't know of an OS-agnostic way.
Related
I've got a project structure as follows:
info.config (just a JSON file w/ prefs+creds)
main.rb
tasks/
test.rb
In both main.rb (at the root of the project), and test.rb (under the tasks folder), I want to be able to read and parse the info.config file. I've figured out how to do that in main.rb with the following:
JSON.parse(File.read('info.config'))
Of course, that doesn't work in test.rb.
Question: How can I read the file from a test.rb even though it's one level deeper in the hierarchy?
Appreciate any guidance I can get! Thanks!
Use relative path:
path = File.join(
File.dirname(File.dirname(File.absolute_path(__FILE__))),
'info.config'
)
JSON.parse(File.read(path))
File.dirname(File.absolute_path(__FILE__)) will give you the directory where test.rb resides. -> (1)
File.dirname(File.dirname(File.absolute_path(__FILE__))) will give you parent directory of (1).
Reference: File::absolute_path, File::dirname
UPDATE
Using File::expand_path is more readable.
path = File.expand_path('../../info.config', __FILE__)
JSON.parse(File.read(path))
What I usually do is:
Create file called environment or similar in your project root. This file has only one purpose - to extend load path:
require 'pathname'
ROOT_PATH = Pathname.new(File.dirname(__FILE__))
$:.unshift ROOT_PATH
Require this file at the beginning of your code. From now on every time you call require, you can use relative_path to you root directory, without worrying where file you are requiring it from is located.
When using File, you can simple do:
File.open(ROOT_PATH.join 'task', 'test.rb')
You can do as below using File::expand_path :
path = File.expand_path("info.config","#{File.dirname(__FILE__)}/..")
JSON.parse(File.read(path))
File.dirname(__FILE__) will give you the path as "root_path_of_your_projet/tasks/".
"#{File.dirname(__FILE__)}/.." will give you the path as "root_path_of_your_projet/". .. means go one level up from the current directory.
File.expand_path("info.config","root_path_of_your_projet/") will give you the actual path to the file as "root_path_of_your_projet/info.config".
You can also use __dir__ instead of File.dirname(__FILE__).
__dir__ : Returns the canonicalized absolute path of the directory of the file from which this method is called.
Hope that explanation helps.
I have written a couple of small Ruby scripts for system administration using Ruby 1.9.3. In one script I use:
File.dirname(__FILE__)
to get the directory of the script file. This returns a relative path, however when I call the script from a second script File.dirname returns an absolute path.
Ruby Doc lists an absolute return path in its example whereas I found a discussion on Ruby Forum where a user says dirname should only return a relative path.
I am using the suggested solution from Ruby Forums to use File.expand_path to always get the absolute path like this:
File.expand_path(File.dirname(__FILE__))
but is there a way to make the behaviour of dirname consistent?
UPDATE:
To expand on Janathan Cairs answer, I made two scripts:
s1.rb:
puts "External script __FILE__: #{File.dirname(__FILE__)}"
s0.rb:
puts "Local script __FILE__: #{File.dirname(__FILE__)}"
require './s1.rb'
Running ./s0.rb gives the following output:
Local script __FILE__: .
External script __FILE__: /home/kenneth/Pictures/wp/rip_vault
File.dirname should return an absolute path if given an absolute path, and a relative path if given a relative path:
File.dirname('/home/jon/test.rb') # => '/home/jon'
File.dirname('test.rb') # => '.'
__FILE__ returns the name of the current script, which is therefore a relative path from the current directory. That means you should always use expand_path if you want to get the absolute path with File.dirname(__FILE__).
NB Ruby 2.0.0 introduces the __dir__ constant
If you already upgraded to Ruby 2.0, you can use the new constant
__dir__
otherwise you can use
File.expand_path('..', __FILE__)
which is shorter than
File.expand_path(File.dirname(__FILE__))
File.expand_path documentation
I have a Ruby code with different classes in a few files. In one file, I start the execution. This file requires my other files.
Is this a good way to start a ruby code?
When I run the code from a symbolic link, for example DIR2/MyRubyCode is a link to the main file DIR1/MyRubyCode.rb, then my requires will fail. I solved the problem by adding the path DIR1 to $LOAD_PATH before the require, but I think there would be much better ways to do it. Do you have any suggestions about that?
If you're using Ruby 1.9 or greater, user require_relative for your dependencies.
require_relative 'foo_class'
require_relative 'bar_module'
If you want to check if a Ruby file is being 'require'ed or executed with 'ruby MyRubyCode.rb', check the __FILE__ constant.
# If the first argument to `ruby` is this file.
if $0 == __FILE__
# Execute some stuff.
end
As far as the require/$LOAD_PATH issue, you could always use the relative path in the require statement. For example:
# MyRubyCode.rb
require "#{File.dirname(__FILE__)}/foo_class"
require "#{File.dirname(__FILE__)}/bar_module"
Which would include the foo_class.rb and bar_module.rb files in the same directory as MyRubyCode.rb.
I know this is an old question, but there is an updated answer to it, and I wanted to post it:
Starting in a more recent version of Ruby (I'm not sure when), you can require files in the same directory by using the following:
require './foo_class'
require './bar_module'
and it'll load files called foo_class.rb and bar_module.rb in the same directory.
For checking if your file is being required or ran normally, check the other answer.
What is the best way to manage the require paths in a ruby program?
Let me give a basic example, consider a structure like:
\MyProgram
\MyProgram\src\myclass.rb
\MyProgram\test\mytest.rb
If in my test i use require '../src/myclass' then I can only call the test from \MyProgram\test folder, but I want to be able to call it from any path!
The solution I came up with is to define in all source files the following line:
ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(ROOT) and then always use require "#{ROOT}/src/myclass"
Is there a better way to do it?
As of Ruby 1.9 you can use require_relative to do this:
require_relative '../src/myclass'
If you need this for earlier versions you can get it from the extensions gem as per this SO comment.
Here is a slightly modified way to do it:
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "src"))
By prepending the path to your source to $LOAD_PATH (aka $:) you don't have to supply the root etc. explicitly when you require your code i.e. require 'myclass'
The same, less noisy IMHO:
$:.unshift File.expand_path("../../src", __FILE__)
require 'myclass'
or just
require File.expand_path "../../src/myclass", __FILE__
Tested with ruby 1.8.7 and 1.9.0 on (Debian) Linux - please tell me if it works on Windows, too.
Why a simpler method (eg. 'use', 'require_relative', or sg like this) isn't built into the standard lib? UPDATE: require_relative is there since 1.9.x
Pathname(__FILE__).dirname.realpath
provides a the absolute path in a dynamic way.
Use following code to require all "rb" files in specific folder (=> Ruby 1.9):
path='../specific_folder/' # relative path from current file to required folder
Dir[File.dirname(__FILE__) + '/'+path+'*.rb'].each do |file|
require_relative path+File.basename(file) # require all files with .rb extension in this folder
end
sris's answer is the standard approach.
Another way would be to package your code as a gem. Then rubygems will take care of making sure your library files are in your path.
This is what I ended up with - a Ruby version of a setenv shell script:
# Read application config
$hConf, $fConf = {}, File.expand_path("../config.rb", __FILE__)
$hConf = File.open($fConf) {|f| eval(f.read)} if File.exist? $fConf
# Application classpath
$: << ($hConf[:appRoot] || File.expand_path("../bin/app", __FILE__))
# Ruby libs
$lib = ($hConf[:rubyLib] || File.expand_path("../bin/lib", __FILE__))
($: << [$lib]).flatten! # lib is string or array, standardize
Then I just need to make sure that this script is called once before anything else, and don't need to touch the individual source files.
I put some options inside a config file, like the location of external (non-gem) libraries:
# Site- and server specific config - location of DB, tmp files etc.
{
:webRoot => "/srv/www/myapp/data",
:rubyLib => "/somewhere/lib",
:tmpDir => "/tmp/myapp"
}
This has been working well for me, and I can reuse the setenv script in multiple projects just by changing the parameters in the config file. A much better alternative than shell scripts, IMO.
How do I get the directory where the rakefile.rb is located?
I want to use this as my root directory to locate everything off.
use __FILE__ to get the file name then you can get the directory from there:
in test.rb
puts __FILE__
output:
/users/foo/test.rb
__FILE__ resolves to the full path of the file it is in.
Use this to get the dir name:
File.dirname(__FILE__)
You can get it by calling application.original_dir method. In task you can achieve application object using application method on task object.
Why not just use Dir.pwd
?
As of Ruby 2 you can use __dir__ instead of File.dirname(__FILE__) to get the directory that contains the current script.
If this is a RoR app your Rakefile.rb should be in your RAILS_ROOT directory. So in any script you can specify file location like
config.load_paths += %W( #{RAILS_ROOT}/extras )