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
- URI_RE =
%r{^[a-z\-]+://}i
- 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).
-
.new(*args) ⇒ Object
Initializers.
- .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
A new instance of Path.
- #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
Methods included from Array::ToCSV
Constructor Details
#initialize(newpath, hints = {}) ⇒ Path
Returns a new instance of Path.
136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/epitools/path.rb', line 136 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
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/epitools/path.rb', line 162 def self.[](path) case path when Path path when String if path =~ URI_RE Path.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.
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 |
# File 'lib/epitools/path.rb', line 1552 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
154 155 156 |
# File 'lib/epitools/path.rb', line 154 def self.escape(str) Shellwords.escape(str) end |
.expand_path(orig_path) ⇒ Object
Same as File.expand_path, except preserves the trailing '/'.
1495 1496 1497 1498 1499 |
# File 'lib/epitools/path.rb', line 1495 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)
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'lib/epitools/path.rb', line 540 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
158 159 160 |
# File 'lib/epitools/path.rb', line 158 def self.glob(str, hints={}) Dir[str].map { |entry| new(entry, hints) } end |
.home ⇒ Object
User's current home directory
1526 1527 1528 |
# File 'lib/epitools/path.rb', line 1526 def self.home Path[ENV['HOME']] end |
.ln_s(src, dest) ⇒ Object
1575 1576 1577 1578 |
# File 'lib/epitools/path.rb', line 1575 def self.ln_s(src, dest) FileUtils.ln_s(src, dest) Path[dest] end |
.ls(path) ⇒ Object
1571 |
# File 'lib/epitools/path.rb', line 1571 def self.ls(path); Path[path].ls end |
.ls_r(path) ⇒ Object
1573 |
# File 'lib/epitools/path.rb', line 1573 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)
1125 1126 1127 1128 1129 1130 1131 1132 |
# File 'lib/epitools/path.rb', line 1125 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 |
.new(*args) ⇒ Object
Initializers
128 129 130 131 132 133 134 |
# File 'lib/epitools/path.rb', line 128 def self.new(*args) if args.first =~ URI_RE and self != Path::URI Path::URI.new(args.first) else super(*args) end end |
.popd ⇒ Object
1542 1543 1544 1545 |
# File 'lib/epitools/path.rb', line 1542 def self.popd @@dir_stack ||= [pwd] @@dir_stack.pop end |
.pushd(destination) ⇒ Object
1537 1538 1539 1540 |
# File 'lib/epitools/path.rb', line 1537 def self.pushd(destination) @@dir_stack ||= [] @@dir_stack.push pwd end |
.pwd ⇒ Object
The current directory
1533 1534 1535 |
# File 'lib/epitools/path.rb', line 1533 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)
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
# File 'lib/epitools/path.rb', line 568 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
1516 1517 1518 1519 1520 |
# File 'lib/epitools/path.rb', line 1516 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.
1504 1505 1506 1507 1508 |
# File 'lib/epitools/path.rb', line 1504 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.)
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
# File 'lib/epitools/path.rb', line 1599 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
526 527 528 529 530 531 |
# File 'lib/epitools/path.rb', line 526 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
492 493 494 495 496 497 498 499 500 501 |
# File 'lib/epitools/path.rb', line 492 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?
503 504 505 |
# File 'lib/epitools/path.rb', line 503 def ==(other) self.path == other.to_s end |
#=~(pattern) ⇒ Object
Match the full path against a regular expression
1338 1339 1340 |
# File 'lib/epitools/path.rb', line 1338 def =~(pattern) to_s =~ pattern end |
#[](key) ⇒ Object
Retrieve one of this file's xattrs
620 621 622 |
# File 'lib/epitools/path.rb', line 620 def [](key) attrs[key] end |
#[]=(key, value) ⇒ Object
Set this file's xattr
627 628 629 630 |
# File 'lib/epitools/path.rb', line 627 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.)
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 |
# File 'lib/epitools/path.rb', line 753 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
401 402 403 |
# File 'lib/epitools/path.rb', line 401 def atime lstat.atime end |
#atime=(new_atime) ⇒ Object
405 406 407 408 409 |
# File 'lib/epitools/path.rb', line 405 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.)
592 593 594 |
# File 'lib/epitools/path.rb', line 592 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.)
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 |
# File 'lib/epitools/path.rb', line 600 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.)
1094 1095 1096 |
# File 'lib/epitools/path.rb', line 1094 def backup! rename(backup_file) end |
#backup_file ⇒ Object
Return a copy of this Path with “.bak” at the end
1078 1079 1080 |
# File 'lib/epitools/path.rb', line 1078 def backup_file with(:filename => filename+".bak") end |
#broken_symlink? ⇒ Boolean
441 442 443 |
# File 'lib/epitools/path.rb', line 441 def broken_symlink? File.symlink?(path) and not File.exist?(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.
988 989 990 |
# File 'lib/epitools/path.rb', line 988 def cd(&block) Path.cd(path, &block) end |
#child_of?(parent) ⇒ Boolean
464 465 466 |
# File 'lib/epitools/path.rb', line 464 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.
1202 1203 1204 1205 |
# File 'lib/epitools/path.rb', line 1202 def chmod(mode) FileUtils.chmod(mode, self) self end |
#chmod_R(mode) ⇒ Object
1213 1214 1215 1216 1217 1218 1219 1220 |
# File 'lib/epitools/path.rb', line 1213 def chmod_R(mode) if directory? FileUtils.chmod_R(mode, self) self else raise "Not a directory." end end |
#chown(usergroup) ⇒ Object
1207 1208 1209 1210 1211 |
# File 'lib/epitools/path.rb', line 1207 def chown(usergroup) user, group = usergroup.split(":") FileUtils.chown(user, group, self) self end |
#chown_R(usergroup) ⇒ Object
1222 1223 1224 1225 1226 1227 1228 1229 1230 |
# File 'lib/epitools/path.rb', line 1222 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
1160 1161 1162 1163 |
# File 'lib/epitools/path.rb', line 1160 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
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 |
# File 'lib/epitools/path.rb', line 1149 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
1141 1142 1143 1144 |
# File 'lib/epitools/path.rb', line 1141 def cp_r(dest) FileUtils.cp_r(path, dest) #if Path[dest].exists? dest end |
#ctime ⇒ Object
397 398 399 |
# File 'lib/epitools/path.rb', line 397 def ctime lstat.ctime end |
#deflate(level = nil) ⇒ Object Also known as: gzip
gzip the file, returning the result as a string
1285 1286 1287 |
# File 'lib/epitools/path.rb', line 1285 def deflate(level=nil) Zlib.deflate(read, level) end |
#dir ⇒ Object Also known as: dirname, directory
The current directory (with a trailing /)
322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/epitools/path.rb', line 322 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=
238 239 240 241 242 243 |
# File 'lib/epitools/path.rb', line 238 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?
429 430 431 |
# File 'lib/epitools/path.rb', line 429 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)
659 660 661 662 663 |
# File 'lib/epitools/path.rb', line 659 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.
669 670 671 672 |
# File 'lib/epitools/path.rb', line 669 def each_line return to_enum(:each_line) unless block_given? open { |io| io.each_line { |line| yield line.chomp } } end |
#endswith(s) ⇒ Object
1354 |
# File 'lib/epitools/path.rb', line 1354 def endswith(s); path.endswith(s); end |
#executable? ⇒ Boolean Also known as: exe?
416 417 418 |
# File 'lib/epitools/path.rb', line 416 def executable? mode & 0o111 > 0 end |
#exists? ⇒ Boolean Also known as: exist?
fstat
368 369 370 |
# File 'lib/epitools/path.rb', line 368 def exists? File.exist? path end |
#exts ⇒ Object
350 351 352 353 354 |
# File 'lib/epitools/path.rb', line 350 def exts extensions = basename.split('.')[1..-1] extensions += [@ext] if @ext extensions end |
#filename ⇒ Object
334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/epitools/path.rb', line 334 def filename if base if ext base + "." + ext else base end else nil end end |
#filename=(newfilename) ⇒ Object
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/epitools/path.rb', line 220 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)
682 683 684 685 686 687 688 |
# File 'lib/epitools/path.rb', line 682 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.
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 |
# File 'lib/epitools/path.rb', line 1321 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.
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 |
# File 'lib/epitools/path.rb', line 1303 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
508 |
# File 'lib/epitools/path.rb', line 508 def hash; path.hash; end |
#hidden? ⇒ Boolean
Does the file or directory name start with a “.”?
475 476 477 478 |
# File 'lib/epitools/path.rb', line 475 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
978 979 980 |
# File 'lib/epitools/path.rb', line 978 def id3 ID3Tag.read(io) end |
#inflate ⇒ Object Also known as: gunzip
gunzip the file, returning the result as a string
1294 1295 1296 |
# File 'lib/epitools/path.rb', line 1294 def inflate Zlib.inflate(read) end |
#initialize_copy(other) ⇒ Object
148 149 150 151 152 |
# File 'lib/epitools/path.rb', line 148 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
360 361 362 |
# File 'lib/epitools/path.rb', line 360 def inspect "#<Path:#{path}>" end |
#join(other) ⇒ Object
Path.join(“anything{}”).path == “/etc/anything{}” (globs ignored)
518 519 520 |
# File 'lib/epitools/path.rb', line 518 def join(other) Path.new File.join(self, other) end |
#ln_s(dest) ⇒ Object
1165 1166 1167 1168 1169 1170 1171 |
# File 'lib/epitools/path.rb', line 1165 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
697 698 699 700 701 |
# File 'lib/epitools/path.rb', line 697 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
716 717 718 719 |
# File 'lib/epitools/path.rb', line 716 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
724 725 726 727 |
# File 'lib/epitools/path.rb', line 724 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
711 712 713 714 715 |
# File 'lib/epitools/path.rb', line 711 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
706 707 708 709 710 |
# File 'lib/epitools/path.rb', line 706 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
378 379 380 381 |
# File 'lib/epitools/path.rb', line 378 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)
1389 1390 1391 |
# File 'lib/epitools/path.rb', line 1389 def magic open { |io| MimeMagic.by_magic(io) } end |
#md5 ⇒ Object Also known as: md5sum
1270 1271 1272 |
# File 'lib/epitools/path.rb', line 1270 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)
1374 1375 1376 |
# File 'lib/epitools/path.rb', line 1374 def mimetype mimetype_from_ext || magic end |
#mimetype_from_ext ⇒ Object
Find the file's mimetype (only using the file extension)
1382 1383 1384 |
# File 'lib/epitools/path.rb', line 1382 def mimetype_from_ext MimeMagic.by_extension(ext) end |
#mkcd(&block) ⇒ Object
Path.mkcd(self)
1137 1138 1139 |
# File 'lib/epitools/path.rb', line 1137 def mkcd(&block) Path.mkcd(self, &block) end |
#mode ⇒ Object
383 384 385 |
# File 'lib/epitools/path.rb', line 383 def mode lstat.mode end |
#mtime ⇒ Object
387 388 389 |
# File 'lib/epitools/path.rb', line 387 def mtime lstat.mtime end |
#mtime=(new_mtime) ⇒ Object
391 392 393 394 395 |
# File 'lib/epitools/path.rb', line 391 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.
1031 1032 1033 1034 1035 1036 1037 1038 |
# File 'lib/epitools/path.rb', line 1031 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.
1052 1053 1054 |
# File 'lib/epitools/path.rb', line 1052 def mv!(arg) update(mv(arg)) end |
#name ⇒ Object
346 347 348 |
# File 'lib/epitools/path.rb', line 346 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.)
1086 1087 1088 |
# File 'lib/epitools/path.rb', line 1086 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.
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 |
# File 'lib/epitools/path.rb', line 1060 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)
639 640 641 642 643 644 645 |
# File 'lib/epitools/path.rb', line 639 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?
412 413 414 |
# File 'lib/epitools/path.rb', line 412 def owner? raise "STUB" end |
#parent ⇒ Object
Find the parent directory. If the `Path` is a filename, it returns the containing directory.
1345 1346 1347 1348 1349 1350 1351 |
# File 'lib/epitools/path.rb', line 1345 def parent if file? with(:filename=>nil) else with(:dirs=>dirs[0...-1]) end end |
#parent_of?(child) ⇒ Boolean
468 469 470 |
# File 'lib/epitools/path.rb', line 468 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.)
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 |
# File 'lib/epitools/path.rb', line 879 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
905 906 907 |
# File 'lib/epitools/path.rb', line 905 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
291 292 293 294 295 296 297 |
# File 'lib/epitools/path.rb', line 291 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.
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/epitools/path.rb', line 197 def path=(newpath, hints={}) if hints[:type] or File.exist? 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
773 774 775 776 |
# File 'lib/epitools/path.rb', line 773 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)
652 653 654 |
# File 'lib/epitools/path.rb', line 652 def read(length=nil, offset=nil) File.read(path, length, offset) end |
#read_bson(io = self.io) ⇒ Object
Parse the file as BSON
962 963 964 |
# File 'lib/epitools/path.rb', line 962 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
941 942 943 |
# File 'lib/epitools/path.rb', line 941 def read_csv(io=self.io, opts={}) CSV.new(io.read, **opts).each end |
#read_html(io = self.io) ⇒ Object Also known as: from_html
922 923 924 |
# File 'lib/epitools/path.rb', line 922 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
911 912 913 |
# File 'lib/epitools/path.rb', line 911 def read_json(io=self.io) JSON.load(io) end |
#read_marshal(io = self.io) ⇒ Object
Parse the file as a Ruby Marshal dump
952 953 954 |
# File 'lib/epitools/path.rb', line 952 def read_marshal(io=self.io) Marshal.load(io) end |
#read_xml(io = self.io) ⇒ Object
Parse the file as XML
947 948 949 |
# File 'lib/epitools/path.rb', line 947 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
934 935 936 |
# File 'lib/epitools/path.rb', line 934 def read_yaml(io=self.io) YAML.load(io) end |
#readable? ⇒ Boolean
425 426 427 |
# File 'lib/epitools/path.rb', line 425 def readable? mode & 0o444 > 0 end |
#realpath ⇒ Object
1360 1361 1362 |
# File 'lib/epitools/path.rb', line 1360 def realpath Path.new File.realpath(path) end |
#relative ⇒ Object
Path relative to current directory (Path.pwd)
311 312 313 |
# File 'lib/epitools/path.rb', line 311 def relative relative_to(pwd) end |
#relative? ⇒ Boolean
Is this a relative path?
302 303 304 305 306 |
# File 'lib/epitools/path.rb', line 302 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
315 316 317 318 319 |
# File 'lib/epitools/path.rb', line 315 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.)
273 274 275 276 277 278 279 280 |
# File 'lib/epitools/path.rb', line 273 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
1017 1018 1019 1020 1021 1022 1023 1024 1025 |
# File 'lib/epitools/path.rb', line 1017 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.
1044 1045 1046 |
# File 'lib/epitools/path.rb', line 1044 def rename!(arg) update(rename(arg)) end |
#reset! ⇒ Object
Clear out the internal state of this object, so that it can be reinitialized.
265 266 267 268 |
# File 'lib/epitools/path.rb', line 265 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
1237 1238 1239 1240 1241 1242 1243 1244 1245 |
# File 'lib/epitools/path.rb', line 1237 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
1260 1261 1262 |
# File 'lib/epitools/path.rb', line 1260 def sha1 Digest::SHA1.file(self).hexdigest end |
#sha2 ⇒ Object Also known as: sha2sum
1265 1266 1267 |
# File 'lib/epitools/path.rb', line 1265 def sha2 Digest::SHA2.file(self).hexdigest end |
#sha256 ⇒ Object Also known as: sha256sum
1275 1276 1277 |
# File 'lib/epitools/path.rb', line 1275 def sha256 Digest::SHA256.file(self).hexdigest end |
#siblings ⇒ Object
Returns all neighbouring directories to this path
732 733 734 |
# File 'lib/epitools/path.rb', line 732 def siblings Path[dir].ls - [self] end |
#size ⇒ Object
372 373 374 375 376 |
# File 'lib/epitools/path.rb', line 372 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)
488 489 490 |
# File 'lib/epitools/path.rb', line 488 def sort_attrs [(filename ? 1 : 0), path.downcase] end |
#startswith(s) ⇒ Object
1353 |
# File 'lib/epitools/path.rb', line 1353 def startswith(s); path.startswith(s); end |
#symlink? ⇒ Boolean
437 438 439 |
# File 'lib/epitools/path.rb', line 437 def symlink? File.symlink? path end |
#symlink_target ⇒ Object Also known as: readlink, target
445 446 447 448 449 450 451 452 |
# File 'lib/epitools/path.rb', line 445 def symlink_target target = File.readlink(path.gsub(/\/$/, '')) if target.startswith("/") Path[target] else Path[dir] / target end end |
#symlink_to ⇒ Object
1173 1174 1175 1176 1177 1178 1179 |
# File 'lib/epitools/path.rb', line 1173 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)
1614 1615 1616 |
# File 'lib/epitools/path.rb', line 1614 def to_Path self end |
#touch ⇒ Object
Like the unix `touch` command (if the file exists, update its timestamp, otherwise create a new file)
740 741 742 743 |
# File 'lib/epitools/path.rb', line 740 def touch open("a") { } self end |
#truncate(offset = 0) ⇒ Object
Shrink or expand the size of a file in-place
1253 1254 1255 |
# File 'lib/epitools/path.rb', line 1253 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?
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 |
# File 'lib/epitools/path.rb', line 1403 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
690 691 692 |
# File 'lib/epitools/path.rb', line 690 def unmarshal read.unmarshal end |
#update(other) ⇒ Object
282 283 284 285 286 |
# File 'lib/epitools/path.rb', line 282 def update(other) @dirs = other.dirs @base = other.base @ext = other.ext end |
#uri? ⇒ Boolean
461 |
# File 'lib/epitools/path.rb', line 461 def uri?; false; end |
#url? ⇒ Boolean
462 |
# File 'lib/epitools/path.rb', line 462 def url?; uri?; end |
#writable? ⇒ Boolean
421 422 423 |
# File 'lib/epitools/path.rb', line 421 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.)
781 782 783 784 785 786 787 788 789 790 791 792 793 |
# File 'lib/epitools/path.rb', line 781 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
967 968 969 |
# File 'lib/epitools/path.rb', line 967 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).
917 918 919 |
# File 'lib/epitools/path.rb', line 917 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
957 958 959 |
# File 'lib/epitools/path.rb', line 957 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).
929 930 931 |
# File 'lib/epitools/path.rb', line 929 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.
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 861 862 863 864 865 866 867 868 869 |
# File 'lib/epitools/path.rb', line 819 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 |