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
- .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.
- .zopen(filename, mode, &block) ⇒ Object
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(symlinks = false) ⇒ Object
Returns all files in this path’s directory and its subdirectories.
-
#ls_R ⇒ 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, **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, #rename_to)
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", **opts, &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.
137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/epitools/path.rb', line 137 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
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/epitools/path.rb', line 163 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.
1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 |
# File 'lib/epitools/path.rb', line 1567 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
155 156 157 |
# File 'lib/epitools/path.rb', line 155 def self.escape(str) Shellwords.escape(str) end |
.expand_path(orig_path) ⇒ Object
Same as File.expand_path, except preserves the trailing ‘/’.
1509 1510 1511 1512 1513 |
# File 'lib/epitools/path.rb', line 1509 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)
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
# File 'lib/epitools/path.rb', line 541 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
159 160 161 |
# File 'lib/epitools/path.rb', line 159 def self.glob(str, **hints) Dir[str].map { |entry| new(entry, **hints) } end |
.home ⇒ Object
User’s current home directory
1541 1542 1543 |
# File 'lib/epitools/path.rb', line 1541 def self.home Path[ENV['HOME']] end |
.ln_s(src, dest) ⇒ Object
1590 1591 1592 1593 |
# File 'lib/epitools/path.rb', line 1590 def self.ln_s(src, dest) FileUtils.ln_s(src, dest) Path[dest] end |
.ls(path) ⇒ Object
1586 |
# File 'lib/epitools/path.rb', line 1586 def self.ls(path); Path[path].ls end |
.ls_r(path) ⇒ Object
1588 |
# File 'lib/epitools/path.rb', line 1588 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)
1139 1140 1141 1142 1143 1144 1145 1146 |
# File 'lib/epitools/path.rb', line 1139 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
129 130 131 132 133 134 135 |
# File 'lib/epitools/path.rb', line 129 def self.new(*args) if args.first =~ URI_RE and self != Path::URI Path::URI.new(args.first) else old_new(*args) end end |
.popd ⇒ Object
1557 1558 1559 1560 |
# File 'lib/epitools/path.rb', line 1557 def self.popd @@dir_stack ||= [pwd] @@dir_stack.pop end |
.pushd(destination) ⇒ Object
1552 1553 1554 1555 |
# File 'lib/epitools/path.rb', line 1552 def self.pushd(destination) @@dir_stack ||= [] @@dir_stack.push pwd end |
.pwd ⇒ Object
The current directory
1548 1549 1550 |
# File 'lib/epitools/path.rb', line 1548 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)
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 |
# File 'lib/epitools/path.rb', line 569 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
1531 1532 1533 1534 1535 |
# File 'lib/epitools/path.rb', line 1531 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.
1518 1519 1520 1521 1522 1523 |
# File 'lib/epitools/path.rb', line 1518 def self.tmpfile(prefix="tmp") # path = Path.new(Tempfile.new(prefix).path, unlink_when_garbage_collected: true) path = Path.new(Tempfile.new(prefix).path) 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.)
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 |
# File 'lib/epitools/path.rb', line 1614 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
527 528 529 530 531 532 |
# File 'lib/epitools/path.rb', line 527 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
493 494 495 496 497 498 499 500 501 502 |
# File 'lib/epitools/path.rb', line 493 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?
504 505 506 |
# File 'lib/epitools/path.rb', line 504 def ==(other) self.path == other.to_s end |
#=~(pattern) ⇒ Object
Match the full path against a regular expression
1352 1353 1354 |
# File 'lib/epitools/path.rb', line 1352 def =~(pattern) to_s =~ pattern end |
#[](key) ⇒ Object
Retrieve one of this file’s xattrs
621 622 623 |
# File 'lib/epitools/path.rb', line 621 def [](key) attrs[key] end |
#[]=(key, value) ⇒ Object
Set this file’s xattr
628 629 630 631 |
# File 'lib/epitools/path.rb', line 628 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.)
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 |
# File 'lib/epitools/path.rb', line 754 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
402 403 404 |
# File 'lib/epitools/path.rb', line 402 def atime lstat.atime end |
#atime=(new_atime) ⇒ Object
406 407 408 409 410 |
# File 'lib/epitools/path.rb', line 406 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.)
593 594 595 |
# File 'lib/epitools/path.rb', line 593 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.)
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 |
# File 'lib/epitools/path.rb', line 601 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.)
1108 1109 1110 |
# File 'lib/epitools/path.rb', line 1108 def backup! rename(backup_file) end |
#backup_file ⇒ Object
Return a copy of this Path with “.bak” at the end
1092 1093 1094 |
# File 'lib/epitools/path.rb', line 1092 def backup_file with(:filename => filename+".bak") end |
#broken_symlink? ⇒ Boolean
442 443 444 |
# File 'lib/epitools/path.rb', line 442 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.
1001 1002 1003 |
# File 'lib/epitools/path.rb', line 1001 def cd(&block) Path.cd(path, &block) end |
#child_of?(parent) ⇒ Boolean
465 466 467 |
# File 'lib/epitools/path.rb', line 465 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.
1216 1217 1218 1219 |
# File 'lib/epitools/path.rb', line 1216 def chmod(mode) FileUtils.chmod(mode, self) self end |
#chmod_R(mode) ⇒ Object
1227 1228 1229 1230 1231 1232 1233 1234 |
# File 'lib/epitools/path.rb', line 1227 def chmod_R(mode) if directory? FileUtils.chmod_R(mode, self) self else raise "Not a directory." end end |
#chown(usergroup) ⇒ Object
1221 1222 1223 1224 1225 |
# File 'lib/epitools/path.rb', line 1221 def chown(usergroup) user, group = usergroup.split(":") FileUtils.chown(user, group, self) self end |
#chown_R(usergroup) ⇒ Object
1236 1237 1238 1239 1240 1241 1242 1243 1244 |
# File 'lib/epitools/path.rb', line 1236 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
1174 1175 1176 1177 |
# File 'lib/epitools/path.rb', line 1174 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
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 |
# File 'lib/epitools/path.rb', line 1163 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
1155 1156 1157 1158 |
# File 'lib/epitools/path.rb', line 1155 def cp_r(dest) FileUtils.cp_r(path, dest) #if Path[dest].exists? dest end |
#ctime ⇒ Object
398 399 400 |
# File 'lib/epitools/path.rb', line 398 def ctime lstat.ctime end |
#deflate(level = nil) ⇒ Object Also known as: gzip
gzip the file, returning the result as a string
1299 1300 1301 |
# File 'lib/epitools/path.rb', line 1299 def deflate(level=nil) Zlib.deflate(read, level) end |
#dir ⇒ Object Also known as: dirname, directory
The current directory (with a trailing /)
323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/epitools/path.rb', line 323 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=
239 240 241 242 243 244 |
# File 'lib/epitools/path.rb', line 239 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?
430 431 432 |
# File 'lib/epitools/path.rb', line 430 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)
660 661 662 663 664 |
# File 'lib/epitools/path.rb', line 660 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.
670 671 672 673 |
# File 'lib/epitools/path.rb', line 670 def each_line return to_enum(:each_line) unless block_given? open { |io| io.each_line { |line| yield line.chomp } } end |
#endswith(s) ⇒ Object
1368 |
# File 'lib/epitools/path.rb', line 1368 def endswith(s); path.endswith(s); end |
#executable? ⇒ Boolean Also known as: exe?
417 418 419 |
# File 'lib/epitools/path.rb', line 417 def executable? mode & 0o111 > 0 end |
#exists? ⇒ Boolean Also known as: exist?
fstat
369 370 371 |
# File 'lib/epitools/path.rb', line 369 def exists? File.exist? path end |
#exts ⇒ Object
351 352 353 354 355 |
# File 'lib/epitools/path.rb', line 351 def exts extensions = basename.split('.')[1..-1] extensions += [@ext] if @ext extensions end |
#filename ⇒ Object
335 336 337 338 339 340 341 342 343 344 345 |
# File 'lib/epitools/path.rb', line 335 def filename if base if ext base + "." + ext else base end else nil end end |
#filename=(newfilename) ⇒ Object
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/epitools/path.rb', line 221 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)
683 684 685 686 687 688 689 |
# File 'lib/epitools/path.rb', line 683 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.
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 |
# File 'lib/epitools/path.rb', line 1335 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.
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 |
# File 'lib/epitools/path.rb', line 1317 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
509 |
# File 'lib/epitools/path.rb', line 509 def hash; path.hash; end |
#hidden? ⇒ Boolean
Does the file or directory name start with a “.”?
476 477 478 479 |
# File 'lib/epitools/path.rb', line 476 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
991 992 993 |
# File 'lib/epitools/path.rb', line 991 def id3 ID3Tag.read(io) end |
#inflate ⇒ Object Also known as: gunzip
gunzip the file, returning the result as a string
1308 1309 1310 |
# File 'lib/epitools/path.rb', line 1308 def inflate Zlib.inflate(read) end |
#initialize_copy(other) ⇒ Object
149 150 151 152 153 |
# File 'lib/epitools/path.rb', line 149 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
361 362 363 |
# File 'lib/epitools/path.rb', line 361 def inspect "#<Path:#{path}>" end |
#join(other) ⇒ Object
Path.join(“anything{}”).path == “/etc/anything{}” (globs ignored)
519 520 521 |
# File 'lib/epitools/path.rb', line 519 def join(other) Path.new File.join(self, other) end |
#ln_s(dest) ⇒ Object
1179 1180 1181 1182 1183 1184 1185 |
# File 'lib/epitools/path.rb', line 1179 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
698 699 700 701 702 |
# File 'lib/epitools/path.rb', line 698 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
717 718 719 720 |
# File 'lib/epitools/path.rb', line 717 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
725 726 727 728 |
# File 'lib/epitools/path.rb', line 725 def ls_files ls.select(&:file?) #Dir.glob("#{path}*", File::FNM_DOTMATCH).map { |s| Path.new(s, :type=>:file) } end |
#ls_r(symlinks = false) ⇒ Object
Returns all files in this path’s directory and its subdirectories
707 708 709 710 711 |
# File 'lib/epitools/path.rb', line 707 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 ⇒ Object
Returns all files in this path’s directory and its subdirectories
712 713 714 715 716 |
# File 'lib/epitools/path.rb', line 712 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
379 380 381 382 |
# File 'lib/epitools/path.rb', line 379 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)
1403 1404 1405 |
# File 'lib/epitools/path.rb', line 1403 def magic open { |io| MimeMagic.by_magic(io) } end |
#md5 ⇒ Object Also known as: md5sum
1284 1285 1286 |
# File 'lib/epitools/path.rb', line 1284 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)
1388 1389 1390 |
# File 'lib/epitools/path.rb', line 1388 def mimetype mimetype_from_ext || magic end |
#mimetype_from_ext ⇒ Object
Find the file’s mimetype (only using the file extension)
1396 1397 1398 |
# File 'lib/epitools/path.rb', line 1396 def mimetype_from_ext MimeMagic.by_extension(ext) end |
#mkcd(&block) ⇒ Object
Path.mkcd(self)
1151 1152 1153 |
# File 'lib/epitools/path.rb', line 1151 def mkcd(&block) Path.mkcd(self, &block) end |
#mode ⇒ Object
384 385 386 |
# File 'lib/epitools/path.rb', line 384 def mode lstat.mode end |
#mtime ⇒ Object
388 389 390 |
# File 'lib/epitools/path.rb', line 388 def mtime lstat.mtime end |
#mtime=(new_mtime) ⇒ Object
392 393 394 395 396 |
# File 'lib/epitools/path.rb', line 392 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.
1045 1046 1047 1048 1049 1050 1051 1052 |
# File 'lib/epitools/path.rb', line 1045 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.
1066 1067 1068 |
# File 'lib/epitools/path.rb', line 1066 def mv!(arg) update(mv(arg)) end |
#name ⇒ Object
347 348 349 |
# File 'lib/epitools/path.rb', line 347 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.)
1100 1101 1102 |
# File 'lib/epitools/path.rb', line 1100 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.
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 |
# File 'lib/epitools/path.rb', line 1074 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)
640 641 642 643 644 645 646 |
# File 'lib/epitools/path.rb', line 640 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?
413 414 415 |
# File 'lib/epitools/path.rb', line 413 def owner? raise "STUB" end |
#parent ⇒ Object
Find the parent directory. If the ‘Path` is a filename, it returns the containing directory.
1359 1360 1361 1362 1363 1364 1365 |
# File 'lib/epitools/path.rb', line 1359 def parent if file? with(:filename=>nil) else with(:dirs=>dirs[0...-1]) end end |
#parent_of?(child) ⇒ Boolean
469 470 471 |
# File 'lib/epitools/path.rb', line 469 def parent_of?(child) dirs == child.dirs[0...dirs.size] end |
#parse(io = self.io, **opts) ⇒ Object
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
# File 'lib/epitools/path.rb', line 887 def parse(io=self.io, **opts) case (opts[:format] || ext.downcase) when 'gz', 'bz2', 'xz' parse(zopen, format: 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 'tsv' opts[:col_sep] ||= "\t" 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
916 917 918 |
# File 'lib/epitools/path.rb', line 916 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
292 293 294 295 296 297 298 |
# File 'lib/epitools/path.rb', line 292 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.
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/epitools/path.rb', line 198 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
774 775 776 777 |
# File 'lib/epitools/path.rb', line 774 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)
653 654 655 |
# File 'lib/epitools/path.rb', line 653 def read(length=nil, offset=nil) File.read(path, length, offset) end |
#read_bson(io = self.io) ⇒ Object
Parse the file as BSON
975 976 977 |
# File 'lib/epitools/path.rb', line 975 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
953 954 955 |
# File 'lib/epitools/path.rb', line 953 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
933 934 935 936 |
# File 'lib/epitools/path.rb', line 933 def read_html(io=self.io) #Nokogiri::HTML(io) Oga.parse_html(io) end |
#read_json(io = self.io) ⇒ Object Also known as: from_json
Parse the file as JSON
922 923 924 |
# File 'lib/epitools/path.rb', line 922 def read_json(io=self.io) JSON.load(io) end |
#read_marshal(io = self.io) ⇒ Object
Parse the file as a Ruby Marshal dump
965 966 967 |
# File 'lib/epitools/path.rb', line 965 def read_marshal(io=self.io) Marshal.load(io) end |
#read_xml(io = self.io) ⇒ Object
Parse the file as XML
959 960 961 962 |
# File 'lib/epitools/path.rb', line 959 def read_xml(io=self.io) # Nokogiri::XML(io) Oga.parse_xml(io) end |
#read_yaml(io = self.io) ⇒ Object Also known as: from_yaml
Parse the file as YAML
946 947 948 |
# File 'lib/epitools/path.rb', line 946 def read_yaml(io=self.io) YAML.load(io) end |
#readable? ⇒ Boolean
426 427 428 |
# File 'lib/epitools/path.rb', line 426 def readable? mode & 0o444 > 0 end |
#realpath ⇒ Object
1374 1375 1376 |
# File 'lib/epitools/path.rb', line 1374 def realpath Path.new File.realpath(path) end |
#relative ⇒ Object
Path relative to current directory (Path.pwd)
312 313 314 |
# File 'lib/epitools/path.rb', line 312 def relative relative_to(pwd) end |
#relative? ⇒ Boolean
Is this a relative path?
303 304 305 306 307 |
# File 'lib/epitools/path.rb', line 303 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
316 317 318 319 320 |
# File 'lib/epitools/path.rb', line 316 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.)
274 275 276 277 278 279 280 281 |
# File 'lib/epitools/path.rb', line 274 def reload! temp = path reset! self.path = temp @attrs = nil self end |
#rename(arg) ⇒ Object Also known as: ren, rename_to
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
1030 1031 1032 1033 1034 1035 1036 1037 1038 |
# File 'lib/epitools/path.rb', line 1030 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.
1058 1059 1060 |
# File 'lib/epitools/path.rb', line 1058 def rename!(arg) update(rename(arg)) end |
#reset! ⇒ Object
Clear out the internal state of this object, so that it can be reinitialized.
266 267 268 269 |
# File 'lib/epitools/path.rb', line 266 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
1251 1252 1253 1254 1255 1256 1257 1258 1259 |
# File 'lib/epitools/path.rb', line 1251 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
1274 1275 1276 |
# File 'lib/epitools/path.rb', line 1274 def sha1 Digest::SHA1.file(self).hexdigest end |
#sha2 ⇒ Object Also known as: sha2sum
1279 1280 1281 |
# File 'lib/epitools/path.rb', line 1279 def sha2 Digest::SHA2.file(self).hexdigest end |
#sha256 ⇒ Object Also known as: sha256sum
1289 1290 1291 |
# File 'lib/epitools/path.rb', line 1289 def sha256 Digest::SHA256.file(self).hexdigest end |
#siblings ⇒ Object
Returns all neighbouring directories to this path
733 734 735 |
# File 'lib/epitools/path.rb', line 733 def siblings Path[dir].ls - [self] end |
#size ⇒ Object
373 374 375 376 377 |
# File 'lib/epitools/path.rb', line 373 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)
489 490 491 |
# File 'lib/epitools/path.rb', line 489 def sort_attrs [(filename ? 1 : 0), path.downcase] end |
#startswith(s) ⇒ Object
1367 |
# File 'lib/epitools/path.rb', line 1367 def startswith(s); path.startswith(s); end |
#symlink? ⇒ Boolean
438 439 440 |
# File 'lib/epitools/path.rb', line 438 def symlink? File.symlink? path end |
#symlink_target ⇒ Object Also known as: readlink, target
446 447 448 449 450 451 452 453 |
# File 'lib/epitools/path.rb', line 446 def symlink_target target = File.readlink(path.gsub(/\/$/, '')) if target.startswith("/") Path[target] else Path[dir] / target end end |
#symlink_to ⇒ Object
1187 1188 1189 1190 1191 1192 1193 |
# File 'lib/epitools/path.rb', line 1187 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)
1629 1630 1631 |
# File 'lib/epitools/path.rb', line 1629 def to_Path self end |
#touch ⇒ Object
Like the unix ‘touch` command (if the file exists, update its timestamp, otherwise create a new file)
741 742 743 744 |
# File 'lib/epitools/path.rb', line 741 def touch open("a") { } self end |
#truncate(offset = 0) ⇒ Object
Shrink or expand the size of a file in-place
1267 1268 1269 |
# File 'lib/epitools/path.rb', line 1267 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?
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 |
# File 'lib/epitools/path.rb', line 1417 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
691 692 693 |
# File 'lib/epitools/path.rb', line 691 def unmarshal read.unmarshal end |
#update(other) ⇒ Object
283 284 285 286 287 |
# File 'lib/epitools/path.rb', line 283 def update(other) @dirs = other.dirs @base = other.base @ext = other.ext end |
#uri? ⇒ Boolean
462 |
# File 'lib/epitools/path.rb', line 462 def uri?; false; end |
#url? ⇒ Boolean
463 |
# File 'lib/epitools/path.rb', line 463 def url?; uri?; end |
#writable? ⇒ Boolean
422 423 424 |
# File 'lib/epitools/path.rb', line 422 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.)
782 783 784 785 786 787 788 789 790 791 792 793 794 |
# File 'lib/epitools/path.rb', line 782 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
980 981 982 |
# File 'lib/epitools/path.rb', line 980 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).
928 929 930 |
# File 'lib/epitools/path.rb', line 928 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
970 971 972 |
# File 'lib/epitools/path.rb', line 970 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).
941 942 943 |
# File 'lib/epitools/path.rb', line 941 def write_yaml(object) write object.to_yaml end |
#zopen(mode = "rb", **opts, &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.
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 870 |
# File 'lib/epitools/path.rb', line 820 def zopen(mode="rb", **opts, &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 = (opts[:format] || 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 |