Class: Build::Files::Path

Inherits:
Object
  • Object
show all
Defined in:
lib/build/files/path.rb,
lib/build/files/glob.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.



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

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
	
	# This improves the cost of hash/eql? slightly but the root cannot be deconstructed if it was an instance of Path.
	# @root = @root.to_s
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



70
71
72
# File 'lib/build/files/path.rb', line 70

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.



39
40
41
42
43
44
45
# File 'lib/build/files/path.rb', line 39

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

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

Expand a subpath within a given root, similar to ‘File.expand_path`



163
164
165
166
167
168
169
# File 'lib/build/files/path.rb', line 163

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

.join(root, relative_path) ⇒ Object



158
159
160
# File 'lib/build/files/path.rb', line 158

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.



34
35
36
# File 'lib/build/files/path.rb', line 34

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



61
62
63
64
65
66
67
68
# File 'lib/build/files/path.rb', line 61

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

.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.



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

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
	
	return File.join([".."] * up + path_components[i..-1])
end

.split(path) ⇒ Object



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

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



126
127
128
# File 'lib/build/files/path.rb', line 126

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

#/(path) ⇒ Object

Define a new root with a sub-path:



131
132
133
# File 'lib/build/files/path.rb', line 131

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

#==(other) ⇒ Object



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

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

#append(extension) ⇒ Object



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

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

#basenameObject



102
103
104
# File 'lib/build/files/path.rb', line 102

def basename
	self.parts.last
end

#componentsObject Also known as: parts



98
99
100
# File 'lib/build/files/path.rb', line 98

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

#directory?Boolean

Checks if the path refers to a directory.

Returns:

  • (Boolean)


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

def directory?
	File.directory? self
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


195
196
197
# File 'lib/build/files/path.rb', line 195

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)


54
55
56
# File 'lib/build/files/system.rb', line 54

def exist?
	File.exist? self
end

#for_appendingObject



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

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

#for_readingObject



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

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

#for_writingObject



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

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

#glob(pattern) ⇒ Object



26
27
28
# File 'lib/build/files/glob.rb', line 26

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

#hashObject



191
192
193
# File 'lib/build/files/path.rb', line 191

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

#inspectObject



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

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

#lengthObject



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

def length
	@full_path.length
end

#mkpathObject Also known as: create

Recursively create a directory hierarchy for the given path.



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

def mkpath
	FileUtils.mkpath self
end

#modified_timeObject

The time the file was last modified.



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

def modified_time
	File.mtime self
end

#open(mode, &block) ⇒ Object

Open a file with the specified mode.



30
31
32
# File 'lib/build/files/system.rb', line 30

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

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

Read the entire contents of the file.



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

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

#rebase(root) ⇒ Object



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

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

#relative_partsObject



116
117
118
119
120
# File 'lib/build/files/path.rb', line 116

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

#relative_pathObject



112
113
114
# File 'lib/build/files/path.rb', line 112

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

#rmObject Also known as: delete

Recursively delete the given path and all contents.



76
77
78
# File 'lib/build/files/system.rb', line 76

def rm
	FileUtils.rm_rf self
end

#shortest_path(root) ⇒ Object



171
172
173
# File 'lib/build/files/path.rb', line 171

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

#start_with?(*args) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/build/files/path.rb', line 106

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

#to_pathObject



179
180
181
# File 'lib/build/files/path.rb', line 179

def to_path
	@full_path
end

#to_sObject



183
184
185
# File 'lib/build/files/path.rb', line 183

def to_s
	@full_path
end

#to_strObject



175
176
177
# File 'lib/build/files/path.rb', line 175

def to_str
	@full_path
end

#touchObject

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



49
50
51
# File 'lib/build/files/system.rb', line 49

def touch
	FileUtils.touch self
end

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



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/build/files/path.rb', line 139

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.



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

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