Class: Filepath

Inherits:
Object
  • Object
show all
Includes:
ContentChanges, ContentInfo, ContentTests, FilesystemChanges, FilesystemInfo, FilesystemTests, MetadataChanges, MetadataInfo, MetadataTests, SearchMethods
Defined in:
lib/filepath/filepath.rb

Defined Under Namespace

Modules: ContentChanges, ContentInfo, ContentTests, EnvironmentInfo, FilesystemChanges, FilesystemInfo, FilesystemTests, MetadataChanges, MetadataInfo, MetadataTests, MethodDelegation, SearchMethods

Constant Summary collapse

SEPARATOR =
'/'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SearchMethods

#directories, #entries, #files, #find, #links

Methods included from ContentChanges

#append, #truncate, #write

Methods included from FilesystemTests

#mountpoint?

Methods included from FilesystemChanges

#touch, #touch_p

Methods included from FilesystemInfo

#absolute_path, #real_path, #resolve_link

Methods included from MetadataTests

#hidden?

Constructor Details

#initialize(path) ⇒ Filepath

Returns a new instance of Filepath



4
5
6
7
8
9
10
11
12
# File 'lib/filepath/filepath.rb', line 4

def initialize(path)
	if path.is_a? Filepath
		@segments = path.segments
	elsif path.is_a? Array
		@segments = path
	else
		@segments = split_path_string(path.to_str)
	end
end

Class Method Details

.getwdObject



1050
1051
1052
# File 'lib/filepath/filepath.rb', line 1050

def Filepath.getwd
	return Dir.getwd.as_path
end

.join(*raw_paths) ⇒ Filepath

Creates a Filepath joining the given segments.

Returns:

  • (Filepath)

    a Filepath created joining the given segments



22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/filepath/filepath.rb', line 22

def Filepath.join(*raw_paths)
	if (raw_paths.count == 1) && (raw_paths.first.is_a? Array)
		raw_paths = raw_paths.first
	end

	paths = raw_paths.map { |p| p.as_path }

	segs = []
	paths.each { |path| segs += path.segments }
	segs.reject!.with_index { |seg, idx| !idx.zero? && seg == '/' }

	return Filepath.new(segs)
end

Instance Method Details

#+(extra_path) ⇒ Object

Deprecated.

Use the #/ (slash) method instead. This method does not show clearly if a path is being added or if a string should be added to the filename

An alias for #/.



75
76
77
78
# File 'lib/filepath/filepath.rb', line 75

def +(extra_path)
	warn "Filepath#+ is deprecated, use Filepath#/ instead."
	return self / extra_path
end

#/(extra_path) ⇒ Filepath

Appends another path to the current path.

Examples:

Append a string


"a/b".as_path / "c" #=> <a/b/c>

Append another Filepath


home = (ENV["HOME"] || "/root").as_path
conf_dir = '.config'.as_path

home / conf_dir #=> </home/user/.config>

Parameters:

  • extra_path (Filepath, String)

    the path to be appended to the current path

Returns:

  • (Filepath)

    a new path with the given path appended



55
56
57
# File 'lib/filepath/filepath.rb', line 55

def /(extra_path)
	return Filepath.join(self, extra_path)
end

#==(other) ⇒ boolean

Note:

this method compares the normalized versions of the paths

Checks whether two paths are equivalent.

Two paths are equivalent when they have the same normalized segments.

A relative and an absolute path will always be considered different. To compare relative paths to absolute path, expand first the relative path using Filepath::FilesystemInfo#absolute_path or Filepath::FilesystemInfo#real_path.

Examples:


path1 = "foo/bar".as_path
path2 = "foo/bar/baz".as_path
path3 = "foo/bar/baz/../../bar".as_path

path1 == path2            #=> false
path1 == path2.parent_dir #=> true
path1 == path3            #=> true

Parameters:

Returns:

  • (boolean)

    whether the other path is equivalent to the current path



704
705
706
707
708
709
710
# File 'lib/filepath/filepath.rb', line 704

def ==(other)
	if !other.respond_to?(:as_path)
		return false
	end

	return self.normalized_segments == other.as_path.normalized_segments
end

#=~(pattern) ⇒ Fixnum?

Note:

this method operates on the normalized path

Matches a pattern against this path.

Parameters:

  • pattern (Regexp, Object)

    the pattern to match against this path

Returns:

  • (Fixnum, nil)

    the position of the pattern in the path, or nil if there is no match



426
427
428
# File 'lib/filepath/filepath.rb', line 426

def =~(pattern)
	return self.to_s =~ pattern
end

#absolute?Boolean

Is this path absolute?

FIXME: document what an absolute path is.

Examples:


