Class: Pathutil

Inherits:
Object
  • Object
show all
Extended by:
Forwardable::Extended, Helpers
Defined in:
lib/pathutil/version.rb,
lib/pathutil.rb,
lib/pathutil/helpers.rb

Overview


Frozen-string-literal: true Copyright: 2015-2016 Jordon Bedwell - MIT License Encoding: utf-8


Defined Under Namespace

Modules: Helpers

Constant Summary collapse

VERSION =
"0.3.0"

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

load_yaml, make_tmpname

Constructor Details

#initialize(path) ⇒ Pathutil




20
21
22
23
24
# File 'lib/pathutil.rb', line 20

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

Class Attribute Details

.encodingObject

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.




676
677
678
679
680
# File 'lib/pathutil.rb', line 676

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

Instance Attribute Details

#encodingObject



See Also:

  • as this is an alias.


500
501
502
503
504
# File 'lib/pathutil.rb', line 500

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

Class Method Details

.normalizeObject


Normalize CRLF -> LF on Windows reads, to ease your troubles. Normalize LF -> CLRF on Windows write, to ease their troubles.




687
688
689
690
691
692
# File 'lib/pathutil.rb', line 687

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

.pwdObject Also known as: gcwd, cwd


Get the current directory that Ruby knows about.




661
662
663
664
665
# File 'lib/pathutil.rb', line 661

def pwd
  new(
    Dir.pwd
  )
end

.tmpdir(*args) ⇒ Object




696
697
698
699
700
701
702
703
# File 'lib/pathutil.rb', line 696

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

  rtn
end

.tmpfile(*args) ⇒ Object




707
708
709
710
711
712
713
714
# File 'lib/pathutil.rb', line 707

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

  rtn
end

Instance Method Details

#<(other) ⇒ Object


Strictly check to see if a path is behind other path but within it.


Examples:

Pathutil.new(“/”) < Pathutil.new(“/hello”) # => true




154
155
156
157
158
# File 'lib/pathutil.rb', line 154

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

#<=(other) ⇒ Object


Check to see if a path is behind the other path butt within it.


Examples:

Pathutil.new(“/hello”) < Pathutil.new(“/hello”) # => true


Pathutil.new(“/”) < Pathutil.new(“/hello”) # => true




168
169
170
171
172
# File 'lib/pathutil.rb', line 168

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

#===(other) ⇒ Object


A stricter version of ‘==` that also makes sure the object matches.


See Also:

  • for more details.


116
117
118
# File 'lib/pathutil.rb', line 116

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

#>(other) ⇒ Object


Strictly checks to see if a path is deeper but within the path of the other.


Examples:

Pathutil.new(“/hello/world”) > Pathutil.new(“/hello”) # => true




141
142
143
144
145
# File 'lib/pathutil.rb', line 141

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

#>=(other) ⇒ Object


Checks to see if a path falls within a path and deeper or is the other.


Examples:

Pathutil.new(“/hello”) >= Pathutil.new(“/”) # => true


Pathutil.new(“/hello”) >= Pathutil.new(“/hello”) # => true




128
129
130
131
132
# File 'lib/pathutil.rb', line 128

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

#absolute?Boolean

Note:

“./” is considered relative.


Check to see if the path is absolute, as in: starts with “/”




180
181
182
# File 'lib/pathutil.rb', line 180

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

#ascend {|path = self| ... } ⇒ Object


Break apart the path and yield each with the previous parts.


Examples:

Pathutil.new("/hello/world").ascend.to_a # => [
  "/", "/hello", "/hello/world"
]
Pathutil.new("/hello/world").ascend do |path|
  $stdout.puts path
end

/
/hello
/hello/world

Yields:

  • (path = self)


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/pathutil.rb', line 203

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) ⇒ Object


Binread took two steroid shots: it can normalize your string, and encode.




529
530
531
532
533
534
535
536
537
538
539
540
541
542
# File 'lib/pathutil.rb', line 529

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) ⇒ Object


Binwrite took two steroid shots: it can normalize your string, and encode.




586
587
588
589
590
591
592
593
594
595
596
597
598
599
# File 'lib/pathutil.rb', line 586

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

#chdirObject

Note:

you do not need to ship a block at all.


Move to the current directory temporarily (or for good) and do work son.




377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/pathutil.rb', line 377

def chdir
  if !block_given?
    Dir.chdir(
      @path
    )

  else
    Dir.chdir @path do
      yield
    end
  end
end

#childrenObject Also known as: entries


Grab all of the children from the current directory, including hidden.




327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/pathutil.rb', line 327

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

#descendObject


Break apart the path in reverse order and descend into the path.


Examples:

Pathutil.new("/hello/world").descend.to_a # => [
  "/hello/world", "/hello", "/"
]
Pathutil.new("/hello/world").descend do |path|
  $stdout.puts path
end

/hello/world
/hello
/


245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/pathutil.rb', line 245

def descend
  unless block_given?
    return to_enum(
      __method__
    )
  end

  ascend.to_a.reverse_each do |val|
    yield val
  end

  nil
end

#each_filenameObject


Splits the path returning each part (filename) back to you.




408
409
410
411
412
413
# File 'lib/pathutil.rb', line 408

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_lineObject


Wraps ‘readlines` and allows you to yield on the result.


