Class: Build::Files::Path

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/build/files/path.rb,
lib/build/files/glob.rb,
lib/build/files/paths.rb,
lib/build/files/system.rb

Overview

Represents a file path with an absolute root and a relative offset:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(full_path, root = nil, relative_path = nil) ⇒ Path

Both paths must be full absolute paths, and path must have root as an prefix.



78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/build/files/path.rb', line 78

def initialize(full_path, root = nil, relative_path = nil)
	# This is the object identity:
	@full_path = full_path
	
	if root
		@root = root
		@relative_path = relative_path
	else
		# Effectively dirname and basename:
		@root, _, @relative_path = full_path.rpartition(File::SEPARATOR)
	end
end

Instance Attribute Details

#full_pathObject (readonly)

Returns the value of attribute full_path.



92
93
94
# File 'lib/build/files/path.rb', line 92

def full_path
  @full_path
end

#rootObject (readonly)

Returns the value of attribute root.



91
92
93
# File 'lib/build/files/path.rb', line 91

def root
  @root
end

Class Method Details

.[](path) ⇒ Object



73
74
75
# File 'lib/build/files/path.rb', line 73

def self.[] path
	self === path ? path : self.new(path.to_s)
end

.components(path) ⇒ Object

Returns a list of components for a path, either represented as a Path instance or a String.



28
29
30
31
32
33
34
# File 'lib/build/files/path.rb', line 28

def self.components(path)
	if Path === path
		path.components
	else
		path.split(File::SEPARATOR)
	end
end

.currentObject



10
11
12
# File 'lib/build/files/path.rb', line 10

def self.current
	self.new(::Dir.pwd)
end

.expand(path, root = Dir.getwd) ⇒ Object

Expand a path within a given root.



191
192
193
194
195
196
197
# File 'lib/build/files/path.rb', line 191

def self.expand(path, root = Dir.getwd)
	if path.start_with?(File::SEPARATOR)
		self.new(path)
	else
		self.join(root, path)
	end
end

.join(root, relative_path) ⇒ Object



186
187
188
# File 'lib/build/files/path.rb', line 186

def self.join(root, relative_path)
	self.new(File.join(root, relative_path), root)
end

.prefix_length(a, b) ⇒ Object

Returns the length of the prefix which is shared by two strings.



23
24
25
# File 'lib/build/files/path.rb', line 23

def self.prefix_length(a, b)
	[a.size, b.size].min.times{|i| return i if a[i] != b[i]}
end

.relative_path(root, full_path) ⇒ Object



64
65
66
67
68
69
70
71
# File 'lib/build/files/path.rb', line 64

def self.relative_path(root, full_path)
	relative_offset = root.length
	
	# Deal with the case where the root may or may not end with the path separator:
	relative_offset += 1 unless root.end_with?(File::SEPARATOR)
	
	return full_path.slice(relative_offset..-1)
end

.root(path) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/build/files/path.rb', line 36

def self.root(path)
	if Path === path
		path.root
	else
		File.dirname(path)
	end
end

.shortest_path(path, root) ⇒ Object

Return the shortest relative path to get to path from root. Root should be a directory with which you are computing the relative path.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/build/files/path.rb', line 45

def self.shortest_path(path, root)
	path_components = Path.components(path)
	root_components = Path.components(root)
	
	# Find the common prefix:
	i = prefix_length(path_components, root_components) || 0
	
	# The difference between the root path and the required path, taking into account the common prefix:
	up = root_components.size - i
	
	components = [".."] * up + path_components[i..-1]
	
	if components.empty?
		return "."
	else
		return File.join(components)
	end
end

.split(path) ⇒ Object



14
15
16
17
18
19
20
# File 'lib/build/files/path.rb', line 14

def self.split(path)
	# Effectively dirname and basename:
	dirname, separator, filename = path.rpartition(File::SEPARATOR)
	filename, dot, extension = filename.rpartition('.')
	
	return dirname + separator, filename, dot + extension
end

Instance Method Details

#+(path) ⇒ Object