"/tmp".absolute?   #=> true
"tmp".absolute?    #=> false
"../tmp".absolute? #=> false

Returns:

  • (Boolean)

    whether the current path is absolute

See Also:



456
457
458
# File 'lib/filepath/filepath.rb', line 456

def absolute?
	return @segments.first == SEPARATOR # FIXME: windows, mac
end

#add_extension(extra_ext) ⇒ Filepath

Adds an extension to the current file extension

Replaces the file extension with the supplied one. If the file has no extension it is added to the filename together with a dot.

Examples:

Addition of an extension


tar_path = "archives/docs.tar".as_path
compressed_path = tar_path.add_extension("gz")
compressed_path.to_s #=> "archives/docs.tar.gz"

Addition of an extension to a filename without extensions


dir_path = "archives/2016".as_path
zip_path = dir_path.add_extension("zip")
zip_path.to_s #=> "archives/2016.zip"

Parameters:

  • extra_ext (String)

    the extension to add

Returns:

  • (Filepath)

    a new path with the given extension added to the existing extensions

See Also:



404
405
406
407
408
409
410
411
412
413
# File 'lib/filepath/filepath.rb', line 404

def add_extension(extra_ext)
	if !self.extension.nil?
		old_ext = self.extension
		new_ext = old_ext + '.' + extra_ext
	else
		new_ext = extra_ext
	end

	return self.with_extension(new_ext)
end

#as_pathFilepath

Returns the path itself.

Returns:



669
670
671
# File 'lib/filepath/filepath.rb', line 669

def as_path
	self
end

#ascend(max_depth = nil) {|path| ... } ⇒ Filepath

Iterates over all the path directories, from the current path to the root.

Examples:


web_dir = "/srv/example.org/web/html/".as_path
web_dir.ascend do |path|
    is = path.readable? ? "is" : "is NOT"

    puts "#{path} #{is} readable"
end

# produces
#
# /srv/example.org/web/html is NOT redable
# /srv/example.org/web is NOT readable
# /srv/example.org is readable
# /srv is readable
# / is readable

Parameters:

  • max_depth (defaults to: nil)

    the maximum depth to ascend to, nil to ascend without limits.

Yields:

  • (path)

    TODO

Returns:

See Also:



583
584
585
# File 'lib/filepath/filepath.rb', line 583

def ascend(max_depth = nil, &block)
	iterate(max_depth, :reverse_each, &block)
end

#descend(max_depth = nil) {|path| ... } ⇒ Filepath

Iterates over all the directory that lead to the current path.

Examples:


web_dir = "/srv/example.org/web/html/".as_path
web_dir.descend do |path|
    is = path.readable? ? "is" : "is NOT"

    puts "#{path} #{is} readable"
end

# produces
#
# / is readable
# /srv is readable
# /srv/example.org is readable
# /srv/example.org/web is NOT readable
# /srv/example.org/web/html is NOT redable

Parameters:

  • max_depth (defaults to: nil)

    the maximum depth to descent to, nil to descend without limits.

Yields:

  • (path)

    TODO

Returns:

See Also:



617
618
619
# File 'lib/filepath/filepath.rb', line 617

def descend(max_depth = nil, &block)
	iterate(max_depth, :each, &block)
end

#each_segment {|path| ... } ⇒ Filepath

Iterates over all the path segments, from the leftmost to the rightmost.

Examples:


web_dir = "/srv/example.org/web/html".as_path
web_dir.each_segment do |seg|
    puts seg
end

# produces
#
# /
# srv
# example.org
# web
# html

Yields:

  • (path)

    TODO

Returns:

See Also:



547
548
549
550
# File 'lib/filepath/filepath.rb', line 547

def each_segment(&block)
	@segments.each(&block)
	return self
end

#expanded_tildeFilepath

Expands tilde to the user's home directory

The tilde character (i.e. ~) will be expanded into the path of the user's home directory according to the rules of File#expand_path.

Examples:


path = "~/.config".as_path
path.expanded_tilde #=> </home/mel/.config>

Returns:

  • (Filepath)

    a new path in which the tilde character has been expanded into the path of the user's home directory.



518
519
520
# File 'lib/filepath/filepath.rb', line 518

def expanded_tilde
	return Filepath.new(File.expand_path(self))
end

#extensionString Also known as: ext

The extension of the file.

The extension of a file are the characters after the last dot.

Returns:

  • (String)

    the extension of the file or nil if the file has no extension

See Also:



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/filepath/filepath.rb', line 241

def extension
	filename = @segments.last

	num_dots = filename.count('.')

	if num_dots.zero?
		ext = nil
	elsif filename.start_with?('.') && num_dots == 1
		ext = nil
	elsif filename.end_with?('.')
		ext = ''
	else
		ext = filename.split('.').last
	end

	return ext
