class File RELATIVE_PARENTDIR = '..' RELATIVE_SAMEDIR = '.' # Turns a path +to+ into a relative path from starting # point +from+. The argument +from+ is assumed to be # a filename. To treat it as a directory, make sure it # ends in +File::SEPARATOR+ ('/' on UNIX filesystems). # # @param [String] from the starting filename # (or directory with +from_isdir+ set to +true+). # @param [String] to the final path that should be made relative. # @return [String] the relative path from +from+ to +to+. def self.relative_path(from, to) from = expand_path(from).split(SEPARATOR) to = expand_path(to).split(SEPARATOR) from.length.times do break if from[0] != to[0] from.shift; to.shift end fname = from.pop join *(from.map { RELATIVE_PARENTDIR } + to) end # Cleans a path by removing extraneous '..', '.' and '/' characters # # @example Clean a path # File.cleanpath('a/b//./c/../e') # => "a/b/e" # @param [String] path the path to clean # @return [String] the sanitized path def self.cleanpath(path) path = path.split(SEPARATOR) path = path.inject([]) do |acc, comp| next acc if comp == RELATIVE_SAMEDIR if comp == RELATIVE_PARENTDIR && acc.size > 0 acc.pop next acc end acc << comp end File.join(*path) end end