Examples:

Pathutil.new("/hello/world").each_line do |line|
  $stdout.puts line
end

Hello
World


271
272
273
274
275
276
277
278
# File 'lib/pathutil.rb', line 271

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

  nil
end

#enforce_root(root) ⇒ Object


Expands the path and left joins the root to the path.




461
462
463
464
465
466
467
468
469
470
471
# File 'lib/pathutil.rb', line 461

def enforce_root(root)
  curr, root = expanded_paths(root)
  if curr.in_path?(root)
    return curr

  else
    File.join(
      root, curr
    )
  end
end

#findObject


Find all files without care and yield the given block.


See Also:

  • Find.find


396
397
398
399
400
401
# File 'lib/pathutil.rb', line 396

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

#fnmatch?(matcher) ⇒ Boolean Also known as: fnmatch


Unlike traditional ‘fnmatch`, with this one `Regexp` is allowed.


Examples:

Pathutil.new(“/hello”).fnmatch?(“/hello”) # => true


Pathutil.new(“/hello”).fnmatch?(/h/) # => true


See Also:

  • for more information.


289
290
291
292
# File 'lib/pathutil.rb', line 289

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

#glob(pattern, flags = 0) ⇒ Object


Allows you to glob however you wish to glob in the current ‘Pathutils`


See Also:

  • for a list of flags.


353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/pathutil.rb', line 353

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) ⇒ Boolean


Allows you to check if the current path is in the path you want.




309
310
311
312
313
314
# File 'lib/pathutil.rb', line 309

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

#inspectObject




318
319
320
# File 'lib/pathutil.rb', line 318

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

#normalizeObject



See Also:

  • as this is an alias.


490
491
492
493
494
# File 'lib/pathutil.rb', line 490

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

#parentObject




417
418
419
420
421
422
# File 'lib/pathutil.rb', line 417

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

#read(*args, **kwd) ⇒ Object


Read took two steroid shots: it can normalize your string, and encode.




510
511
512
513
514
515
516
517
518
519
520
521
522
523
# File 'lib/pathutil.rb', line 510

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) ⇒ Object




82
83
84
85
86
87
88
89
90
91
# File 'lib/pathutil.rb', line 82

def read_json(throw_missing: false)
  JSON.parse(
    read
  )

rescue Errno::ENOENT
  throw_missing ? raise : (
    return {}
  )
end

#read_yaml(throw_missing: false, **kwd) ⇒ Object




69
70
71
72
73
74
75
76
77
78
# File 'lib/pathutil.rb', line 69

def read_yaml(throw_missing: false, **kwd)
  self.class.load_yaml(
    read, **kwd
  )

rescue Errno::ENOENT
  throw_missing ? raise : (
    return {}
  )
end

#readlines(*args, **kwd) ⇒ Object


Readlines took two steroid shots: it can normalize your string, and encode.




548
549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'lib/pathutil.rb', line 548

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_path_from(from) ⇒ Object


A less complex version of ‘relative_path_from` that simply uses a `Regexp` and returns the full path if it cannot be relatively determined.




450
451
452
453
# File 'lib/pathutil.rb', line 450

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?Boolean


Allows you to quickly determine if the file is the root folder.




299
300
301
# File 'lib/pathutil.rb', line 299

def root?
  self == File::SEPARATOR
end

#safe_copy(to, root: nil) ⇒ Object


Copy a directory, allowing symlinks if the link falls inside of the root.


Raises:

  • (ArgumentError)


477
478
479
480
481
482
483
484
# File 'lib/pathutil.rb', line 477

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

#search_backwards(file, backwards: Float::INFINITY) ⇒ Object

Note:

It will return all results that it finds across all ascending paths.


Search backwards for a file (like Rakefile, _config.yml, opts.yml).


Examples:

Pathutil.new("~/").expand_path.search_backwards(".bashrc") => [
  #<Pathutil:/home/user/.bashrc>
]


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/pathutil.rb', line 38

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

#splitObject


Split the file into its dirname and basename, so you can do stuff.




429
430
431
432
433
# File 'lib/pathutil.rb', line 429

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

#split_pathObject

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


Examples:

Pathutil.new("/my/path").split_path # => [
  "", "my", "path"
]


103
104
105
106
107
# File 'lib/pathutil.rb', line 103

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

#sub_ext(ext) ⇒ Object


Replace a files extension with your given extension.




439
440
441
# File 'lib/pathutil.rb', line 439

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

#write(data, *args, **kwd) ⇒ Object


Write took two steroid shots: it can normalize your string, and encode.




567
568
569
570
571
572
573
574
575
576
577
578
579
580
# File 'lib/pathutil.rb', line 567

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