class Pathutil
Copyright: 2015-2016 Jordon Bedwell - MIT License Encoding: utf-8
Constants
- VERSION
Attributes
Public Class Methods
– @note A lot of this class can be compatible with Pathname. Initialize a new instance. @return Pathutil
–
# File lib/pathutil.rb, line 19 def initialize(path) return @path = path if path.is_a?(String) return @path = path.to_path if path.respond_to?(:to_path) return @path = path.to_s end
Private Class Methods
– @note you are encouraged to override this if you need to. Aliases the default system encoding to us so that we can do most read and write operations with that encoding, instead of being crazy. –
# File lib/pathutil.rb, line 743 def encoding return @encoding ||= begin Encoding.default_external end end
– Normalize CRLF -> LF on Windows reads, to ease your troubles. Normalize LF -> CLRF on Windows write, to ease your troubles. –
# File lib/pathutil.rb, line 753 def normalize return @normalize ||= { :read => Gem.win_platform?, :write => Gem.win_platform? } end
– @note We do nothing special here. Get the current directory that Ruby knows about. @return Pathutil
–
# File lib/pathutil.rb, line 729 def pwd new( Dir.pwd ) end
– Make a temporary directory. @note if you adruptly exit it will not remove the dir. @note this directory is removed on exit. @return Pathutil
–
# File lib/pathutil.rb, line 766 def tmpdir(*args) rtn = new(make_tmpname(*args)).tap(&:mkdir) ObjectSpace.define_finalizer(rtn, proc do rtn.rm_rf end) rtn end
– Make a temporary file. @note if you adruptly exit it will not remove the dir. @note this file is removed on exit. @return Pathutil
–
# File lib/pathutil.rb, line 781 def tmpfile(*args) rtn = new(make_tmpname(*args)).tap(&:touch) ObjectSpace.define_finalizer(rtn, proc do rtn.rm_rf end) rtn end
Public Instance Methods
– @example Pathutil.new
(“/”) < Pathutil.new
(“/hello”) # => true Strictly check to see if a path is behind other path but within it. @return true|false –
# File lib/pathutil.rb, line 173 def <(other) mine, other = expanded_paths(other) return false if other == mine other.in_path?(mine) end
– Check to see if a path is behind the other path but within it. @example Pathutil.new
(“/hello”) < Pathutil.new
(“/hello”) # => true @example Pathutil.new
(“/”) < Pathutil.new
(“/hello”) # => true @return true|false –
# File lib/pathutil.rb, line 185 def <=(other) mine, other = expanded_paths(other) return true if other == mine other.in_path?(mine) end
– @see ‘String#==` for more details. A stricter version of `==` that also makes sure the object matches. @return true|false –
# File lib/pathutil.rb, line 141 def ===(other) other.is_a?(self.class) && @path == other end
– @example Pathutil.new
(“/hello/world”) > Pathutil.new
(“/hello”) # => true Strictly checks to see if a path is deeper but within the path of the other. @return true|false –
# File lib/pathutil.rb, line 162 def >(other) mine, other = expanded_paths(other) return false if other == mine mine.in_path?(other) end
– @example Pathutil.new
(“/hello”) >= Pathutil.new
(“/”) # => true @example Pathutil.new
(“/hello”) >= Pathutil.new
(“/hello”) # => true Checks to see if a path falls within a path and deeper or is the other. @return true|false –
# File lib/pathutil.rb, line 151 def >=(other) mine, other = expanded_paths(other) return true if other == mine mine.in_path?(other) end
– Make a path absolute –
# File lib/pathutil.rb, line 40 def absolute return self if absolute? self.class.new("/").join( @path ) end
– @note “./” is considered relative. Check to see if the path is absolute, as in: starts with “/” @return true|false –
# File lib/pathutil.rb, line 196 def absolute? return !!( @path =~ %r!\A(?:[A-Za-z]:)?(?:\\+|/+)! ) end
– rubocop:disable Metrics/AbcSize rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/PerceivedComplexity –
# File lib/pathutil.rb, line 615 def aggressive_cleanpath return self.class.new("/") if root? _out = split_path.each_with_object([]) do |part, out| next if part == "." || (part == ".." && out.last == "") if part == ".." && out.last && out.last != ".." out.pop else out.push( part ) end end # -- return self.class.new("/") if _out == [""].freeze return self.class.new(".") if _out.empty? && (end_with?(".") || relative?) self.class.new(_out.join("/")) end
– @yield Pathutil
Break apart the path and yield each with the previous parts. @example Pathutil.new
(“/hello/world”).ascend.to_a # => [“/”, “/hello”, “/hello/world”] @example Pathutil.new
(“/hello/world”).ascend { |path| $stdout.puts path } @return Enum –
# File lib/pathutil.rb, line 209 def ascend unless block_given? return to_enum( __method__ ) end yield( path = self ) while (new_path = path.dirname) if path == new_path || new_path == "." break else path = new_path yield new_path end end nil end
– @note You can set the default encodings via the class. Binread took two steroid shots: it can normalize your string, and encode. @return String –
# File lib/pathutil.rb, line 516 def binread(*args, **kwd) kwd[:encoding] ||= encoding if normalize[:read] File.binread(self, *args, kwd).encode({ :universal_newline => true }) else File.read( self, *args, kwd ) end end
– @note You can set the default encodings via the class. Binwrite took two steroid shots: it can normalize your string, and encode. @return Fixnum<Bytes> –
# File lib/pathutil.rb, line 576 def binwrite(data, *args, **kwd) kwd[:encoding] ||= encoding if normalize[:write] File.binwrite(self, data.encode( :crlf_newline => true ), *args, kwd) else File.binwrite( self, data, *args, kwd ) end end
– @yield &block Move to the current directory temporarily (or for good) and do work son. @note you do not need to ship a block at all. @return nil –
# File lib/pathutil.rb, line 358 def chdir if !block_given? Dir.chdir( @path ) else Dir.chdir @path do yield end end end
– @return Array<Pathutil> Grab all of the children from the current directory, including hidden. @yield Pathutil
–
# File lib/pathutil.rb, line 310 def children ary = [] Dir.foreach(@path) do |path| if path == "." || path == ".." next else path = self.class.new(File.join(@path, path)) yield path if block_given? ary.push( path ) end end ary end
– @see Pathname#cleanpath. @note This is a wholesale rip and cleanup of Pathname#cleanpath @return Pathutil
–
# File lib/pathutil.rb, line 52 def cleanpath(symlink = false) symlink ? conservative_cleanpath : aggressive_cleanpath end
–
# File lib/pathutil.rb, line 639 def conservative_cleanpath _out = split_path.each_with_object([]) do |part, out| next if part == "." || (part == ".." && out.last == "") out.push( part ) end # -- if !_out.empty? && basename == "." && _out.last != "" && _out.last != ".." _out << "." end # -- return self.class.new("/") if _out == [""].freeze return self.class.new(".") if _out.empty? && (end_with?(".") || relative?) return self.class.new(_out.join("/")).join("") if @path =~ %r!/\z! \ && _out.last != "." && _out.last != ".." self.class.new(_out.join("/")) end
– @yield Pathutil
Break apart the path in reverse order and descend into the path. @example Pathutil.new
(“/hello/world”).descend.to_a # => [“/hello/world”, “/hello”, “/”] @example Pathutil.new
(“/hello/world”).descend { |path| $stdout.puts path } @return Enum –
# File lib/pathutil.rb, line 239 def descend unless block_given? return to_enum( __method__ ) end ascend.to_a.reverse_each do |val| yield val end nil end
– @yield Pathutil
Splits the path returning each part (filename) back to you. @return Enum –
# File lib/pathutil.rb, line 388 def each_filename return to_enum(__method__) unless block_given? @path.split(File::SEPARATOR).delete_if(&:empty?).each do |file| yield file end end
– @yield Pathutil
@example Pathutil.new
(“/hello/world”).each_line { |line| $stdout.puts line } Wraps ‘readlines` and allows you to yield on the result. @return Enum –
# File lib/pathutil.rb, line 259 def each_line return to_enum(__method__) unless block_given? readlines.each do |line| yield line end nil end
– @see ‘self.class.encoding` as this is an alias. –
# File lib/pathutil.rb, line 485 def encoding return @encoding ||= begin self.class.encoding end end
– Expands the path and left joins the root to the path. @return Pathutil
–
# File lib/pathutil.rb, line 443 def enforce_root(root) return self if !relative? && in_path?(root) self.class.new(root).join( self ) end
– @yield Pathutil
Find all files without care and yield the given block. @return Enum –
# File lib/pathutil.rb, line 376 def find return to_enum(__method__) unless block_given? Find.find @path do |val| yield self.class.new(val) end end
– @example Pathutil.new
(“/hello”).fnmatch?(“/hello”) # => true Unlike traditional ‘fnmatch`, with this one `Regexp` is allowed. @example Pathutil.new
(“/hello”).fnmatch?(/h/) # => true @see `File#fnmatch` for more information. @return true|false –
# File lib/pathutil.rb, line 275 def fnmatch?(matcher) matcher.is_a?(Regexp) ? !!(self =~ matcher) : \ File.fnmatch(matcher, self) end
– @yield Pathutil
Allows you to glob however you wish to glob in the current ‘Pathutil` @see `File::Constants` for a list of flags. @return Enum –
# File lib/pathutil.rb, line 334 def glob(pattern, flags = 0) unless block_given? return to_enum( __method__, pattern, flags ) end chdir do Dir.glob(pattern, flags).each do |file| yield self.class.new( File.join(@path, file) ) end end nil end
– Allows you to check if the current path is in the path you want. @return true|false –
# File lib/pathutil.rb, line 292 def in_path?(path) path = self.class.new(path).expand_path.split_path mine = (symlink?? expand_path.realpath : expand_path).split_path path.each_with_index { |part, index| return false if mine[index] != part } true end
–
# File lib/pathutil.rb, line 301 def inspect "#<#{self.class}:#{@path}>" end
– @see ‘self.class.normalize` as this is an alias. –
# File lib/pathutil.rb, line 476 def normalize return @normalize ||= begin self.class.normalize end end
– Get the parent of the current path. @note This will simply return self if “/”. @return Pathutil
–
# File lib/pathutil.rb, line 400 def parent return self if @path == "/" self.class.new(absolute?? File.dirname(@path) : File.join( @path, ".." )) end
– @note You can set the default encodings via the class. Read took two steroid shots: it can normalize your string, and encode. @return String –
# File lib/pathutil.rb, line 496 def read(*args, **kwd) kwd[:encoding] ||= encoding if normalize[:read] File.read(self, *args, kwd).encode({ :universal_newline => true }) else File.read( self, *args, kwd ) end end
– Read the file as a JSON file turning it into an object. @see self.class.read_json as this is a direct alias of that method. @return Hash –
# File lib/pathutil.rb, line 113 def read_json(throw_missing: false) JSON.parse( read ) rescue Errno::ENOENT throw_missing ? raise : ( return {} ) end
– Read the file as a YAML file turning it into an object. @see self.class.load_yaml as this a direct alias of that method. @return Hash –
# File lib/pathutil.rb, line 97 def read_yaml(throw_missing: false, **kwd) self.class.load_yaml( read, **kwd ) rescue Errno::ENOENT throw_missing ? raise : ( return {} ) end
– @note You can set the default encodings via the class. Readlines took two steroid shots: it can normalize your string, and encode. @return Array<String> –
# File lib/pathutil.rb, line 536 def readlines(*args, **kwd) kwd[:encoding] ||= encoding if normalize[:read] File.readlines(self, *args, kwd).encode({ :universal_newline => true }) else File.readlines( self, *args, kwd ) end end
– Make a path relative. –
# File lib/pathutil.rb, line 29 def relative return self if relative? self.class.new(strip_windows_drive.gsub( %r!\A(\\+|/+)!, "" )) end
– A less complex version of ‘relative_path_from` that simply uses a `Regexp` and returns the full path if it cannot be determined. @return Pathutil
–
# File lib/pathutil.rb, line 432 def relative_path_from(from) from = self.class.new(from).expand_path.gsub(%r!/$!, "") self.class.new(expand_path.gsub(%r!^#{ from.regexp_escape }/!, "")) end
– Allows you to quickly determine if the file is the root folder. @return true|false –
# File lib/pathutil.rb, line 284 def root? !!(self =~ %r!\A(?:[A-Za-z]:)?(?:\\+|/+)\z!) end
– Copy a directory, allowing symlinks if the link falls inside of the root. This is indented for people who wish some safety to their copies. @note Ignore is ignored on safe_copy
file because it’s explicit. @return nil –
# File lib/pathutil.rb, line 456 def safe_copy(to, root: nil, ignore: []) raise ArgumentError, "must give a root" unless root root = self.class.new(root) to = self.class.new(to) if directory? safe_copy_directory(to, { :root => root, :ignore => ignore }) else safe_copy_file(to, { :root => root }) end end
– @yield Pathutil
@note It will return all results that it finds across all ascending paths. @example Pathutil.new
(“~/”).expand_path.search_backwards(“.bashrc”) => [#<Pathutil:/home/user/.bashrc>] Search backwards for a file (like Rakefile, _config.yml, opts.yml). @return Enum –
# File lib/pathutil.rb, line 63 def search_backwards(file, backwards: Float::INFINITY) ary = [] ascend.with_index(1).each do |path, index| if index > backwards break else Dir.chdir path do if block_given? file = self.class.new(file) if yield(file) ary.push( file ) end elsif File.exist?(file) ary.push(self.class.new( path.join(file) )) end end end end ary end
– @yield Pathutil
Split the file into its dirname and basename, so you can do stuff. @return nil –
# File lib/pathutil.rb, line 412 def split File.split(@path).collect! do |path| self.class.new(path) end end
– @note The blank part is intentionally left there so that you can rejoin. Splits the path into all parts so that you can do step by step comparisons @example Pathutil.new
(“/my/path”).split_path # => [“”, “my”, “path”] @return Array<String> –
# File lib/pathutil.rb, line 130 def split_path @path.split( %r!\\+|/+! ) end
– Strips the windows drive from the path. –
# File lib/pathutil.rb, line 603 def strip_windows_drive(path = @path) self.class.new(path.gsub( %r!\A[A-Za-z]:(?:\\+|/+)!, "" )) end
– @note Your extension should start with “.” Replace a files extension with your given extension. @return Pathutil
–
# File lib/pathutil.rb, line 423 def sub_ext(ext) self.class.new(@path.chomp(File.extname(@path)) + ext) end
–
# File lib/pathutil.rb, line 593 def to_regexp(guard: true) Regexp.new((guard ? "\\A" : "") + Regexp.escape( self )) end
– @note You can set the default encodings via the class. Write took two steroid shots: it can normalize your string, and encode. @return Fixnum<Bytes> –
# File lib/pathutil.rb, line 556 def write(data, *args, **kwd) kwd[:encoding] ||= encoding if normalize[:write] File.write(self, data.encode( :crlf_newline => true ), *args, kwd) else File.write( self, data, *args, kwd ) end end
Private Instance Methods
– rubocop:enable Metrics/AbcSize rubocop:enable Metrics/CyclomaticComplexity rubocop:enable Metrics/PerceivedComplexity Expand the paths and return. –
# File lib/pathutil.rb, line 669 def expanded_paths(path) return expand_path, self.class.new(path).expand_path end
– Safely copy a directory and it’s sub-files. –
# File lib/pathutil.rb, line 688 def safe_copy_directory(to, root: nil, ignore: []) ignore = [ignore].flatten.uniq if !in_path?(root) raise Errno::EPERM, "#{self} not in #{ root }" else to.mkdir_p unless to.exist? children do |file| unless ignore.any? { |path| file.in_path?(path) } if !file.in_path?(root) raise Errno::EPERM, "#{file} not in #{ root }" elsif file.file? FileUtils.cp(file, to, { :preserve => true }) else path = file.realpath path.safe_copy(to.join(file.basename), { :root => root, :ignore => ignore }) end end end end end
– Safely copy a file. –
# File lib/pathutil.rb, line 677 def safe_copy_file(to, root: nil) raise Errno::EPERM, "#{self} not in #{root}" unless in_path?(root) FileUtils.cp(self, to, { :preserve => true }) end