Class: Path
- Includes:
- Comparable, Enumerable
- Defined in:
- lib/epitools/path.rb
Overview
Path: An object-oriented wrapper for files. (Combines useful methods from FileUtils, File, Dir, and more!)
To create a path object, or array of path objects, throw whatever you want into Path[]:
These returns a single path object:
passwd = Path["/etc/passwd"]
also_passwd = Path["/etc"] / "passwd" # joins two paths
parent_dir = Path["/usr/local/bin"] / ".." # joins two paths (up one dir)
These return an array of path objects:
pictures = Path["photos/*.{jpg,png}"] # globbing
notes = Path["notes/2014/**/*.txt"] # recursive globbing
everything = Path["/etc"].ls
Each Path object has the following attributes, which can all be modified:
path => the absolute path, as a string
filename => just the name and extension
basename => just the filename (without extension)
ext => just the extension
dir => just the directory
dirs => an array of directories
Some commonly used methods:
path.file?
path.exists?
path.dir?
path.mtime
path.xattrs
path.symlink?
path.broken_symlink?
path.symlink_target
path.executable?
path.chmod(0o666)
Interesting examples:
Path["*.jpeg"].each { |path| path.rename(:ext=>"jpg") } # renames .jpeg to .jpg
files = Path["/etc"].ls # all files in directory
morefiles = Path["/etc"].ls_R # all files in directory tree
Path["*.txt"].each(&:gzip!)
Path["filename.txt"] << "Append data!" # appends data to a file
string = Path["filename.txt"].read # read all file data into a string
json = Path["filename.json"].read_json # read and parse JSON
doc = Path["filename.html"].read_html # read and parse HTML
xml = Path["filename.xml"].parse # figure out the format and parse it (as XML)
Path["saved_data.marshal"].write(data.marshal) # Save your data!
data = Path["saved_data.marshal"].unmarshal # Load your data!
Path["unknown_file"].mimetype # sniff the file to determine its mimetype
Path["unknown_file"].mimetype.image? # ...is this some kind of image?
Path["otherdir/"].cd do # temporarily change to "otherdir/"
p Path.ls
end
p Path.ls
The `Path#dirs` attribute is a split up version of the directory (eg: Path.dirs => [“usr”, “local”, “bin”]).
You can modify the dirs array to change subsets of the directory. Here's an example that finds out if you're in a git repo:
def inside_a_git_repo?
path = Path.pwd # start at the current directory
while path.dirs.any?
if (path/".git").exists?
return true
else
path.dirs.pop # go up one level
end
end
false
end
Swap two files:
a, b = Path["file_a", "file_b"]
temp = a.with(:ext => a.ext+".swapping") # return a modified version of this object
a.mv(temp)
b.mv(a)
temp.mv(b)
Paths can be created for existant and non-existant files.
To create a nonexistant path object that thinks it's a directory, just add a '/' at the end. (eg: Path).
Performance has been an important factor in Path's design, so doing crazy things with Path usually doesn't kill performance. Go nuts!
Defined Under Namespace
Constant Summary collapse
- COMPRESSORS =
zopening files
{ "gz" => "gzip", "xz" => "xz", "bz2" => "bzip2" }
- AUTOGENERATED_CLASS_METHODS =
FileUtils-like class-method versions of instance methods (eg: `Path.mv(src, dest)`)
Note: Methods with cardinality 1 (`method/1`) are instance methods that take one parameter, and hence, class methods that take two parameters.
%w[ mkdir mkdir_p sha1 sha2 md5 rm truncate realpath mv/1 move/1 chmod/1 chown/1 chown_R/1 chmod_R/1 ].each do |spec| meth, cardinality = spec.split("/") cardinality = cardinality.to_i class_eval %{ def self.#{meth}(path#{", *args" if cardinality > 0}) Path[path].#{meth}#{"(*args)" if cardinality > 0} end } end
- PATH_SEPARATOR =
":"
- BINARY_EXTENSION =
""
Instance Attribute Summary collapse
-
#base ⇒ Object
(also: #basename)
The filename without an extension.
-
#dirs ⇒ Object
The directories in the path, split into an array.
-
#ext ⇒ Object
(also: #extname, #extension)
The file extension, including the .
Class Method Summary collapse
- .[](path) ⇒ Object
-
.cd(dest) ⇒ Object
Change into the directory “dest”.
- .escape(str) ⇒ Object
-
.expand_path(orig_path) ⇒ Object
Same as File.expand_path, except preserves the trailing '/'.
-
.getfattr(path) ⇒ Object
Read xattrs from file (requires “getfattr” to be in the path).
- .glob(str, hints = {}) ⇒ Object
-
.home ⇒ Object
User's current home directory.
- .ln_s(src, dest) ⇒ Object
- .ls(path) ⇒ Object
- .ls_r(path) ⇒ Object
-
.mkcd(path, &block) ⇒ Object
Path.mkcd(path) creates a path if it doesn't exist, and changes to it (temporarily, if a block is provided).
- .popd ⇒ Object
- .pushd(destination) ⇒ Object
-
.pwd ⇒ Object
The current directory.
-
.setfattr(path, key, value) ⇒ Object
Set xattrs on a file (requires “setfattr” to be in the path).
-
.tmpdir(prefix = "tmp") ⇒ Object
Create a uniqely named directory in /tmp.
-
.tmpfile(prefix = "tmp") {|path| ... } ⇒ Object
TODO: Remove the tempfile when the Path object is garbage collected or freed.
-
.which(bin, *extras) ⇒ Object
A clone of `/usr/bin/which`: pass in the name of a binary, and it'll search the PATH returning the absolute location of the binary if it exists, or `nil` otherwise.
Instance Method Summary collapse
- #/(other) ⇒ Object
- #<=>(other) ⇒ Object
- #==(other) ⇒ Object (also: #eql?)
-
#=~(pattern) ⇒ Object
Match the full path against a regular expression.
-
#[](key) ⇒ Object
Retrieve one of this file's xattrs.
-
#[]=(key, value) ⇒ Object
Set this file's xattr.
-
#append(data = nil) ⇒ Object
(also: #<<)
Append data to this file (accepts a string, an IO, or it can yield the file handle to a block.).
- #atime ⇒ Object
- #atime=(new_atime) ⇒ Object
-
#attrs ⇒ Object
(also: #xattrs)
Return a hash of all of this file's xattrs.
-
#attrs=(new_attrs) ⇒ Object
Set this file's xattrs.
-
#backup! ⇒ Object
Rename this file, “filename.ext”, to “filename.ext.bak”.
-
#backup_file ⇒ Object
Return a copy of this Path with “.bak” at the end.
- #broken_symlink? ⇒ Boolean
-
#cd(&block) ⇒ Object
Change into the directory.
- #child_of?(parent) ⇒ Boolean
-
#chmod(mode) ⇒ Object
Same usage as `FileUtils.chmod` (because it just calls `FileUtils.chmod`).
- #chmod_R(mode) ⇒ Object
- #chown(usergroup) ⇒ Object
- #chown_R(usergroup) ⇒ Object
- #cp(dest) ⇒ Object
-
#cp_p(dest) ⇒ Object
Copy a file to a destination, creating all intermediate directories if they don't already exist.
- #cp_r(dest) ⇒ Object
- #ctime ⇒ Object
-
#deflate(level = nil) ⇒ Object
(also: #gzip)
gzip the file, returning the result as a string.
-
#dir ⇒ Object
(also: #dirname, #directory)
The current directory (with a trailing /).
- #dir=(newdir) ⇒ Object (also: #dirname=, #directory=)
- #dir? ⇒ Boolean (also: #directory?)
-
#each_chunk(chunk_size = 2**14) ⇒ Object
Read the contents of a file one chunk at a time (default chunk size is 16k).
-
#each_line ⇒ Object
(also: #each, #lines, #nicelines, #nice_lines)
All the lines in this file, chomped.
- #endswith(s) ⇒ Object
- #executable? ⇒ Boolean (also: #exe?)
-
#exists? ⇒ Boolean
(also: #exist?)
fstat.
- #exts ⇒ Object
- #file? ⇒ Boolean
- #filename ⇒ Object
- #filename=(newfilename) ⇒ Object
-
#grep(pat) ⇒ Object
Yields all matching lines in the file (by returning an Enumerator, or receiving a block).
-
#gunzip! ⇒ Object
Quickly gunzip a file, creating a new file, without removing the original, and returning a Path to that new file.
-
#gzip!(level = nil) ⇒ Object
Quickly gzip a file, creating a new .gz file, without removing the original, and returning a Path to that new file.
- #hash ⇒ Object
-
#hidden? ⇒ Boolean
Does the file or directory name start with a “.”?.
-
#id3 ⇒ Object
(also: #id3tags)
Read ID3 tags (requires 'id3tag' gem).
-
#inflate ⇒ Object
(also: #gunzip)
gunzip the file, returning the result as a string.
-
#initialize(newpath, hints = {}) ⇒ Path
constructor
Initializers.
- #initialize_copy(other) ⇒ Object
-
#inspect ⇒ Object
inspect.
-
#join(other) ⇒ Object
Path.join(“anything{}”).path == “/etc/anything{}” (globs ignored).
- #ln_s(dest) ⇒ Object
-
#ls ⇒ Object
Returns all the files in the directory that this path points to.
-
#ls_dirs ⇒ Object
Returns all the directories in this path.
-
#ls_files ⇒ Object
Returns all the files in this path.
-
#ls_R ⇒ Object
Returns all files in this path's directory and its subdirectories.
-
#ls_r(symlinks = false) ⇒ Object
Returns all files in this path's directory and its subdirectories.
- #lstat ⇒ Object
-
#magic ⇒ Object
Find the file's mimetype (by magic).
- #md5 ⇒ Object (also: #md5sum)
-
#mimetype ⇒ Object
(also: #identify)
Find the file's mimetype (first from file extension, then by magic).
-
#mimetype_from_ext ⇒ Object
Find the file's mimetype (only using the file extension).
-
#mkcd(&block) ⇒ Object
Path.mkcd(self).
- #mode ⇒ Object
- #mtime ⇒ Object
- #mtime=(new_mtime) ⇒ Object
-
#mv(arg) ⇒ Object
(also: #move)
Works the same as “rename”, but the destination can be on another disk.
-
#mv!(arg) ⇒ Object
(also: #move!)
Moves the file (overwriting the destination if it already exists).
- #name ⇒ Object
-
#numbered_backup! ⇒ Object
Rename this file, “filename.ext”, to “filename (1).ext” (or (2), or (3), or whatever number is available.) (Does not modify this Path object.).
-
#numbered_backup_file ⇒ Object
Find a backup filename that doesn't exist yet by appending “(1)”, “(2)”, etc.
-
#open(mode = "rb", &block) ⇒ Object
(also: #io, #stream)
Open the file (default: read-only + binary mode).
-
#owner? ⇒ Boolean
FIXME: Does the current user own this file?.
-
#parent ⇒ Object
Find the parent directory.
- #parent_of?(child) ⇒ Boolean
-
#parse(io = self.io, forced_ext = nil, opts = {}) ⇒ Object
Parse the file based on the file extension.
-
#parse_lines ⇒ Object
Treat each line of the file as a json object, and parse them all, returning an array of hashes.
-
#path ⇒ Object
(also: #to_path, #to_str, #to_s, #pathname)
Joins and returns the full path.
-
#path=(newpath, hints = {}) ⇒ Object
This is the core that initializes the whole class.
-
#puts(data = nil) ⇒ Object
Append data, with a newline at the end.
-
#read(length = nil, offset = nil) ⇒ Object
Read bytes from the file (just a wrapper around File.read).
-
#read_bson(io = self.io) ⇒ Object
Parse the file as BSON.
-
#read_csv(io = self.io, opts = {}) ⇒ Object
(also: #from_csv)
Parse the file as CSV.
- #read_html(io = self.io) ⇒ Object (also: #from_html)
-
#read_json(io = self.io) ⇒ Object
(also: #from_json)
Parse the file as JSON.
-
#read_marshal(io = self.io) ⇒ Object
Parse the file as a Ruby Marshal dump.
-
#read_xml(io = self.io) ⇒ Object
Parse the file as XML.
-
#read_yaml(io = self.io) ⇒ Object
(also: #from_yaml)
Parse the file as YAML.
- #readable? ⇒ Boolean
- #realpath ⇒ Object
-
#relative ⇒ Object
Path relative to current directory (Path.pwd).
-
#relative? ⇒ Boolean
Is this a relative path?.
- #relative_to(anchor) ⇒ Object
-
#reload! ⇒ Object
Reload this path (updates cached values.).
-
#rename(arg) ⇒ Object
(also: #ren)
Renames the file, but doesn't change the current Path object, and returns a Path that points at the new filename.
-
#rename!(arg) ⇒ Object
(also: #ren!)
Rename the file and change this Path object so that it points to the destination file.
-
#reset! ⇒ Object
Clear out the internal state of this object, so that it can be reinitialized.
-
#rm ⇒ Object
(also: #delete!, #unlink!, #remove!)
Remove a file or directory.
-
#sha1 ⇒ Object
(also: #sha1sum)
Checksums.
- #sha2 ⇒ Object (also: #sha2sum)
- #sha256 ⇒ Object (also: #sha256sum)
-
#siblings ⇒ Object
Returns all neighbouring directories to this path.
- #size ⇒ Object
-
#sort_attrs ⇒ Object
An array of attributes which will be used sort paths (case insensitive, directories come first).
- #startswith(s) ⇒ Object
- #symlink? ⇒ Boolean
- #symlink_target ⇒ Object (also: #readlink, #target)
- #symlink_to ⇒ Object
-
#to_Path ⇒ Object
No-op (returns self).
-
#touch ⇒ Object
Like the unix `touch` command (if the file exists, update its timestamp, otherwise create a new file).
-
#truncate(offset = 0) ⇒ Object
Shrink or expand the size of a file in-place.
-
#type ⇒ Object
Returns the filetype (as a standard file extension), verified with Magic.
- #unmarshal ⇒ Object
- #update(other) ⇒ Object
- #uri? ⇒ Boolean
- #url? ⇒ Boolean
- #writable? ⇒ Boolean
-
#write(data = nil) ⇒ Object
Overwrite the data in this file (accepts a string, an IO, or it can yield the file handle to a block.).
-
#write_bson(object) ⇒ Object
Serilize an object to BSON format and write it to this path.
-
#write_json(object) ⇒ Object
Convert the object to JSON and write it to the file (overwriting the existing file).
-
#write_marshal(object) ⇒ Object
Serilize an object to Ruby Marshal format and write it to this path.
-
#write_yaml(object) ⇒ Object
Convert the object to YAML and write it to the file (overwriting the existing file).
-
#zopen(mode = "rb", &block) ⇒ Object
A mutation of “open” that lets you read/write gzip files, as well as regular files.
Methods included from Enumerable
#*, #**, #average, #blank?, #combination, #counts, #cross_product, #foldl, #group_neighbours_by, #grouped_to_h, #groups, #map_recursively, #parallel_map, #permutation, #powerset, #reverse, #reverse_each, #rle, #rzip, #select_recursively, #skip, #sort_numerically, #split_after, #split_at, #split_before, #split_between, #sum, #to_iter, #uniq, #unzip
Constructor Details
#initialize(newpath, hints = {}) ⇒ Path
Initializers
127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/epitools/path.rb', line 127 def initialize(newpath, hints={}) send("path=", newpath, hints) # if hints[:unlink_when_garbage_collected] # backup_path = path.dup # puts "unlinking #{backup_path} after gc!" # ObjectSpace.define_finalizer self do |object_id| # File.unlink backup_path # end # end end |
Instance Attribute Details
#base ⇒ Object Also known as: basename
The filename without an extension
117 118 119 |
# File 'lib/epitools/path.rb', line 117 def base @base end |
#dirs ⇒ Object
The directories in the path, split into an array. (eg: ['usr', 'src', 'linux'])
114 115 116 |
# File 'lib/epitools/path.rb', line 114 def dirs @dirs end |
#ext ⇒ Object Also known as: extname, extension
The file extension, including the . (eg: “.mp3”)
120 121 122 |
# File 'lib/epitools/path.rb', line 120 def ext @ext end |
Class Method Details
.[](path) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/epitools/path.rb', line 153 def self.[](path) case path when Path path when String if path =~ %r{^[a-z\-]+://}i # URL? Path::URI.new(path) else # TODO: highlight backgrounds of codeblocks to show indent level & put boxes (or rules?) around (between?) double-spaced regions path = Path.(path) unless path =~ /(^|[^\\])[\?\*\{\}]/ # contains unescaped glob chars? new(path) else glob(path) end end end end |
.cd(dest) ⇒ Object
Change into the directory “dest”. If a block is given, it changes into the directory for the duration of the block, then puts you back where you came from once the block is finished.
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 |
# File 'lib/epitools/path.rb', line 1543 def self.cd(dest) dest = Path[dest] raise "Can't 'cd' into #{dest}" unless dest.dir? if block_given? orig = pwd Dir.chdir(dest) result = yield dest Dir.chdir(orig) result else Dir.chdir(dest) dest end end |
.escape(str) ⇒ Object
145 146 147 |
# File 'lib/epitools/path.rb', line 145 def self.escape(str) Shellwords.escape(str) end |
.expand_path(orig_path) ⇒ Object
Same as File.expand_path, except preserves the trailing '/'.
1486 1487 1488 1489 1490 |
# File 'lib/epitools/path.rb', line 1486 def self.(orig_path) new_path = File. orig_path new_path << "/" if orig_path.endswith "/" new_path end |
.getfattr(path) ⇒ Object
Read xattrs from file (requires “getfattr” to be in the path)
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
# File 'lib/epitools/path.rb', line 531 def self.getfattr(path) # # file: Scissor_Sisters_-_Invisible_Light.flv # user.m.options="-c" cmd = %w[getfattr -d -m - -e base64] + [path] attrs = {} IO.popen(cmd, "rb", :err=>[:child, :out]) do |io| io.each_line do |line| if line =~ /^([^=]+)=0s(.+)/ key = $1 value = $2.from_base64 # unpack base64 string # value = value.encode("UTF-8", "UTF-8") # set string's encoding to UTF-8 value = value.force_encoding("UTF-8").scrub # set string's encoding to UTF-8 # value = value.encode("UTF-8", "UTF-8") # set string's encoding to UTF-8 attrs[key] = value end end end attrs end |
.glob(str, hints = {}) ⇒ Object
149 150 151 |
# File 'lib/epitools/path.rb', line 149 def self.glob(str, hints={}) Dir[str].map { |entry| new(entry, hints) } end |
.home ⇒ Object
User's current home directory
1517 1518 1519 |
# File 'lib/epitools/path.rb', line 1517 def self.home Path[ENV['HOME']] end |
.ln_s(src, dest) ⇒ Object
1566 1567 1568 1569 |
# File 'lib/epitools/path.rb', line 1566 def self.ln_s(src, dest) FileUtils.ln_s(src, dest) Path[dest] end |
.ls(path) ⇒ Object
1562 |
# File 'lib/epitools/path.rb', line 1562 def self.ls(path); Path[path].ls end |
.ls_r(path) ⇒ Object
1564 |
# File 'lib/epitools/path.rb', line 1564 def self.ls_r(path); Path[path].ls_r; end |
.mkcd(path, &block) ⇒ Object
Path.mkcd(path) creates a path if it doesn't exist, and changes to it (temporarily, if a block is provided)
1116 1117 1118 1119 1120 1121 1122 1123 |
# File 'lib/epitools/path.rb', line 1116 def self.mkcd(path, &block) path = path.to_Path unless path.is_a? Path path.mkdir_p unless path.exists? raise "Error: #{path} couldn't be created." unless path.dir? self.cd(path, &block) end |
.popd ⇒ Object
1533 1534 1535 1536 |
# File 'lib/epitools/path.rb', line 1533 def self.popd @@dir_stack ||= [pwd] @@dir_stack.pop end |
.pushd(destination) ⇒ Object
1528 1529 1530 1531 |
# File 'lib/epitools/path.rb', line 1528 def self.pushd(destination) @@dir_stack ||= [] @@dir_stack.push pwd end |
.pwd ⇒ Object
The current directory
1524 1525 1526 |
# File 'lib/epitools/path.rb', line 1524 def self.pwd Path.new (Dir.pwd) end |
.setfattr(path, key, value) ⇒ Object
Set xattrs on a file (requires “setfattr” to be in the path)
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 |
# File 'lib/epitools/path.rb', line 559 def self.setfattr(path, key, value) cmd = %w[setfattr] if value == nil # delete cmd += ["-x", key] else # set cmd += ["-n", key, "-v", value.to_s.strip] end cmd << path IO.popen(cmd, "rb", :err=>[:child, :out]) do |io| result = io.each_line.to_a error = {:cmd => cmd, :result => result.to_s}.inspect raise error if result.any? end end |
.tmpdir(prefix = "tmp") ⇒ Object
Create a uniqely named directory in /tmp
1507 1508 1509 1510 1511 |
# File 'lib/epitools/path.rb', line 1507 def self.tmpdir(prefix="tmp") t = tmpfile t.rm; t.mkdir # FIXME: These two operations should be made atomic t end |
.tmpfile(prefix = "tmp") {|path| ... } ⇒ Object
TODO: Remove the tempfile when the Path object is garbage collected or freed.
1495 1496 1497 1498 1499 |
# File 'lib/epitools/path.rb', line 1495 def self.tmpfile(prefix="tmp") path = Path.new(Tempfile.new(prefix).path, unlink_when_garbage_collected: true) yield path if block_given? path end |
.which(bin, *extras) ⇒ Object
A clone of `/usr/bin/which`: pass in the name of a binary, and it'll search the PATH returning the absolute location of the binary if it exists, or `nil` otherwise.
(Note: If you pass more than one argument, it'll return an array of `Path`s instead of
a single path.)
1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 |
# File 'lib/epitools/path.rb', line 1590 def self.which(bin, *extras) if extras.empty? ENV["PATH"].split(PATH_SEPARATOR).find do |path| result = (Path[path] / (bin + BINARY_EXTENSION)) return result if result.exists? end nil else ([bin] + extras).map { |bin| which(bin) } end end |
Instance Method Details
#/(other) ⇒ Object
517 518 519 520 521 522 |
# File 'lib/epitools/path.rb', line 517 def /(other) # / <- fixes jedit syntax highlighting bug. # TODO: make it work for "/dir/dir"/"/dir/file" #Path.new( File.join(self, other) ) Path[ File.join(self, other) ] end |
#<=>(other) ⇒ Object
483 484 485 486 487 488 489 490 491 492 |
# File 'lib/epitools/path.rb', line 483 def <=>(other) case other when Path sort_attrs <=> other.sort_attrs when String path <=> other else raise "Invalid comparison: Path to #{other.class}" end end |
#==(other) ⇒ Object Also known as: eql?
494 495 496 |
# File 'lib/epitools/path.rb', line 494 def ==(other) self.path == other.to_s end |
#=~(pattern) ⇒ Object
Match the full path against a regular expression
1329 1330 1331 |
# File 'lib/epitools/path.rb', line 1329 def =~(pattern) to_s =~ pattern end |
#[](key) ⇒ Object
Retrieve one of this file's xattrs
611 612 613 |
# File 'lib/epitools/path.rb', line 611 def [](key) attrs[key] end |
#[]=(key, value) ⇒ Object
Set this file's xattr
618 619 620 621 |
# File 'lib/epitools/path.rb', line 618 def []=(key, value) Path.setfattr(path, key, value) @attrs = nil # clear cached xattrs end |
#append(data = nil) ⇒ Object Also known as: <<
Append data to this file (accepts a string, an IO, or it can yield the file handle to a block.)
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 |
# File 'lib/epitools/path.rb', line 744 def append(data=nil) # FIXME: copy_stream might be inefficient if you're calling it a lot. Investigate! self.open("ab") do |f| if data and not block_given? if data.is_an? IO IO.copy_stream(data, f) else f.write(data) end else yield f end end self end |
#atime ⇒ Object
392 393 394 |
# File 'lib/epitools/path.rb', line 392 def atime lstat.atime end |
#atime=(new_atime) ⇒ Object
396 397 398 399 400 |
# File 'lib/epitools/path.rb', line 396 def atime=(new_atime) File.utime(new_atime, mtime, path) @lstat = nil new_atime end |
#attrs ⇒ Object Also known as: xattrs
Return a hash of all of this file's xattrs. (Metadata key=>valuse pairs, supported by most modern filesystems.)
583 584 585 |
# File 'lib/epitools/path.rb', line 583 def attrs @attrs ||= Path.getfattr(path) end |
#attrs=(new_attrs) ⇒ Object
Set this file's xattrs. (Optimized so that only changed attrs are written to disk.)
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 |
# File 'lib/epitools/path.rb', line 591 def attrs=(new_attrs) changes = attrs.diff(new_attrs) changes.each do |key, (old, new)| case new when String, Numeric, true, false, nil self[key] = new else if new.respond_to? :to_str self[key] = new.to_str else raise "Error: Can't use a #{new.class} as an xattr value. Try passing a String." end end end end |
#backup! ⇒ Object
Rename this file, “filename.ext”, to “filename.ext.bak”. (Does not modify this Path object.)
1085 1086 1087 |
# File 'lib/epitools/path.rb', line 1085 def backup! rename(backup_file) end |
#backup_file ⇒ Object
Return a copy of this Path with “.bak” at the end
1069 1070 1071 |
# File 'lib/epitools/path.rb', line 1069 def backup_file with(:filename => filename+".bak") end |
#broken_symlink? ⇒ Boolean
432 433 434 |
# File 'lib/epitools/path.rb', line 432 def broken_symlink? File.symlink?(path) and not File.exists?(path) end |
#cd(&block) ⇒ Object
Change into the directory. If a block is given, it changes into the directory for the duration of the block, then puts you back where you came from once the block is finished.
979 980 981 |
# File 'lib/epitools/path.rb', line 979 def cd(&block) Path.cd(path, &block) end |
#child_of?(parent) ⇒ Boolean
455 456 457 |
# File 'lib/epitools/path.rb', line 455 def child_of?(parent) parent.parent_of? self end |
#chmod(mode) ⇒ Object
Same usage as `FileUtils.chmod` (because it just calls `FileUtils.chmod`)
eg:
path.chmod(0600) # mode bits in octal (can also be 0o600 in ruby)
path.chmod "u=wrx,go=rx", 'somecommand'
path.chmod "u=wr,go=rr", "my.rb", "your.rb", "his.rb", "her.rb"
path.chmod "ugo=rwx", "slutfile"
path.chmod "u=wrx,g=rx,o=rx", '/usr/bin/ruby', :verbose => true
Letter things:
"a" :: is user, group, other mask.
"u" :: is user's mask.
"g" :: is group's mask.
"o" :: is other's mask.
"w" :: is write permission.
"r" :: is read permission.
"x" :: is execute permission.
"X" :: is execute permission for directories only, must be used in conjunction with "+"
"s" :: is uid, gid.
"t" :: is sticky bit.
"+" :: is added to a class given the specified mode.
"-" :: Is removed from a given class given mode.
"=" :: Is the exact nature of the class will be given a specified mode.
1193 1194 1195 1196 |
# File 'lib/epitools/path.rb', line 1193 def chmod(mode) FileUtils.chmod(mode, self) self end |
#chmod_R(mode) ⇒ Object
1204 1205 1206 1207 1208 1209 1210 1211 |
# File 'lib/epitools/path.rb', line 1204 def chmod_R(mode) if directory? FileUtils.chmod_R(mode, self) self else raise "Not a directory." end end |
#chown(usergroup) ⇒ Object
1198 1199 1200 1201 1202 |
# File 'lib/epitools/path.rb', line 1198 def chown(usergroup) user, group = usergroup.split(":") FileUtils.chown(user, group, self) self end |
#chown_R(usergroup) ⇒ Object
1213 1214 1215 1216 1217 1218 1219 1220 1221 |
# File 'lib/epitools/path.rb', line 1213 def chown_R(usergroup) user, group = usergroup.split(":") if directory? FileUtils.chown_R(user, group, self) self else raise "Not a directory." end end |
#cp(dest) ⇒ Object
1151 1152 1153 1154 |
# File 'lib/epitools/path.rb', line 1151 def cp(dest) FileUtils.cp(path, dest) dest end |
#cp_p(dest) ⇒ Object
Copy a file to a destination, creating all intermediate directories if they don't already exist
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 |
# File 'lib/epitools/path.rb', line 1140 def cp_p(dest) FileUtils.mkdir_p(dest.dir) unless File.directory? dest.dir if file? FileUtils.cp(path, dest) elsif dir? FileUtils.cp_r(path, dest) end dest end |
#cp_r(dest) ⇒ Object
1132 1133 1134 1135 |
# File 'lib/epitools/path.rb', line 1132 def cp_r(dest) FileUtils.cp_r(path, dest) #if Path[dest].exists? dest end |
#ctime ⇒ Object
388 389 390 |
# File 'lib/epitools/path.rb', line 388 def ctime lstat.ctime end |
#deflate(level = nil) ⇒ Object Also known as: gzip
gzip the file, returning the result as a string
1276 1277 1278 |
# File 'lib/epitools/path.rb', line 1276 def deflate(level=nil) Zlib.deflate(read, level) end |
#dir ⇒ Object Also known as: dirname, directory
The current directory (with a trailing /)
313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/epitools/path.rb', line 313 def dir if dirs if relative? File.join(*dirs) else File.join("", *dirs) end else nil end end |
#dir=(newdir) ⇒ Object Also known as: dirname=, directory=
229 230 231 232 233 234 |
# File 'lib/epitools/path.rb', line 229 def dir=(newdir) dirs = File.(newdir).split(File::SEPARATOR) dirs = dirs[1..-1] if dirs.size > 0 @dirs = dirs end |
#dir? ⇒ Boolean Also known as: directory?
420 421 422 |
# File 'lib/epitools/path.rb', line 420 def dir? File.directory? path end |
#each_chunk(chunk_size = 2**14) ⇒ Object
Read the contents of a file one chunk at a time (default chunk size is 16k)
650 651 652 653 654 |
# File 'lib/epitools/path.rb', line 650 def each_chunk(chunk_size=2**14) open do |io| yield io.read(chunk_size) until io.eof? end end |
#each_line ⇒ Object Also known as: each, lines, nicelines, nice_lines
All the lines in this file, chomped.
660 661 662 663 |
# File 'lib/epitools/path.rb', line 660 def each_line return to_enum(:each_line) unless block_given? open { |io| io.each_line { |line| yield line.chomp } } end |
#endswith(s) ⇒ Object
1345 |
# File 'lib/epitools/path.rb', line 1345 def endswith(s); path.endswith(s); end |
#executable? ⇒ Boolean Also known as: exe?
407 408 409 |
# File 'lib/epitools/path.rb', line 407 def executable? mode & 0o111 > 0 end |
#exists? ⇒ Boolean Also known as: exist?
fstat
359 360 361 |
# File 'lib/epitools/path.rb', line 359 def exists? File.exists? path end |
#exts ⇒ Object
341 342 343 344 345 |
# File 'lib/epitools/path.rb', line 341 def exts extensions = basename.split('.')[1..-1] extensions += [@ext] if @ext extensions end |
#file? ⇒ Boolean
424 425 426 |
# File 'lib/epitools/path.rb', line 424 def file? File.file? path end |
#filename ⇒ Object
325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/epitools/path.rb', line 325 def filename if base if ext base + "." + ext else base end else nil end end |
#filename=(newfilename) ⇒ Object
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/epitools/path.rb', line 211 def filename=(newfilename) if newfilename.nil? @ext, @base = nil, nil else ext = File.extname(newfilename) if ext.blank? @ext = nil @base = newfilename else self.ext = ext if pos = newfilename.rindex(ext) @base = newfilename[0...pos] end end end end |
#grep(pat) ⇒ Object
Yields all matching lines in the file (by returning an Enumerator, or receiving a block)
673 674 675 676 677 678 679 |
# File 'lib/epitools/path.rb', line 673 def grep(pat) return to_enum(:grep, pat).to_a unless block_given? each_line do |line| yield line if line[pat] end end |
#gunzip! ⇒ Object
Quickly gunzip a file, creating a new file, without removing the original, and returning a Path to that new file.
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 |
# File 'lib/epitools/path.rb', line 1312 def gunzip! raise "Not a .gz file" unless ext == "gz" regular_file = self.with(:ext=>nil) regular_file.open("wb") do |output| Zlib::GzipReader.open(self) do |gzreader| IO.copy_stream(gzreader, output) end end update(regular_file) end |
#gzip!(level = nil) ⇒ Object
Quickly gzip a file, creating a new .gz file, without removing the original, and returning a Path to that new file.
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 |
# File 'lib/epitools/path.rb', line 1294 def gzip!(level=nil) gz_file = self.with(:filename=>filename+".gz") raise "#{gz_file} already exists" if gz_file.exists? open("rb") do |input| Zlib::GzipWriter.open(gz_file) do |gzwriter| IO.copy_stream(input, gzwriter) end end update(gz_file) end |
#hash ⇒ Object
499 |
# File 'lib/epitools/path.rb', line 499 def hash; path.hash; end |
#hidden? ⇒ Boolean
Does the file or directory name start with a “.”?
466 467 468 469 |
# File 'lib/epitools/path.rb', line 466 def hidden? thing = filename ? filename : dirs.last !!thing[/^\../] end |
#id3 ⇒ Object Also known as:
Read ID3 tags (requires 'id3tag' gem)
Available fields:
tag.artist, tag.title, tag.album, tag.year, tag.track_nr, tag.genre, tag.get_frame(:TIT2)&.content,
tag.get_frames(:COMM).first&.content, tag.get_frames(:COMM).last&.language
969 970 971 |
# File 'lib/epitools/path.rb', line 969 def id3 ID3Tag.read(io) end |
#inflate ⇒ Object Also known as: gunzip
gunzip the file, returning the result as a string
1285 1286 1287 |
# File 'lib/epitools/path.rb', line 1285 def inflate Zlib.inflate(read) end |
#initialize_copy(other) ⇒ Object
139 140 141 142 143 |
# File 'lib/epitools/path.rb', line 139 def initialize_copy(other) @dirs = other.dirs && other.dirs.dup @base = other.base && other.base.dup @ext = other.ext && other.ext.dup end |
#inspect ⇒ Object
inspect
351 352 353 |
# File 'lib/epitools/path.rb', line 351 def inspect "#<Path:#{path}>" end |
#join(other) ⇒ Object
Path.join(“anything{}”).path == “/etc/anything{}” (globs ignored)
509 510 511 |
# File 'lib/epitools/path.rb', line 509 def join(other) Path.new File.join(self, other) end |
#ln_s(dest) ⇒ Object
1156 1157 1158 1159 1160 1161 1162 |
# File 'lib/epitools/path.rb', line 1156 def ln_s(dest) if dest.startswith("/") Path.ln_s(self, dest) else Path.ln_s(self, self / dest) end end |
#ls ⇒ Object
Returns all the files in the directory that this path points to
688 689 690 691 692 |
# File 'lib/epitools/path.rb', line 688 def ls Dir.foreach(path). reject {|fn| fn == "." or fn == ".." }. flat_map {|fn| self / fn } end |
#ls_dirs ⇒ Object
Returns all the directories in this path
707 708 709 710 |
# File 'lib/epitools/path.rb', line 707 def ls_dirs ls.select(&:dir?) #Dir.glob("#{path}*/", File::FNM_DOTMATCH).map { |s| Path.new(s, :type=>:dir) } end |
#ls_files ⇒ Object
Returns all the files in this path
715 716 717 718 |
# File 'lib/epitools/path.rb', line 715 def ls_files ls.select(&:file?) #Dir.glob("#{path}*", File::FNM_DOTMATCH).map { |s| Path.new(s, :type=>:file) } end |
#ls_R ⇒ Object
Returns all files in this path's directory and its subdirectories
702 703 704 705 706 |
# File 'lib/epitools/path.rb', line 702 def ls_r(symlinks=false) # glob = symlinks ? "**{,/*/**}/*" : "**/*" # Path[File.join(path, glob)] Find.find(path).drop(1).map {|fn| Path.new(fn) } end |
#ls_r(symlinks = false) ⇒ Object
Returns all files in this path's directory and its subdirectories
697 698 699 700 701 |
# File 'lib/epitools/path.rb', line 697 def ls_r(symlinks=false) # glob = symlinks ? "**{,/*/**}/*" : "**/*" # Path[File.join(path, glob)] Find.find(path).drop(1).map {|fn| Path.new(fn) } end |
#lstat ⇒ Object
369 370 371 372 |
# File 'lib/epitools/path.rb', line 369 def lstat @lstat ||= File.lstat self # to cache, or not to cache? that is the question. # File.lstat self # ...answer: not to cache! end |
#magic ⇒ Object
Find the file's mimetype (by magic)
1380 1381 1382 |
# File 'lib/epitools/path.rb', line 1380 def magic open { |io| MimeMagic.by_magic(io) } end |
#md5 ⇒ Object Also known as: md5sum
1261 1262 1263 |
# File 'lib/epitools/path.rb', line 1261 def md5 Digest::MD5.file(self).hexdigest end |
#mimetype ⇒ Object Also known as: identify
Find the file's mimetype (first from file extension, then by magic)
1365 1366 1367 |
# File 'lib/epitools/path.rb', line 1365 def mimetype mimetype_from_ext || magic end |
#mimetype_from_ext ⇒ Object
Find the file's mimetype (only using the file extension)
1373 1374 1375 |
# File 'lib/epitools/path.rb', line 1373 def mimetype_from_ext MimeMagic.by_extension(ext) end |
#mkcd(&block) ⇒ Object
Path.mkcd(self)
1128 1129 1130 |
# File 'lib/epitools/path.rb', line 1128 def mkcd(&block) Path.mkcd(self, &block) end |
#mode ⇒ Object
374 375 376 |
# File 'lib/epitools/path.rb', line 374 def mode lstat.mode end |
#mtime ⇒ Object
378 379 380 |
# File 'lib/epitools/path.rb', line 378 def mtime lstat.mtime end |
#mtime=(new_mtime) ⇒ Object
382 383 384 385 386 |
# File 'lib/epitools/path.rb', line 382 def mtime=(new_mtime) File.utime(atime, new_mtime, path) @lstat = nil new_mtime end |
#mv(arg) ⇒ Object Also known as: move
Works the same as “rename”, but the destination can be on another disk.
1022 1023 1024 1025 1026 1027 1028 1029 |
# File 'lib/epitools/path.rb', line 1022 def mv(arg) dest = arg_to_path(arg) raise "Error: can't move #{self.inspect} because source location doesn't exist." unless exists? FileUtils.mv(path, dest) dest end |
#mv!(arg) ⇒ Object Also known as: move!
Moves the file (overwriting the destination if it already exists). Also points the current Path object at the new destination.
1043 1044 1045 |
# File 'lib/epitools/path.rb', line 1043 def mv!(arg) update(mv(arg)) end |
#name ⇒ Object
337 338 339 |
# File 'lib/epitools/path.rb', line 337 def name filename || "#{dirs.last}/" end |
#numbered_backup! ⇒ Object
Rename this file, “filename.ext”, to “filename (1).ext” (or (2), or (3), or whatever number is available.) (Does not modify this Path object.)
1077 1078 1079 |
# File 'lib/epitools/path.rb', line 1077 def numbered_backup! rename(numbered_backup_file) end |
#numbered_backup_file ⇒ Object
Find a backup filename that doesn't exist yet by appending “(1)”, “(2)”, etc. to the current filename.
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 |
# File 'lib/epitools/path.rb', line 1051 def numbered_backup_file return self unless exists? n = 1 loop do if dir? new_file = with(:dirs => dirs[0..-2] + ["#{dirs.last} (#{n})"]) else new_file = with(:basename => "#{basename} (#{n})") end return new_file unless new_file.exists? n += 1 end end |
#open(mode = "rb", &block) ⇒ Object Also known as: io, stream
Open the file (default: read-only + binary mode)
630 631 632 633 634 635 636 |
# File 'lib/epitools/path.rb', line 630 def open(mode="rb", &block) if block_given? File.open(path, mode, &block) else File.open(path, mode) end end |
#owner? ⇒ Boolean
FIXME: Does the current user own this file?
403 404 405 |
# File 'lib/epitools/path.rb', line 403 def owner? raise "STUB" end |
#parent ⇒ Object
Find the parent directory. If the `Path` is a filename, it returns the containing directory.
1336 1337 1338 1339 1340 1341 1342 |
# File 'lib/epitools/path.rb', line 1336 def parent if file? with(:filename=>nil) else with(:dirs=>dirs[0...-1]) end end |
#parent_of?(child) ⇒ Boolean
459 460 461 |
# File 'lib/epitools/path.rb', line 459 def parent_of?(child) dirs == child.dirs[0...dirs.size] end |
#parse(io = self.io, forced_ext = nil, opts = {}) ⇒ Object
Parse the file based on the file extension. (Handles json, html, yaml, xml, csv, marshal, and bson.)
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 |
# File 'lib/epitools/path.rb', line 870 def parse(io=self.io, forced_ext=nil, opts={}) case (forced_ext or ext.downcase) when 'gz', 'bz2', 'xz' parse(zopen, exts[-2]) when 'json' read_json(io) when 'html', 'htm' read_html(io) when 'yaml', 'yml' read_yaml(io) when 'xml', 'rdf', 'rss' read_xml(io) when 'csv' read_csv(io, opts) when 'marshal' read_marshal(io) when 'bson' read_bson(io) else raise "Unrecognized format: #{ext}" end end |
#parse_lines ⇒ Object
Treat each line of the file as a json object, and parse them all, returning an array of hashes
896 897 898 |
# File 'lib/epitools/path.rb', line 896 def parse_lines each_line.map { |line| JSON.parse line } end |
#path ⇒ Object Also known as: to_path, to_str, to_s, pathname
Joins and returns the full path
282 283 284 285 286 287 288 |
# File 'lib/epitools/path.rb', line 282 def path if d = dir File.join(d, (filename || "") ) else "" end end |
#path=(newpath, hints = {}) ⇒ Object
This is the core that initializes the whole class.
Note: The `hints` parameter contains options so `path=` doesn't have to touch the filesytem as much.
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/epitools/path.rb', line 188 def path=(newpath, hints={}) if hints[:type] or File.exists? newpath if hints[:type] == :dir or File.directory? newpath self.dir = newpath else self.dir, self.filename = File.split(newpath) end else if newpath.endswith(File::SEPARATOR) # ends in '/' self.dir = newpath else self.dir, self.filename = File.split(newpath) end end # FIXME: Make this work with globs. if hints[:relative] update(relative_to(Path.pwd)) elsif hints[:relative_to] update(relative_to(hints[:relative_to])) end end |
#puts(data = nil) ⇒ Object
Append data, with a newline at the end
764 765 766 767 |
# File 'lib/epitools/path.rb', line 764 def puts(data=nil) append data append "\n" unless data and data[-1] == "\n" end |
#read(length = nil, offset = nil) ⇒ Object
Read bytes from the file (just a wrapper around File.read)
643 644 645 |
# File 'lib/epitools/path.rb', line 643 def read(length=nil, offset=nil) File.read(path, length, offset) end |
#read_bson(io = self.io) ⇒ Object
Parse the file as BSON
953 954 955 |
# File 'lib/epitools/path.rb', line 953 def read_bson(io=self.io) BSON.deserialize(read) end |
#read_csv(io = self.io, opts = {}) ⇒ Object Also known as: from_csv
Parse the file as CSV
932 933 934 |
# File 'lib/epitools/path.rb', line 932 def read_csv(io=self.io, opts={}) open { |io| CSV.new(io.read, opts).each } end |
#read_html(io = self.io) ⇒ Object Also known as: from_html
913 914 915 |
# File 'lib/epitools/path.rb', line 913 def read_html(io=self.io) Nokogiri::HTML(io) end |
#read_json(io = self.io) ⇒ Object Also known as: from_json
Parse the file as JSON
902 903 904 |
# File 'lib/epitools/path.rb', line 902 def read_json(io=self.io) JSON.load(io) end |
#read_marshal(io = self.io) ⇒ Object
Parse the file as a Ruby Marshal dump
943 944 945 |
# File 'lib/epitools/path.rb', line 943 def read_marshal(io=self.io) Marshal.load(io) end |
#read_xml(io = self.io) ⇒ Object
Parse the file as XML
938 939 940 |
# File 'lib/epitools/path.rb', line 938 def read_xml(io=self.io) Nokogiri::XML(io) end |
#read_yaml(io = self.io) ⇒ Object Also known as: from_yaml
Parse the file as YAML
925 926 927 |
# File 'lib/epitools/path.rb', line 925 def read_yaml(io=self.io) YAML.load(io) end |
#readable? ⇒ Boolean
416 417 418 |
# File 'lib/epitools/path.rb', line 416 def readable? mode & 0o444 > 0 end |
#realpath ⇒ Object
1351 1352 1353 |
# File 'lib/epitools/path.rb', line 1351 def realpath Path.new File.realpath(path) end |
#relative ⇒ Object
Path relative to current directory (Path.pwd)
302 303 304 |
# File 'lib/epitools/path.rb', line 302 def relative relative_to(pwd) end |
#relative? ⇒ Boolean
Is this a relative path?
293 294 295 296 297 |
# File 'lib/epitools/path.rb', line 293 def relative? # FIXME: Need a Path::Relative subclass, so that "dir/filename" can be valid. # (If the user changes dirs, the relative path should change too.) dirs.first == ".." end |
#relative_to(anchor) ⇒ Object
306 307 308 309 310 |
# File 'lib/epitools/path.rb', line 306 def relative_to(anchor) anchor = anchor.to_s anchor += "/" unless anchor[/\/$/] to_s.gsub(/^#{Regexp.escape(anchor)}/, '') end |
#reload! ⇒ Object
Reload this path (updates cached values.)
264 265 266 267 268 269 270 271 |
# File 'lib/epitools/path.rb', line 264 def reload! temp = path reset! self.path = temp @attrs = nil self end |
#rename(arg) ⇒ Object Also known as: ren
Renames the file, but doesn't change the current Path object, and returns a Path that points at the new filename.
Examples:
Path["file"].rename("newfile") #=> Path["newfile"]
Path["SongySong.mp3"].rename(:basename=>"Songy Song")
Path["Songy Song.mp3"].rename(:ext=>"aac")
Path["Songy Song.aac"].rename(:dir=>"/music2")
Path["/music2/Songy Song.aac"].exists? #=> true
1008 1009 1010 1011 1012 1013 1014 1015 1016 |
# File 'lib/epitools/path.rb', line 1008 def rename(arg) dest = arg_to_path(arg) raise "Error: destination (#{dest.inspect}) already exists" if dest.exists? raise "Error: can't rename #{self.inspect} because source location doesn't exist." unless exists? File.rename(path, dest) dest end |
#rename!(arg) ⇒ Object Also known as: ren!
Rename the file and change this Path object so that it points to the destination file.
1035 1036 1037 |
# File 'lib/epitools/path.rb', line 1035 def rename!(arg) update(rename(arg)) end |
#reset! ⇒ Object
Clear out the internal state of this object, so that it can be reinitialized.
256 257 258 259 |
# File 'lib/epitools/path.rb', line 256 def reset! [:@dirs, :@base, :@ext].each { |var| remove_instance_variable(var) rescue nil } self end |
#rm ⇒ Object Also known as: delete!, unlink!, remove!
Remove a file or directory
1228 1229 1230 1231 1232 1233 1234 1235 1236 |
# File 'lib/epitools/path.rb', line 1228 def rm raise "Error: #{self} does not exist" unless symlink? or exists? if directory? and not symlink? Dir.rmdir(self) == 0 else File.unlink(self) == 1 end end |
#sha1 ⇒ Object Also known as: sha1sum
Checksums
1251 1252 1253 |
# File 'lib/epitools/path.rb', line 1251 def sha1 Digest::SHA1.file(self).hexdigest end |
#sha2 ⇒ Object Also known as: sha2sum
1256 1257 1258 |
# File 'lib/epitools/path.rb', line 1256 def sha2 Digest::SHA2.file(self).hexdigest end |
#sha256 ⇒ Object Also known as: sha256sum
1266 1267 1268 |
# File 'lib/epitools/path.rb', line 1266 def sha256 Digest::SHA256.file(self).hexdigest end |
#siblings ⇒ Object
Returns all neighbouring directories to this path
723 724 725 |
# File 'lib/epitools/path.rb', line 723 def siblings Path[dir].ls - [self] end |
#size ⇒ Object
363 364 365 366 367 |
# File 'lib/epitools/path.rb', line 363 def size File.size(path) rescue Errno::ENOENT -1 end |
#sort_attrs ⇒ Object
An array of attributes which will be used sort paths (case insensitive, directories come first)
479 480 481 |
# File 'lib/epitools/path.rb', line 479 def sort_attrs [(filename ? 1 : 0), path.downcase] end |
#startswith(s) ⇒ Object
1344 |
# File 'lib/epitools/path.rb', line 1344 def startswith(s); path.startswith(s); end |
#symlink? ⇒ Boolean
428 429 430 |
# File 'lib/epitools/path.rb', line 428 def symlink? File.symlink? path end |
#symlink_target ⇒ Object Also known as: readlink, target
436 437 438 439 440 441 442 443 |
# File 'lib/epitools/path.rb', line 436 def symlink_target target = File.readlink(path.gsub(/\/$/, '')) if target.startswith("/") Path[target] else Path[dir] / target end end |
#symlink_to ⇒ Object
1164 1165 1166 1167 1168 1169 1170 |
# File 'lib/epitools/path.rb', line 1164 def ln_s(dest) if dest.startswith("/") Path.ln_s(self, dest) else Path.ln_s(self, self / dest) end end |
#to_Path ⇒ Object
No-op (returns self)
1605 1606 1607 |
# File 'lib/epitools/path.rb', line 1605 def to_Path self end |
#touch ⇒ Object
Like the unix `touch` command (if the file exists, update its timestamp, otherwise create a new file)
731 732 733 734 |
# File 'lib/epitools/path.rb', line 731 def touch open("a") { } self end |
#truncate(offset = 0) ⇒ Object
Shrink or expand the size of a file in-place
1244 1245 1246 |
# File 'lib/epitools/path.rb', line 1244 def truncate(offset=0) File.truncate(self, offset) if exists? end |
#type ⇒ Object
Returns the filetype (as a standard file extension), verified with Magic.
(In other words, this will give you the true extension, even if the file's extension is wrong.)
Note: Prefers long extensions (eg: jpeg over jpg)
TODO: rename type => magicext?
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 |
# File 'lib/epitools/path.rb', line 1394 def type @cached_type ||= begin if file? or symlink? ext = self.ext magic = self.magic if ext and magic if magic.extensions.include? ext ext else magic.ext # in case the supplied extension is wrong... end elsif !ext and magic magic.ext elsif ext and !magic ext else # !ext and !magic :unknown end elsif dir? :directory end end end |
#unmarshal ⇒ Object
681 682 683 |
# File 'lib/epitools/path.rb', line 681 def unmarshal read.unmarshal end |
#update(other) ⇒ Object
273 274 275 276 277 |
# File 'lib/epitools/path.rb', line 273 def update(other) @dirs = other.dirs @base = other.base @ext = other.ext end |
#uri? ⇒ Boolean
452 |
# File 'lib/epitools/path.rb', line 452 def uri?; false; end |
#url? ⇒ Boolean
453 |
# File 'lib/epitools/path.rb', line 453 def url?; uri?; end |
#writable? ⇒ Boolean
412 413 414 |
# File 'lib/epitools/path.rb', line 412 def writable? mode & 0o222 > 0 end |
#write(data = nil) ⇒ Object
Overwrite the data in this file (accepts a string, an IO, or it can yield the file handle to a block.)
772 773 774 775 776 777 778 779 780 781 782 783 784 |
# File 'lib/epitools/path.rb', line 772 def write(data=nil) self.open("wb") do |f| if data and not block_given? if data.is_an? IO IO.copy_stream(data, f) else f.write(data) end else yield f end end end |
#write_bson(object) ⇒ Object
Serilize an object to BSON format and write it to this path
958 959 960 |
# File 'lib/epitools/path.rb', line 958 def write_bson(object) write BSON.serialize(object) end |
#write_json(object) ⇒ Object
Convert the object to JSON and write it to the file (overwriting the existing file).
908 909 910 |
# File 'lib/epitools/path.rb', line 908 def write_json(object) write object.to_json end |
#write_marshal(object) ⇒ Object
Serilize an object to Ruby Marshal format and write it to this path
948 949 950 |
# File 'lib/epitools/path.rb', line 948 def write_marshal(object) write object.marshal end |
#write_yaml(object) ⇒ Object
Convert the object to YAML and write it to the file (overwriting the existing file).
920 921 922 |
# File 'lib/epitools/path.rb', line 920 def write_yaml(object) write object.to_yaml end |
#zopen(mode = "rb", &block) ⇒ Object
A mutation of “open” that lets you read/write gzip files, as well as regular files.
(NOTE: gzip detection is based on the filename, not the contents.)
It accepts a block just like open()!
Example:
zopen("test.txt") #=> #<File:test.txt>
zopen("test.txt.gz") #=> #<Zlib::GzipReader:0xb6c79424>
zopen("otherfile.gz", "w") #=> #<Zlib::GzipWriter:0x7fe30448>>
zopen("test.txt.gz") { |f| f.read } # read the contents of the .gz file, then close the file handle automatically.
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
# File 'lib/epitools/path.rb', line 810 def zopen(mode="rb", &block) # if ext == "gz" # io = open(mode) # case mode # when "r", "rb" # io = Zlib::GzipReader.new(io) # def io.to_str; read; end # when "w", "wb" # io = Zlib::GzipWriter.new(io) # else # raise "Unknown mode: #{mode.inspect}. zopen only supports 'r' and 'w'." # end # elsif bin = COMPRESSORS[ext] if bin = COMPRESSORS[ext] if which(bin) case mode when "w", "wb" # TODO: figure out how to pipe the compressor directly a file so we don't require a block raise "Error: Must supply a block when writing" unless block_given? IO.popen([bin, "-c"], "wb+") do |compressor| yield(compressor) compressor.close_write open("wb") { |output| IO.copy_stream(compressor, output) } end when "r", "rb" if block_given? IO.popen([bin, "-d" ,"-c", path], "rb", &block) else IO.popen([bin, "-d" ,"-c", path], "rb") end else raise "Error: Mode #{mode.inspect} not recognized" end else raise "Error: couldn't find #{bin.inspect} in the path" end else # io = open(path) raise "Error: #{ext.inspect} is an unsupported format" end # if block_given? # result = yield(io) # io.close # result # else # io # end end |