Add a path component to the current path.

Parameters:

  • path (String, nil)

    (Optionally) the path to append.



145
146
147
148
149
150
151
# File 'lib/build/files/path.rb', line 145

def +(path)
	if path
		self.class.new(File.join(@full_path, path), @root)
	else
		self
	end
end

#/(path) ⇒ Object

Use the current path to define a new root, with an optional sub-path.

Parameters:

  • path (String, nil)

    (Optionally) the path to append.



155
156
157
158
159
160
161
# File 'lib/build/files/path.rb', line 155

def /(path)
	if path
		self.class.new(File.join(self, path), self)
	else
		self.class.new(self, self)
	end
end

#<=>(other) ⇒ Object



230
231
232
# File 'lib/build/files/path.rb', line 230

def <=>(other)
	self.to_s <=> other.to_s
end

#append(extension) ⇒ Object



139
140
141
# File 'lib/build/files/path.rb', line 139

def append(extension)
	self.class.new(@full_path + extension, @root)
end

#basenameObject



104
105
106
# File 'lib/build/files/path.rb', line 104

def basename
	self.parts.last
end

#componentsObject Also known as: parts



100
101
102
# File 'lib/build/files/path.rb', line 100

def components
	@components ||= @full_path.split(File::SEPARATOR).freeze
end

#copy(destination) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/build/files/system.rb', line 33

def copy(destination)
	if directory?
		destination.create
	else
		FileUtils.cp(self.to_s, destination.to_s)
	end
end

#directory?Boolean

Checks if the path refers to a directory.

Returns:

  • (Boolean)


56
57
58
# File 'lib/build/files/system.rb', line 56

def directory?
	File.directory?(self.to_s)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


224
225
226
# File 'lib/build/files/path.rb', line 224

def eql?(other)
	self.class.eql?(other.class) and @root.eql?(other.root) and @full_path.eql?(other.full_path)
end

#exist?Boolean

Checks if the file exists in the local file system.

Returns:

  • (Boolean)


51
52
53
# File 'lib/build/files/system.rb', line 51

def exist?
	File.exist?(self.to_s)
end

#file?Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/build/files/system.rb', line 60

def file?
	File.file?(self.to_s)
end

#for_appendingObject



249
250
251
# File 'lib/build/files/path.rb', line 249

def for_appending
	[@full_path, File::CREAT|File::APPEND|File::WRONLY]
end

#for_readingObject



241
242
243
# File 'lib/build/files/path.rb', line 241

def for_reading
	[@full_path, File::RDONLY]
end

#for_writingObject



245
246
247
# File 'lib/build/files/path.rb', line 245

def for_writing
	[@full_path, File::CREAT|File::TRUNC|File::WRONLY]
end

#glob(pattern) ⇒ Object



11
12
13
# File 'lib/build/files/glob.rb', line 11

def glob(pattern)
	Glob.new(self, pattern)
end

#hashObject



220
221
222
# File 'lib/build/files/path.rb', line 220

def hash
	[@root, @full_path].hash
end

#inspectObject



216
217
218
# File 'lib/build/files/path.rb', line 216

def inspect
	"#{@root.inspect}/#{relative_path.inspect}"
end

#lengthObject Also known as: size



94
95
96
# File 'lib/build/files/path.rb', line 94

def length
	@full_path.length
end

#list(*relative_paths) ⇒ Object



59
60
61
# File 'lib/build/files/paths.rb', line 59

def list(*relative_paths)
	Paths.directory(self, relative_paths)
end

#match(pattern, flags = 0) ⇒ Object

Match a path with a given pattern, using ‘File#fnmatch`.



235
236
237
238
239
# File 'lib/build/files/path.rb', line 235

def match(pattern, flags = 0)
	path = pattern.start_with?('/') ? full_path : relative_path
	
	return File.fnmatch(pattern, path, flags)
end

#mkpathObject Also known as: create

Recursively create a directory hierarchy for the given path.



78
79
80
# File 'lib/build/files/system.rb', line 78

