forked from lsegal/yard
/
file.rb
58 lines (53 loc) · 1.76 KB
/
file.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
require 'fileutils'
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.last != RELATIVE_PARENTDIR
acc.pop
next acc
end
acc << comp
end
File.join(*path)
end
# Forces opening a file (for writing) by first creating the file's directory
def self.open!(file, *args, &block)
dir = dirname(file)
FileUtils.mkdir_p(dir) unless directory?(dir)
open(file, *args, &block)
end
# Reads a file with binary encoding
# @return [String] the ascii-8bit encoded data
def self.read_binary(file)
File.open(file, 'rb') {|f| f.read }
end
end