class Pathutil

def <(other)

def <(other)
  mine, other = expanded_paths(other)
  return false if other == mine
  other.in_path?(mine)
end

def <=(other)

def <=(other)
  mine, other = expanded_paths(other)
  return true if other == mine
  other.in_path?(mine)
end

def ===(other)

def ===(other)
  other.is_a?(self.class) && @path == other
end

def >(other)

def >(other)
  mine, other = expanded_paths(other)
  return false if other == mine
  mine.in_path?(other)
end

def >=(other)

def >=(other)
  mine, other = expanded_paths(other)
  return true if other == mine
  mine.in_path?(other)
end

def absolute?

def absolute?
  @path.start_with?("/")
end

def ascend

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

def binread(*args, **kwd)

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

def binwrite(data, *args, **kwd)

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

def chdir

def chdir
  if !block_given?
    Dir.chdir(
      @path
    )
  else
    Dir.chdir @path do
      yield
    end
  end
end

def children

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

def descend

def descend
  unless block_given?
    return to_enum(
      __method__
    )
  end
  ascend.to_a.reverse_each do |val|
    yield val
  end
  nil
end

def each_filename

def each_filename
  return to_enum(__method__) unless block_given?
  @path.split(File::SEPARATOR).delete_if(&:empty?).each do |file|
    yield file
  end
end

def each_line

def each_line
  return to_enum(__method__) unless block_given?
  readlines.each do |line|
    yield line
  end
  nil
end

def encoding

def encoding
  return @encoding ||= begin
    self.class.encoding
  end
end

def encoding

def encoding
  return @encoding ||= begin
    Encoding.default_external
  end
end

def enforce_root(root)

def enforce_root(root)
  curr, root = expanded_paths(root)
  if curr.in_path?(root)
    return curr
  else
    File.join(
      root, curr
    )
  end
end

def expanded_paths(path)

def expanded_paths(path)
  return expand_path, self.class.new(path).expand_path
end

def find

def find
  return to_enum(__method__) unless block_given?
  Find.find @path do |val|
    yield self.class.new(val)
  end
end

def fnmatch?(matcher)

def fnmatch?(matcher)
  matcher.is_a?(Regexp) ? !!(self =~ matcher) : \
    File.fnmatch(self, matcher)
end

def glob(pattern, flags = 0)

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

def in_path?(path)

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

def initialize(path)

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

def inspect

def inspect
  "#<#{self.class}:#{@path}>"
end

def normalize

def normalize
  return @normalize ||= begin
    self.class.normalize
  end
end

def normalize

def normalize
  return @normalize ||= {
    :read  => Gem.win_platform?,
    :write => Gem.win_platform?
  }
end

def parent

def parent
  return self if @path == "/"
  self.class.new(absolute?? File.dirname(@path) : File.join(
    @path, ".."
  ))
end

def pwd

def pwd
  new(
    Dir.pwd
  )
end

def read(*args, **kwd)

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

def read_json(throw_missing: false)

def read_json(throw_missing: false)
  JSON.parse(
    read
  )
rescue Errno::ENOENT
  throw_missing ? raise : (
    return {}
  )
end

def read_yaml(throw_missing: false, **kwd)

def read_yaml(throw_missing: false, **kwd)
  self.class.load_yaml(
    read, **kwd
  )
rescue Errno::ENOENT
  throw_missing ? raise : (
    return {}
  )
end

def readlines(*args, **kwd)

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

def relative_path_from(from)

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

def root?

def root?
  self == File::SEPARATOR
end

def safe_copy(to, root: nil)

def safe_copy(to, root: nil)
  raise ArgumentError, "must give a root" unless root
  to = self.class.new(to)
  root = self.class.new(root)
  return safe_copy_directory(to, :root => root) if directory?
  safe_copy_file(to, :root => root)
end

def safe_copy_directory(to, root: nil)

def safe_copy_directory(to, root: nil)
  if !in_path?(root)
    raise Errno::EPERM, "#{self} not in #{
      root
    }"
  else
    to.mkdir_p unless to.exist?
    children do |file|
      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
        })
      end
    end
  end
end

def safe_copy_file(to, root: nil)

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

def search_backwards(file, backwards: Float::INFINITY)

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

def split

def split
  File.split(@path).collect! do |path|
    self.class.new(path)
  end
end

def split_path

def split_path
  @path.split(
    File::SEPARATOR
  )
end

def sub_ext(ext)

def sub_ext(ext)
  self.class.new(@path.chomp(File.extname(@path)) + ext)
end

def tmpdir(*args)

def tmpdir(*args)
  rtn = new(make_tmpname(*args)).tap(&:mkdir)
  ObjectSpace.define_finalizer(rtn, proc do
    rtn.rm_rf
  end)
  rtn
end

def tmpfile(*args)

def tmpfile(*args)
  rtn = new(make_tmpname(*args)).tap(&:touch)
  ObjectSpace.define_finalizer(rtn, proc do
    rtn.rm_rf
  end)
  rtn
end

def write(data, *args, **kwd)

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