end

#extension?(ext) ⇒ Object #extension?Object Also known as: ext?

Overloads:

  • #extension?(ext) ⇒ Object

    Returns whether the file extension matches the given extension

    Parameters:

    • ext (String, Regexp)

      the extension to be matched

    Returns:

    • whether the file extension matches the given extension

  • #extension?Object

    Returns whether the file has an extension

    Returns:

    • whether the file has an extension



270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/filepath/filepath.rb', line 270

def extension?(ext = nil)
	cur_ext = self.extension

	if ext.nil?
		return !cur_ext.nil?
	else
		if ext.is_a? Regexp
			return !cur_ext.match(ext).nil?
		else
			return cur_ext == ext
		end
	end
end

#filenameFilepath Also known as: basename

The filename component of the path.

The filename is the component of a path that appears after the last path separator.

Returns:



182
183
184
185
186
187
188
189
190
191
# File 'lib/filepath/filepath.rb', line 182

def filename
	segs = self.normalized_segments

	if self.root? || segs.empty?
		return ''.as_path
	end

	filename = segs.last
	return filename.as_path
end

#join(*extra_paths) ⇒ Filepath

Append multiple paths to the current path.

Returns:

  • (Filepath)

    a new path with all the paths appended



64
65
66
# File 'lib/filepath/filepath.rb', line 64

def join(*extra_paths)
	return Filepath.join(self, *extra_paths)
end

#normalizedFilepath Also known as: normalised

Simplify paths that contain . and ...

The resulting path will be in normal form.

FIXME: document what normal form is.

Examples:


path = $ENV["HOME"] / ".." / "jack" / "."

path #=> </home/gioele/../jack/.>
path.normalized #=> </home/jack>

Returns:

  • (Filepath)

    a new path that does not contain . or .. segments.



496
497
498
# File 'lib/filepath/filepath.rb', line 496

def normalized
	return Filepath.join(self.normalized_segments)
end

#parent_dirFilepath

The dir that contains the file

Returns:

  • (Filepath)

    the path of the parent dir



200
201
202
# File 'lib/filepath/filepath.rb', line 200

def parent_dir
	return self / '..'
end

#relative?Boolean

Is this path relative?

FIXME: document what a relative path is.

Examples:


"/tmp".relative?   #=> false
"tmp".relative?    #=> true
"../tmp".relative? #=> true

Returns:

  • (Boolean)

    whether the current path is relative

See Also:



475
476
477
# File 'lib/filepath/filepath.rb', line 475

def relative?
	return !self.absolute?
end

#relative_to(base) ⇒ Filepath

Note:

this method operates on the normalized paths

Calculates the relative path from a given directory.

Examples:

relative paths between relative paths


posts_dir = "posts".as_path
images_dir = "static/images".as_path

 = images_dir / 'logo.png'

.relative_to(posts_dir) #=> <../static/images/logo.png>

relative paths between absolute paths


home_dir = "/home/gioele".as_path
docs_dir = "/home/gioele/Documents".as_path
tmp_dir = "/tmp".as_path

docs_dir.relative_to(home_dir) #=> <Documents>
home_dir.relative_to(docs_dir) #=> <..>

tmp_dir.relative_to(home_dir) #=> <../../tmp>

Parameters:

  • base (Filepath, String)

    the directory to use as base for the relative path

Returns:

See Also:



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/filepath/filepath.rb', line 112

def relative_to(base)
	base = base.as_path

	if self.absolute? != base.absolute?
		self_abs = self.absolute? ? "absolute" : "relative"
		base_abs = base.absolute? ? "absolute" : "relative"
		msg = "cannot compare: "
		msg += "`#{self}` is #{self_abs} while "
		msg += "`#{base}` is #{base_abs}"
		raise ArgumentError, msg
	end

	self_segs = self.normalized_segments
	base_segs = base.normalized_segments

	base_segs_tmp = base_segs.dup
	num_same = self_segs.find_index do |seg|
		base_segs_tmp.delete_at(0) != seg
	end

	# find_index returns nil if `self` is a subset of `base`
	num_same ||= self_segs.length

	num_parent_dirs = base_segs.length - num_same
	left_in_self = self_segs[num_same..-1]

	segs = [".."] * num_parent_dirs + left_in_self
	normalized_segs = normalized_relative_segs(segs)

	return Filepath.join(normalized_segs)
end

#relative_to_file(base_file) ⇒ Filepath

Calculates the relative path from a given file.

Examples:

relative paths between relative paths


post = "posts/2012-02-14-hello.html".as_path
images_dir = "static/images".as_path

