class Pathutil

Copyright: 2015-2016 Jordon Bedwell - MIT License Encoding: utf-8

Constants

VERSION

Attributes

encoding[W]
encoding[W]

Public Class Methods

new(path) click to toggle source

– @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

cwd()
Alias for: pwd
encoding() click to toggle source

– @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
gcwd()
Alias for: pwd
normalize() click to toggle source

– 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
pwd() click to toggle source

– @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
Also aliased as: gcwd, cwd
tmpdir(*args) click to toggle source

– 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
tmpfile(*args) click to toggle source

– 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

<(other) click to toggle source

– @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
<=(other) click to toggle source

– 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
===(other) click to toggle source

– @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
>(other) click to toggle source

– @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
>=(other) click to toggle source

– @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
absolute() click to toggle source

– Make a path absolute –

# File lib/pathutil.rb, line 40
def absolute
  return self if absolute?
  self.class.new("/").join(
    @path
  )
end
absolute?() click to toggle source

– @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
aggressive_cleanpath() click to toggle source

– 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
Also aliased as: cleanpath_aggressive
ascend() { |path = self| ... } click to toggle source

– @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
binread(*args, **kwd) click to toggle source

– @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
binwrite(data, *args, **kwd) click to toggle source

– @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
chdir() { || ... } click to toggle source

– @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
children() { |path| ... } click to toggle source

– @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
Also aliased as: entries
cleanpath(symlink = false) click to toggle source

– @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
conservative_cleanpath() click to toggle source

# 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
Also aliased as: cleanpath_conservative
descend() { |val| ... } click to toggle source

– @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
each_filename() { |file| ... } click to toggle source

– @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
each_line() { |line| ... } click to toggle source

– @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
encoding() click to toggle source

– @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
enforce_root(root) click to toggle source

– 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
Also aliased as: prepend
find() { |class.new(val)| ... } click to toggle source

– @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
fnmatch?(matcher) click to toggle source

– @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
Also aliased as: fnmatch
glob(pattern, flags = 0) { |class.new( join| ... } click to toggle source

– @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
in_path?(path) click to toggle source

– 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
inspect() click to toggle source

# File lib/pathutil.rb, line 301
def inspect
  "#<#{self.class}:#{@path}>"
end
normalize() click to toggle source

– @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
parent() click to toggle source

– 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
read(*args, **kwd) click to toggle source

– @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_json(throw_missing: false) click to toggle source

– 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_yaml(throw_missing: false, **kwd) click to toggle source

– 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
readlines(*args, **kwd) click to toggle source

– @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
relative() click to toggle source

– 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
relative_path_from(from) click to toggle source

– 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
root?() click to toggle source

– 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
safe_copy(to, root: nil, ignore: []) click to toggle source

– 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
search_backwards(file, backwards: Float::INFINITY) { |file| ... } click to toggle source

– @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
split() click to toggle source

– @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
split_path() click to toggle source

– @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
strip_windows_drive(path = @path) click to toggle source

– 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
sub_ext(ext) click to toggle source

– @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
to_regexp(guard: true) click to toggle source

# File lib/pathutil.rb, line 593
def to_regexp(guard: true)
  Regexp.new((guard ? "\\A" : "") + Regexp.escape(
    self
  ))
end
write(data, *args, **kwd) click to toggle source

– @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

cleanpath_aggressive()
cleanpath_conservative()
entries()
Alias for: children
expanded_paths(path) click to toggle source

– 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
fnmatch(matcher)
Alias for: fnmatch?
prepend(root)
Alias for: enforce_root
safe_copy_directory(to, root: nil, ignore: []) click to toggle source

– 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
safe_copy_file(to, root: nil) click to toggle source

– 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