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.9.0"

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

allowed, load_yaml, make_tmpname

Constructor Details

#initialize(path) ⇒ Pathutil


Note: A lot of this class can be compatible with Pathname.




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.




646
647
648
649
650
# File 'lib/pathutil.rb', line 646

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

Instance Attribute Details

#encodingObject


See: ‘self.class.encoding` as this is an alias.




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

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 your troubles.




657
658
659
660
661
662
# File 'lib/pathutil.rb', line 657

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. Note: We do nothing special here.




631
632
633
634
635
# File 'lib/pathutil.rb', line 631

def pwd
  new(
    Dir.pwd
  )
end

.tmpdir(*args) ⇒ Object


Make a temporary directory. Note: if you adruptly exit it will not remove the dir. Note: this directory is removed on exit.




670
671
672
673
674
675
676
677
# File 'lib/pathutil.rb', line 670

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


Make a temporary file. Note: if you adruptly exit it will not remove the dir. Note: this file is removed on exit.




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

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. Example: Pathutil.new(“/”) < Pathutil.new(“/hello”) # => true




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

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 but within it. Example: Pathutil.new(“/hello”) < Pathutil.new(“/hello”) # => true Example: 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 true if other == mine
  other.in_path?(mine)
end

#===(other) ⇒ Object


A stricter version of ‘==` that also makes sure the object matches. See: `String#==` for more details.




110
111
112
# File 'lib/pathutil.rb', line 110

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. Example: Pathutil.new(“/hello/world”) > Pathutil.new(“/hello”) # => true




131
132
133
134
135
# File 'lib/pathutil.rb', line 131

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. Example: Pathutil.new(“/hello”) >= Pathutil.new(“/hello”) # => true Example: Pathutil.new(“/hello”) >= Pathutil.new(“/”) # => true




120
121
122
123
124
# File 'lib/pathutil.rb', line 120

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

#absolute?Boolean


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


Returns:

  • (Boolean)


165
166
167
# File 'lib/pathutil.rb', line 165

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

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


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 }


Yields:

  • (path = self)


175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/pathutil.rb', line 175

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. Note: You can set the default encodings via the class.




481
482
483
484
485
486
487
488
489
490
491
492
493
494
# File 'lib/pathutil.rb', line 481

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. Note: You can set the default encodings via the class.




541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'lib/pathutil.rb', line 541

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


Move to the current directory temporarily (or for good) and do work son. Note: you do not need to ship a block at all.




319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/pathutil.rb', line 319

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.




273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/pathutil.rb', line 273

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. Example: Pathutil.new(“/hello/world”).descend.to_a # => [“/hello/world”, “/hello”, “/”] Example: Pathutil.new(“/hello/world”).descend { |path| $stdout.puts path }




204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/pathutil.rb', line 204

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.




347
348
349
350
351
352
# File 'lib/pathutil.rb', line 347

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


Example: Pathutil.new(“/hello/world”).each_line { |line| $stdout.puts line } Wraps ‘readlines` and allows you to yield on the result.




223
224
225
226
227
228
229
230
# File 'lib/pathutil.rb', line 223

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.




401
402
403
404
405
406
407
408
409
410
411
# File 'lib/pathutil.rb', line 401

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.




336
337
338
339
340
341
# File 'lib/pathutil.rb', line 336

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


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.


Returns:

  • (Boolean)


239
240
241
242
# File 'lib/pathutil.rb', line 239

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

#glob(pattern, flags = 0) ⇒ Object


Allows you to glob however you wish to glob in the current ‘Pathutil` See: `File::Constants` for a list of flags.




296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/pathutil.rb', line 296

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.


Returns:

  • (Boolean)


256
257
258
259
260
261
# File 'lib/pathutil.rb', line 256

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




265
266
267
# File 'lib/pathutil.rb', line 265

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

#normalizeObject


See: ‘self.class.normalize` as this is an alias.




440
441
442
443
444
# File 'lib/pathutil.rb', line 440

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

#parentObject


Note: This will simply return self if “/”. Get the parent of the current path.




359
360
361
362
363
364
# File 'lib/pathutil.rb', line 359

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. Note: You can set the default encodings via the class.




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

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


See: self.class.read_json as this is a direct alias of that method. Read the file as a JSON file turning it into an 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


See: self.class.load_yaml as this a direct alias of that method. Read the file as a YAML file turning it into an object.




66
67
68
69
70
71
72
73
74
75
# File 'lib/pathutil.rb', line 66

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. Note: You can set the default encodings via the class.




501
502
503
504
505
506
507
508
509
510
511
512
513
514
# File 'lib/pathutil.rb', line 501

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 determined.




390
391
392
393
394
395
# File 'lib/pathutil.rb', line 390

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.


Returns:

  • (Boolean)


248
249
250
# File 'lib/pathutil.rb', line 248

def root?
  self == File::SEPARATOR
end

#safe_copy(to, root: nil, ignore: []) ⇒ Object


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.


Raises:

  • (ArgumentError)


419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# File 'lib/pathutil.rb', line 419

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


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).




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/pathutil.rb', line 32

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.




370
371
372
373
374
# File 'lib/pathutil.rb', line 370

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 Example: Pathutil.new(“/my/path”).split_path # => [“”, “my”, “path”]




99
100
101
102
103
# File 'lib/pathutil.rb', line 99

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

#sub_ext(ext) ⇒ Object


Replace a files extension with your given extension. Note: Your extension should start with “.”




381
382
383
# File 'lib/pathutil.rb', line 381

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

#to_regexp(guard: true) ⇒ Object




558
559
560
561
562
# File 'lib/pathutil.rb', line 558

def to_regexp(guard: true)
  Regexp.new((guard ? "\\A" : "") + Regexp.escape(
    self
  ))
end

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


Write took two steroid shots: it can normalize your string, and encode. Note: You can set the default encodings via the class.




521
522
523
524
525
526
527
528
529
530
531
532
533
534
# File 'lib/pathutil.rb', line 521

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