def mkpath
	FileUtils.mkpath(self.to_s)
end

#modified_timeObject

The time the file was last modified.



73
74
75
# File 'lib/build/files/system.rb', line 73

def modified_time
	File.mtime(self.to_s)
end

#open(mode, &block) ⇒ Object

Open a file with the specified mode.



15
16
17
# File 'lib/build/files/system.rb', line 15

def open(mode, &block)
	File.open(self.to_s, mode, &block)
end

#parentObject



108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/build/files/path.rb', line 108

def parent
	root = @root
	full_path = File.dirname(@full_path)
	
	while root.size > full_path.size
		root = Path.root(root)
	end
	
	if root.size == full_path.size
		root = Path.root(root)
	end
	
	self.class.new(full_path, root)
end

#read(mode = File::RDONLY) ⇒ Object

Read the entire contents of the file.



20
21
22
23
24
# File 'lib/build/files/system.rb', line 20

def read(mode = File::RDONLY)
	open(mode) do |file|
		file.read
	end
end

#readable?Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/build/files/system.rb', line 68

def readable?
	File.readable?(self.to_s)
end

#rebase(root) ⇒ Object



163
164
165
# File 'lib/build/files/path.rb', line 163

def rebase(root)
	self.class.new(File.join(root, relative_path), root)
end

#relative_partsObject



133
134
135
136
137
# File 'lib/build/files/path.rb', line 133

def relative_parts
	dirname, _, basename = self.relative_path.rpartition(File::SEPARATOR)
	
	return dirname, basename
end

#relative_pathObject



129
130
131
# File 'lib/build/files/path.rb', line 129

def relative_path
	@relative_path ||= Path.relative_path(@root.to_s, @full_path.to_s).freeze
end

#rmObject Also known as: delete

Recursively delete the given path and all contents.



85
86
87
# File 'lib/build/files/system.rb', line 85

def rm
	FileUtils.rm_rf(self.to_s)
end

#shortest_path(root) ⇒ Object



199
200
201
# File 'lib/build/files/path.rb', line 199

def shortest_path(root)
	self.class.shortest_path(self, root)
end

#start_with?(*args) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/build/files/path.rb', line 123

def start_with?(*args)
	@full_path.start_with?(*args)
end

#statObject



46
47
48
# File 'lib/build/files/system.rb', line 46

def stat
	File.stat(self.to_s)
end

#symlink?Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/build/files/system.rb', line 64

def symlink?
	File.symlink?(self.to_s)
end

#to_pathObject



207
208
209
# File 'lib/build/files/path.rb', line 207

def to_path
	@full_path
end

#to_sObject



211
212
213
214
# File 'lib/build/files/path.rb', line 211

def to_s
	# It's not guaranteed to be string.
	@full_path.to_s
end

#to_strObject



203
204
205
# File 'lib/build/files/path.rb', line 203

def to_str
	@full_path.to_str
end

#touchObject

Touch the file, changing it’s last modified time.



42
43
44
# File 'lib/build/files/system.rb', line 42

def touch
	FileUtils.touch(self.to_s)
end

#with(root: @root, extension: nil, basename: false) ⇒ Object



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/build/files/path.rb', line 167

def with(root: @root, extension: nil, basename: false)
	relative_path = self.relative_path
	
	if basename
		dirname, filename, _ = self.class.split(relative_path)
		
		# Replace the filename if the basename is supplied:
		filename = basename if basename.is_a? String
		
		relative_path = dirname + filename
	end
	
	if extension
		relative_path = relative_path + extension
	end
	
	self.class.new(File.join(root, relative_path), root, relative_path)
end

#write(buffer, mode = File::CREAT|File::TRUNC|File::WRONLY) ⇒ Object

Write a buffer to the file, creating it if it doesn’t exist.



27
28
29
30
31
# File 'lib/build/files/system.rb', line 27

def write(buffer, mode = File::CREAT|File::TRUNC|File::WRONLY)
	open(mode) do |file|
		file.write(buffer)
	end
end