Class: Pathutil

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

Overview


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


Constant Summary collapse

VERSION =
"0.0.1"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Pathutil




48
49
50
# File 'lib/pathutil.rb', line 48

def initialize(path)
  @path = path.to_s
end

Instance Attribute Details

#encodingObject



See Also:

  • as this is an alias.


504
505
506
507
508
# File 'lib/pathutil.rb', line 504

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

Class Method 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.




27
28
29
30
31
# File 'lib/pathutil.rb', line 27

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

.normalizeObject


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




38
39
40
41
42
43
# File 'lib/pathutil.rb', line 38

def normalize
  return @normalize ||= {
    :read  => Gem.win_platform?,
    :write => Gem.win_platform?
  }
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


Parameters:

  • path

    the path that should be below the object.

Returns:

  • true, false



162
163
164
165
166
# File 'lib/pathutil.rb', line 162

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


Parameters:

  • path

    the path that should be below the object.

Returns:

  • true, false



176
177
178
179
180
# File 'lib/pathutil.rb', line 176

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.


Parameters:

Returns:

  • true, false

See Also:

  • for more details.


124
125
126
# File 'lib/pathutil.rb', line 124

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


Parameters:

  • path

    the path that should be above the object.

Returns:

  • true, false



149
150
151
152
153
# File 'lib/pathutil.rb', line 149

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


Parameters:

  • path

    the path that should be above the object.

Returns:

  • true, false



136
137
138
139
140
# File 'lib/pathutil.rb', line 136

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 “/”


Returns:

  • (Boolean)

    true, false



188
189
190
# File 'lib/pathutil.rb', line 188

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)

Returns:

  • Enumerator if no block is given.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/pathutil.rb', line 211

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.




533
534
535
536
537
538
539
540
541
542
543
544
545
546
# File 'lib/pathutil.rb', line 533

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.




590
591
592
593
594
595
596
597
598
599
600
601
602
603
# File 'lib/pathutil.rb', line 590

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.


Returns:

  • 0, 1 if no block given



380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/pathutil.rb', line 380

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.




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

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
/

Returns:

  • Enumerator if no block is given.



253
254
255
256
257
258
259
260
# File 'lib/pathutil.rb', line 253

def descend
  return ascend.to_a.reverse.to_enum unless block_given?
  ascend.to_a.reverse_each do |val|
    yield val
  end

  nil
end

#each_filenameObject


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


Returns:

  • Enumerator if no block is given.



411
412
413
414
415
416
# File 'lib/pathutil.rb', line 411

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


274
275
276
277
278
279
280
281
# File 'lib/pathutil.rb', line 274

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.


Parameters:

  • root (String, Pathutil)

    the root you wish to enforce on it.

Returns:

  • Pathutil the enforced path with given root.



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

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.


Returns:

  • Enumerator if no block is given.

See Also:

  • Find.find


399
400
401
402
403
404
# File 'lib/pathutil.rb', line 399

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


Parameters:

  • matcher (String, Regexp)

    the matcher used, can be a ‘Regexp`

Returns:

  • (Boolean)

    true, false

See Also:

  • for more information.


292
293
294
295
# File 'lib/pathutil.rb', line 292

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`


Parameters:

  • flags (String) (defaults to: 0)

    the flags you want to ship to the glob.

  • pattern (String)

    the pattern A.K.A: “*/

Returns:

  • Enumerator unless a block is given.

See Also:

  • for a list of flags.


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

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.


Parameters:

  • path (Pathutil, String)

    the reference.

Returns:

  • (Boolean)

    true, false



312
313
314
315
316
317
# File 'lib/pathutil.rb', line 312

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




321
322
323
# File 'lib/pathutil.rb', line 321

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

#normalizeObject



See Also:

  • as this is an alias.


494
495
496
497
498
# File 'lib/pathutil.rb', line 494

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

#parentObject




420
421
422
423
424
# File 'lib/pathutil.rb', line 420

def parent
  self.class.new(File.join(
    @path, ".."
  ))
end

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


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




514
515
516
517
518
519
520
521
522
523
524
525
526
527
# File 'lib/pathutil.rb', line 514

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




90
91
92
93
94
95
96
97
98
99
# File 'lib/pathutil.rb', line 90

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

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

#read_yaml(safe: true, whitelist_classes: [], throw_missing: false) ⇒ Object




62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/pathutil.rb', line 62

def read_yaml(safe: true, whitelist_classes: [], throw_missing: false)
  require "yaml"

  unless safe
    return YAML.load(
      read
    )
  end

  if !YAML.respond_to?(:safe_load)
    setup_safe_yaml whitelist_classes
    SafeYAML.load(read, {
      :raise_on_unknown_tag => true
    })

  else
    YAML.safe_load(read, {
      :whitelist_classes => whitelist_classes
    })
  end
rescue Errno::ENOENT
  throw_missing ? raise : (
    return {}
  )
end

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


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




552
553
554
555
556
557
558
559
560
561
562
563
564
565
# File 'lib/pathutil.rb', line 552

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.


Returns:

  • Pathutils the relative path if it can be determined or is relative.

  • Pathutils the full path if relative path cannot be determined



454
455
456
457
# File 'lib/pathutil.rb', line 454

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)

    true, false



302
303
304
# File 'lib/pathutil.rb', line 302

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)


481
482
483
484
485
486
487
488
# File 'lib/pathutil.rb', line 481

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

#splitObject


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


Returns:

  • File.dirname, File.basename



431
432
433
434
435
# File 'lib/pathutil.rb', line 431

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"
]


111
112
113
114
115
# File 'lib/pathutil.rb', line 111

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

#sub_ext(ext) ⇒ Object


Replace a files extension with your given extension.




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

def sub_ext(ext)
  self.class.new(
    "#{@path.gsub(/\..+$/, "")}#{ext}"
  )
end

#to_pathnameObject




54
55
56
57
58
# File 'lib/pathutil.rb', line 54

def to_pathname
  Pathname.new(
    self
  )
end

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


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




571
572
573
574
575
576
577
578
579
580
581
582
583
584
# File 'lib/pathutil.rb', line 571

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