Question

Converting a relative path foo with respect to reference point bar into an absolute path baz can be done by:

baz = File.expand_path(foo, bar)

How can the opposite of this be done? In other words, given an absolute path baz and reference point bar (given as absolute path), how can it be converted into a relative path foo as below?

foo = File.relative_path(baz, bar)

Please assume that all given paths are normalized in the sense that they do not end with / in case they are directories:

"/foo/bar"
"/foo/bar/" # No need to consider

and the same applies to all returned paths.

Note that this is not as trivial as stripping away bar from the initial part of baz and replacing it with ./ because baz is not necessarily a descendant of bar. In general, a number of ../ have to be stacked to reach the common ancestor.

Examples include, but are not limited to:

File.relative_path("/foo/bar/quex", "/foo") # => "bar/quex" (preferred) or
                                            #    "./bar/quex"
File.relative_path("/foo", "/foo/bar") # => "../"
File.relative_path("/foo/bar", "/baz/quex") # => "../../foo/bar"
Was it helpful?

Solution

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top