Ruby: How to calculate a path relative to another one?
Use Pathname#relative_path_from
:
require 'pathname'
first = Pathname.new '/first/path'
second = Pathname.new '/second/path'
relative = second.relative_path_from first
# ../../second/path
first + relative
# /second/path
Converting an absolute path to a relative one
I believe Pathname#relative_path_from
is what you're looking for. See this answer I gave to another question.
require 'pathname'
first = Pathname.new '/first/path'
second = Pathname.new '/second/path'
relative = second.relative_path_from first
# ../../second/path
first + relative
# /second/path
Relative path to your project directory
You can get current directory (directory of current file) with this
File.dirname(__FILE__)
You can then join it with relative path to the root
File.join(File.dirname(__FILE__), '../../') # add proper number of ..
Or you can use expand_path
to convert relative path to absolute.
ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', File.dirname(__FILE__))
Or you can calculate relative path between two dirs.
require 'pathname';
puts Pathname.new('/').relative_path_from(Pathname.new('/some/child/dir/')).to_s
# => ../../..
get relative paths to files in ruby
You can use Dir.glob
:
Starting with Ruby 2.5 there's a base
argument:
cpp_file_paths = Dir.glob('**/*.cpp', base: 'FolderA')
#=> ["a.cpp", "b.cpp", "c.cpp", "FolderB/trial.cpp", "FolderB/trial1.cpp", "FolderC/srcFolder/anothercppfile.cpp"]
For older Rubies, you can chdir
into the base directory:
Dir.chdir('FolderA') do
cpp_file_paths = Dir.glob('**/*.cpp') #=> ["a.cpp", "b.cpp", "c.cpp", "FolderB/trial.cpp", "FolderB/trial1.cpp", "FolderC/srcFolder/anothercppfile.cpp"]
end
Note that the paths are relative, i.e. they don't start with a /
. Passing a block to chdir
ensures that the current directory is restored afterwards (thanks Arup Rakshit).
Opening relative paths from gem
Short answer
If I understand it correctly, you don't need to change anything.
Inside app.rb
and your gem
, relative paths will be understood relatively to Dir.pwd
.
If you run ruby app.rb
from inside /home/user/my_app
:
Dir.pwd
will be/home/user/my_app
- both
app.rb
andmy_gem
will look for'data.txt'
inside/home/user/my_app
.
Useful methods, just in case
Dir.chdir
If for some reason Dir.pwd
isn't the desired folder, you could change directory :
Dir.chdir('/home/user/my_app') do
# relative paths will be based from /home/user/my_app
# call your gem from here
end
Get the directory of current file :
__dir__
will help you get the directory :
Returns the canonicalized absolute path of the directory of the file
from which this method is called.
Get the current file :
__FILE__
will return the current file. (Note : uppercase.)
Concatenate file paths :
If you need to concatenate file paths, use File.expand_path
or File.join
. Please don't concatenate strings.
If you don't trust that the relative path will be correctly resolved, you could send an absolute path to your method :
my_gem.load_from_file(File.expand_path('data.txt'))
Determine if one path is under another path in Ruby?
Another way:
def child?(root, target)
raise ArgumentError, "target.size=#{target.size} < #{root.size} = root.size"\
if target.size < root.size
target[0...root.size] == root &&
(target.size == root.size || target[root.size] == ?/)
end
root = "/root/app"
p child?(root, "/root/app/some/path") # => true
p child?(root, "/root/apple") # => false
p child?(root, "/root/app") # => true
p child?(root, "/root") # => ArgumentError: target.size = 5 < 9 = root.size
Find the relative depth of child folder
The most simple way to solve this will look like:
parent = '/home/user/path/parent/'
child = '/home/user/path/parent/g/g/child/'
# Split the paths
child_chunks = child.split(File::SEPARATOR).reject(&:empty?)
parent_chunks = parent.split(File::SEPARATOR).reject(&:empty?)
# Find the diff between the two lists
puts (child_chunks - parent_chunks).length # => 3
The better way though would be to use Pathname
helper:
require 'pathname'
parent = Pathname.new('/home/user/path/parent/')
child = Pathname.new('/home/user/path/parent/g/g/child/')
puts child.relative_path_from(parent).to_s.split(File::SEPARATOR).length # => 3
Related Topics
Garbage Collector Tuning in Ruby 1.9
Invoke Delayed_Job Capistrano Tasks Only on Specific Servers
Rendering a JSON Object of a Join-Model and Its Associated Models
How I Know My Document's Size Inside Mongodb with the Ruby Driver
What's the Difference Between "=" & "=>" and "@Variable", "@@Variable" and ":Variable" in Ruby
How to Build Remote Webdriver for Chrome
Custom Rails Configuration Section
How to Sort Not Simple Hash (Hash of Hashes)
Require Lib in Rspec with Ruby 1.9.2 Brings "No Such File to Load"