rel_img_dir = images_dir.relative_to_file(post)
rel_img_dir.to_s #=> "../static/images"

 = rel_img_dir / 'logo.png' #=> <../static/images/logo.png>

relative paths between absolute paths


rc_file = "/home/gioele/.bashrc".as_path
tmp_dir = "/tmp".as_path

tmp_dir.relative_to_file(rc_file) #=> <../../tmp>

Parameters:

  • base_file (Filepath, String)

    the file to use as base for the relative path

Returns:

See Also:



170
171
172
# File 'lib/filepath/filepath.rb', line 170

def relative_to_file(base_file)
	return relative_to(base_file.as_path.parent_dir)
end

#root?Boolean

Note:

this method operates on the normalized paths

Is this path pointing to the root directory?

Returns:

  • (Boolean)

    whether the path points to the root directory



437
438
439
# File 'lib/filepath/filepath.rb', line 437

def root?
	return self.normalized_segments == [SEPARATOR] # FIXME: windows, mac
end

#to_raw_stringString Also known as: to_raw_str

This path converted to a String.

Examples:

differences between #to_raw_string and #to_s


path = "/home/gioele/.config".as_path / ".." / ".cache"
path.to_raw_string #=> "/home/gioele/config/../.cache"
path.to_s #=> "/home/gioele/.cache"

Returns:

  • (String)

    this path converted to a String

See Also:



646
647
648
# File 'lib/filepath/filepath.rb', line 646

def to_raw_string
	@to_raw_string ||= join_segments(@segments)
end

#to_sString

Note:

this method operates on the normalized path

Returns this path converted to a String

Returns:

  • (String)

    this path converted to a String



657
658
659
# File 'lib/filepath/filepath.rb', line 657

def to_s
	to_str
end

#with_extension(new_ext) ⇒ Filepath #with_extensionFilepath Also known as: replace_extension, replace_ext, sub_ext

Replaces or removes the file extension.

Overloads:

  • #with_extension(new_ext) ⇒ Filepath

    Replaces the file extension with the supplied one. If the file has no extension it is added to the file name together with a dot.

    Examples:

    Extension replacement

    
    src_path = "pages/about.markdown".as_path
    html_path = src_path.with_extension("html")
    html_path.to_s #=> "pages/about.html"

    Extension addition

    
    base = "style/main-style".as_path
    sass_style = base.with_extension("sass")
    sass_style.to_s #=> "style/main-style.sass"

    Parameters:

    • new_ext (String)

      the new extension

    Returns:

    • (Filepath)

      a new path with the replaced extension

  • #with_extensionFilepath

    Removes the file extension if present.

    The #without_extension method provides the same functionality but has a more meaningful name.

    Examples:

    
    post_file = "post/welcome.html"
    post_url = post_file.with_extension(nil)
    post_url.to_s #=> "post/welcome"

    Returns:

    • (Filepath)

      a new path without the extension

See Also:



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/filepath/filepath.rb', line 328

def with_extension(new_ext) # FIXME: accept block
	orig_filename = filename.to_s

	if !self.extension?
		if new_ext.nil?
			new_filename = orig_filename
		else
			new_filename = orig_filename + '.' + new_ext
		end
	else
		if new_ext.nil?
			pattern = /\.[^.]*?\Z/
			new_filename = orig_filename.sub(pattern, '')
		else
			pattern = Regexp.new('.' + extension + '\\Z')
			new_filename = orig_filename.sub(pattern, '.' + new_ext)
		end
	end

	segs = @segments[0..-2]
	segs << new_filename

	return Filepath.new(segs)
end

#with_filename(new_path) ⇒ Filepath Also known as: with_basename, replace_filename, replace_basename

Replace the path filename with the supplied path.

Examples:


post = "posts/2012-02-16-hello-world/index.md".as_path
style = post.with_filename("style.css")
style.to_s #=> "posts/2012-02-16-hello-world/style.css"

Parameters:

  • new_path (Filepath, String)

    the path to be put in place of the current filename

Returns:

  • (Filepath)

    a path with the supplied path instead of the current filename

See Also:



222
223
224
225
# File 'lib/filepath/filepath.rb', line 222

def with_filename(new_path)
	dir = self.parent_dir
	return dir / new_path
end

#without_extensionFilepath Also known as: remove_ext, remove_extension

Removes the file extension if present.

Examples:


post_file = "post/welcome.html"
post_url = post_file.without_extension
post_url.to_s #=> "post/welcome"

Returns:

  • (Filepath)

    a new path without the extension

See Also:



370
371
372
# File 'lib/filepath/filepath.rb', line 370

def without_extension
	return with_extension(nil)
end