pathutil 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c10b81a9cf17f0652212fefb3a9b82467716c295
4
- data.tar.gz: 3f336ad870a92910d1dc28fd4131b07366cd7581
3
+ metadata.gz: ff3970eccd4ba23f0967096b403f8877d817e7b1
4
+ data.tar.gz: f56f0ec8f93744500a8a8cce865eae14789492af
5
5
  SHA512:
6
- metadata.gz: 6a9b1db57f38d02fb924c98aa1061dd5a8045aa9f3599b9e4be3896904d8cd0e9135ebb1ada4960dde3eb4c599825321d499b146f3b22e3414c73baeee0e94f9
7
- data.tar.gz: 5c7c52a0373b8a7807d89ecdd7bafeba72a29ef3c9ac888832a29a4744e7273e266b7c88d6806562624c2d0243056fc181aa246890da485860f9843a6e3d172b
6
+ metadata.gz: 7636f86ee046ce975a4fbbb45e1314b70ff7e4363d5d4c9537453f17c83d57edbbad8f941b4b6e68edbd93d76aa9f5248a5b747bfe21668a3bb83bbb3b40b65b
7
+ data.tar.gz: 419f55807ad4227f508b61921ed253350e037c7916f7a660480f4ae42783a43c9c25e1944c39e6be41074a8561d180a0f96c5f0f3954789c0fc30ca69e1bb542
data/lib/pathutil.rb CHANGED
@@ -1,8 +1,6 @@
1
- # ----------------------------------------------------------------------------
2
1
  # Frozen-string-literal: true
3
2
  # Copyright: 2015-2016 Jordon Bedwell - MIT License
4
3
  # Encoding: utf-8
5
- # ----------------------------------------------------------------------------
6
4
 
7
5
  require "pathutil/helpers"
8
6
  require "forwardable/extended"
@@ -13,22 +11,33 @@ class Pathutil
13
11
  extend Forwardable::Extended
14
12
  extend Helpers
15
13
 
16
- # --------------------------------------------------------------------------
17
- # Note: A lot of this class can be compatible with Pathname.
18
- # --------------------------------------------------------------------------
19
-
14
+ # --
15
+ # @note A lot of this class can be compatible with Pathname.
16
+ # Initialize a new instance.
17
+ # @return Pathutil
18
+ # --
20
19
  def initialize(path)
21
20
  return @path = path if path.is_a?(String)
22
21
  return @path = path.to_path if path.respond_to?(:to_path)
23
22
  return @path = path.to_s
24
23
  end
25
24
 
26
- # --------------------------------------------------------------------------
27
- # Note: It will return all results that it finds across all ascending paths.
28
- # Example: Pathutil.new("~/").expand_path.search_backwards(".bashrc") => [#<Pathutil:/home/user/.bashrc>]
29
- # Search backwards for a file (like Rakefile, _config.yml, opts.yml).
30
- # --------------------------------------------------------------------------
25
+ # --
26
+ # @see Pathname#cleanpath.
27
+ # @note This is a wholesale rip and cleanup of Pathname#cleanpath
28
+ # @return Pathutil
29
+ # --
30
+ def cleanpath(symlink = false)
31
+ symlink ? conservative_cleanpath : aggressive_cleanpath
32
+ end
31
33
 
34
+ # --
35
+ # @yield Pathutil
36
+ # @note It will return all results that it finds across all ascending paths.
37
+ # @example Pathutil.new("~/").expand_path.search_backwards(".bashrc") => [#<Pathutil:/home/user/.bashrc>]
38
+ # Search backwards for a file (like Rakefile, _config.yml, opts.yml).
39
+ # @return Enum
40
+ # --
32
41
  def search_backwards(file, backwards: Float::INFINITY)
33
42
  ary = []
34
43
 
@@ -58,11 +67,11 @@ class Pathutil
58
67
  ary
59
68
  end
60
69
 
61
- # --------------------------------------------------------------------------
62
- # See: self.class.load_yaml as this a direct alias of that method.
70
+ # --
63
71
  # Read the file as a YAML file turning it into an object.
64
- # --------------------------------------------------------------------------
65
-
72
+ # @see self.class.load_yaml as this a direct alias of that method.
73
+ # @return Hash
74
+ # --
66
75
  def read_yaml(throw_missing: false, **kwd)
67
76
  self.class.load_yaml(
68
77
  read, **kwd
@@ -74,11 +83,11 @@ class Pathutil
74
83
  )
75
84
  end
76
85
 
77
- # --------------------------------------------------------------------------
78
- # See: self.class.read_json as this is a direct alias of that method.
86
+ # --
79
87
  # Read the file as a JSON file turning it into an object.
80
- # --------------------------------------------------------------------------
81
-
88
+ # @see self.class.read_json as this is a direct alias of that method.
89
+ # @return Hash
90
+ # --
82
91
  def read_json(throw_missing: false)
83
92
  JSON.parse(
84
93
  read
@@ -90,88 +99,89 @@ class Pathutil
90
99
  )
91
100
  end
92
101
 
93
- # --------------------------------------------------------------------------
94
- # Note: The blank part is intentionally left there so that you can rejoin.
102
+ # --
103
+ # @note The blank part is intentionally left there so that you can rejoin.
95
104
  # Splits the path into all parts so that you can do step by step comparisons
96
- # Example: Pathutil.new("/my/path").split_path # => ["", "my", "path"]
97
- # --------------------------------------------------------------------------
98
-
105
+ # @example Pathutil.new("/my/path").split_path # => ["", "my", "path"]
106
+ # @return Array<String>
107
+ # --
99
108
  def split_path
100
109
  @path.split(
101
- File::SEPARATOR
110
+ /\\+|\/+/.freeze
102
111
  )
103
112
  end
104
113
 
105
- # --------------------------------------------------------------------------
114
+ # --
115
+ # @see `String#==` for more details.
106
116
  # A stricter version of `==` that also makes sure the object matches.
107
- # See: `String#==` for more details.
108
- # --------------------------------------------------------------------------
109
-
117
+ # @return true|false
118
+ # --
110
119
  def ===(other)
111
120
  other.is_a?(self.class) && @path == other
112
121
  end
113
122
 
114
- # --------------------------------------------------------------------------
123
+ # --
124
+ # @example Pathutil.new("/hello") >= Pathutil.new("/") # => true
125
+ # @example Pathutil.new("/hello") >= Pathutil.new("/hello") # => true
115
126
  # Checks to see if a path falls within a path and deeper or is the other.
116
- # Example: Pathutil.new("/hello") >= Pathutil.new("/hello") # => true
117
- # Example: Pathutil.new("/hello") >= Pathutil.new("/") # => true
118
- # --------------------------------------------------------------------------
119
-
127
+ # @return true|false
128
+ # --
120
129
  def >=(other)
121
130
  mine, other = expanded_paths(other)
122
131
  return true if other == mine
123
132
  mine.in_path?(other)
124
133
  end
125
134
 
126
- # --------------------------------------------------------------------------
135
+ # --
136
+ # @example Pathutil.new("/hello/world") > Pathutil.new("/hello") # => true
127
137
  # Strictly checks to see if a path is deeper but within the path of the other.
128
- # Example: Pathutil.new("/hello/world") > Pathutil.new("/hello") # => true
129
- # --------------------------------------------------------------------------
130
-
138
+ # @return true|false
139
+ # --
131
140
  def >(other)
132
141
  mine, other = expanded_paths(other)
133
142
  return false if other == mine
134
143
  mine.in_path?(other)
135
144
  end
136
145
 
137
- # --------------------------------------------------------------------------
146
+ # --
147
+ # @example Pathutil.new("/") < Pathutil.new("/hello") # => true
138
148
  # Strictly check to see if a path is behind other path but within it.
139
- # Example: Pathutil.new("/") < Pathutil.new("/hello") # => true
140
- # --------------------------------------------------------------------------
141
-
149
+ # @return true|false
150
+ # --
142
151
  def <(other)
143
152
  mine, other = expanded_paths(other)
144
153
  return false if other == mine
145
154
  other.in_path?(mine)
146
155
  end
147
156
 
148
- # --------------------------------------------------------------------------
157
+ # --
149
158
  # Check to see if a path is behind the other path but within it.
150
- # Example: Pathutil.new("/hello") < Pathutil.new("/hello") # => true
151
- # Example: Pathutil.new("/") < Pathutil.new("/hello") # => true
152
- # --------------------------------------------------------------------------
153
-
159
+ # @example Pathutil.new("/hello") < Pathutil.new("/hello") # => true
160
+ # @example Pathutil.new("/") < Pathutil.new("/hello") # => true
161
+ # @return true|false
162
+ # --
154
163
  def <=(other)
155
164
  mine, other = expanded_paths(other)
156
165
  return true if other == mine
157
166
  other.in_path?(mine)
158
167
  end
159
168
 
160
- # --------------------------------------------------------------------------
169
+ # --
170
+ # @note "./" is considered relative.
161
171
  # Check to see if the path is absolute, as in: starts with "/"
162
- # Note: "./" is considered relative.
163
- # --------------------------------------------------------------------------
164
-
172
+ # @return true|false
173
+ # --
165
174
  def absolute?
166
175
  @path.start_with?("/")
167
176
  end
168
177
 
169
- # --------------------------------------------------------------------------
178
+ # --
179
+ # @yield Pathutil
170
180
  # Break apart the path and yield each with the previous parts.
171
- # Example: Pathutil.new("/hello/world").ascend.to_a # => ["/", "/hello", "/hello/world"]
172
- # Example: Pathutil.new("/hello/world").ascend { |path| $stdout.puts path }
173
- # --------------------------------------------------------------------------
174
-
181
+ # @example Pathutil.new("/hello/world").ascend.to_a # => ["/", "/hello", "/hello/world"]
182
+ # @example Pathutil.new("/hello/world").ascend { |path| $stdout.puts path }
183
+ # @return Enum
184
+ # --
175
185
  def ascend
176
186
  unless block_given?
177
187
  return to_enum(
@@ -195,12 +205,13 @@ class Pathutil
195
205
  nil
196
206
  end
197
207
 
198
- # --------------------------------------------------------------------------
208
+ # --
209
+ # @yield Pathutil
199
210
  # Break apart the path in reverse order and descend into the path.
200
- # Example: Pathutil.new("/hello/world").descend.to_a # => ["/hello/world", "/hello", "/"]
201
- # Example: Pathutil.new("/hello/world").descend { |path| $stdout.puts path }
202
- # --------------------------------------------------------------------------
203
-
211
+ # @example Pathutil.new("/hello/world").descend.to_a # => ["/hello/world", "/hello", "/"]
212
+ # @example Pathutil.new("/hello/world").descend { |path| $stdout.puts path }
213
+ # @return Enum
214
+ # --
204
215
  def descend
205
216
  unless block_given?
206
217
  return to_enum(
@@ -215,11 +226,12 @@ class Pathutil
215
226
  nil
216
227
  end
217
228
 
218
- # --------------------------------------------------------------------------
219
- # Example: Pathutil.new("/hello/world").each_line { |line| $stdout.puts line }
229
+ # --
230
+ # @yield Pathutil
231
+ # @example Pathutil.new("/hello/world").each_line { |line| $stdout.puts line }
220
232
  # Wraps `readlines` and allows you to yield on the result.
221
- # --------------------------------------------------------------------------
222
-
233
+ # @return Enum
234
+ # --
223
235
  def each_line
224
236
  return to_enum(__method__) unless block_given?
225
237
  readlines.each do |line|
@@ -229,30 +241,30 @@ class Pathutil
229
241
  nil
230
242
  end
231
243
 
232
- # --------------------------------------------------------------------------
233
- # Example: Pathutil.new("/hello").fnmatch?("/hello") # => true
244
+ # --
245
+ # @example Pathutil.new("/hello").fnmatch?("/hello") # => true
234
246
  # Unlike traditional `fnmatch`, with this one `Regexp` is allowed.
235
- # Example: Pathutil.new("/hello").fnmatch?(/h/) # => true
236
- # See: `File#fnmatch` for more information.
237
- # --------------------------------------------------------------------------
238
-
247
+ # @example Pathutil.new("/hello").fnmatch?(/h/) # => true
248
+ # @see `File#fnmatch` for more information.
249
+ # @return true|false
250
+ # --
239
251
  def fnmatch?(matcher)
240
252
  matcher.is_a?(Regexp) ? !!(self =~ matcher) : \
241
253
  File.fnmatch(matcher, self)
242
254
  end
243
255
 
244
- # --------------------------------------------------------------------------
256
+ # --
245
257
  # Allows you to quickly determine if the file is the root folder.
246
- # --------------------------------------------------------------------------
247
-
258
+ # @return true|false
259
+ # --
248
260
  def root?
249
- self == File::SEPARATOR
261
+ !!(self =~ /\A(?:[A-Za-z]:)?(?:\\+|\/+)\Z/)
250
262
  end
251
263
 
252
- # --------------------------------------------------------------------------
264
+ # --
253
265
  # Allows you to check if the current path is in the path you want.
254
- # --------------------------------------------------------------------------
255
-
266
+ # @return true|false
267
+ # --
256
268
  def in_path?(path)
257
269
  path = self.class.new(path).expand_path.split_path
258
270
  mine = (symlink?? expand_path.realpath : expand_path).split_path
@@ -260,16 +272,17 @@ class Pathutil
260
272
  true
261
273
  end
262
274
 
263
- # --------------------------------------------------------------------------
275
+ # --
264
276
 
265
277
  def inspect
266
278
  "#<#{self.class}:#{@path}>"
267
279
  end
268
280
 
269
- # --------------------------------------------------------------------------
281
+ # --
282
+ # @return Array<Pathutil>
270
283
  # Grab all of the children from the current directory, including hidden.
271
- # --------------------------------------------------------------------------
272
-
284
+ # @yield Pathutil
285
+ # --
273
286
  def children
274
287
  ary = []
275
288
 
@@ -288,11 +301,12 @@ class Pathutil
288
301
  ary
289
302
  end
290
303
 
291
- # --------------------------------------------------------------------------
304
+ # --
305
+ # @yield Pathutil
292
306
  # Allows you to glob however you wish to glob in the current `Pathutil`
293
- # See: `File::Constants` for a list of flags.
294
- # --------------------------------------------------------------------------
295
-
307
+ # @see `File::Constants` for a list of flags.
308
+ # @return Enum
309
+ # --
296
310
  def glob(pattern, flags = 0)
297
311
  unless block_given?
298
312
  return to_enum(
@@ -311,11 +325,12 @@ class Pathutil
311
325
  nil
312
326
  end
313
327
 
314
- # --------------------------------------------------------------------------
328
+ # --
329
+ # @yield &block
315
330
  # Move to the current directory temporarily (or for good) and do work son.
316
- # Note: you do not need to ship a block at all.
317
- # --------------------------------------------------------------------------
318
-
331
+ # @note you do not need to ship a block at all.
332
+ # @return nil
333
+ # --
319
334
  def chdir
320
335
  if !block_given?
321
336
  Dir.chdir(
@@ -329,10 +344,11 @@ class Pathutil
329
344
  end
330
345
  end
331
346
 
332
- # --------------------------------------------------------------------------
347
+ # --
348
+ # @yield Pathutil
333
349
  # Find all files without care and yield the given block.
334
- # --------------------------------------------------------------------------
335
-
350
+ # @return Enum
351
+ # --
336
352
  def find
337
353
  return to_enum(__method__) unless block_given?
338
354
  Find.find @path do |val|
@@ -340,10 +356,11 @@ class Pathutil
340
356
  end
341
357
  end
342
358
 
343
- # --------------------------------------------------------------------------
359
+ # --
360
+ # @yield Pathutil
344
361
  # Splits the path returning each part (filename) back to you.
345
- # --------------------------------------------------------------------------
346
-
362
+ # @return Enum
363
+ # --
347
364
  def each_filename
348
365
  return to_enum(__method__) unless block_given?
349
366
  @path.split(File::SEPARATOR).delete_if(&:empty?).each do |file|
@@ -351,11 +368,11 @@ class Pathutil
351
368
  end
352
369
  end
353
370
 
354
- # --------------------------------------------------------------------------
355
- # Note: This will simply return self if "/".
371
+ # --
356
372
  # Get the parent of the current path.
357
- # --------------------------------------------------------------------------
358
-
373
+ # @note This will simply return self if "/".
374
+ # @return Pathutil
375
+ # --
359
376
  def parent
360
377
  return self if @path == "/"
361
378
  self.class.new(absolute?? File.dirname(@path) : File.join(
@@ -363,30 +380,31 @@ class Pathutil
363
380
  ))
364
381
  end
365
382
 
366
- # --------------------------------------------------------------------------
383
+ # --
384
+ # @yield Pathutil
367
385
  # Split the file into its dirname and basename, so you can do stuff.
368
- # --------------------------------------------------------------------------
369
-
386
+ # @return nil
387
+ # --
370
388
  def split
371
389
  File.split(@path).collect! do |path|
372
390
  self.class.new(path)
373
391
  end
374
392
  end
375
393
 
376
- # --------------------------------------------------------------------------
394
+ # --
395
+ # @note Your extension should start with "."
377
396
  # Replace a files extension with your given extension.
378
- # Note: Your extension should start with "."
379
- # --------------------------------------------------------------------------
380
-
397
+ # @return Pathutil
398
+ # --
381
399
  def sub_ext(ext)
382
400
  self.class.new(@path.chomp(File.extname(@path)) + ext)
383
401
  end
384
402
 
385
- # --------------------------------------------------------------------------
403
+ # --
386
404
  # A less complex version of `relative_path_from` that simply uses a
387
405
  # `Regexp` and returns the full path if it cannot be determined.
388
- # --------------------------------------------------------------------------
389
-
406
+ # @return Pathutil
407
+ # --
390
408
  def relative_path_from(from)
391
409
  from = self.class.new(from).expand_path.gsub(%r!/$!, "")
392
410
  self.class.new(expand_path.gsub(%r!^#{
@@ -394,28 +412,28 @@ class Pathutil
394
412
  }/!, ""))
395
413
  end
396
414
 
397
- # --------------------------------------------------------------------------
415
+ # --
398
416
  # Expands the path and left joins the root to the path.
399
- # --------------------------------------------------------------------------
400
-
417
+ # @return Pathutil
418
+ # --
401
419
  def enforce_root(root)
402
420
  curr, root = expanded_paths(root)
403
421
  if curr.in_path?(root)
404
422
  return curr
405
423
 
406
424
  else
407
- File.join(
425
+ Pathutil.new(File.join(
408
426
  root, curr
409
- )
427
+ ))
410
428
  end
411
429
  end
412
430
 
413
- # --------------------------------------------------------------------------
431
+ # --
414
432
  # Copy a directory, allowing symlinks if the link falls inside of the root.
415
433
  # This is indented for people who wish some safety to their copies.
416
- # NOTE: Ignore is ignored on safe_copy file because it's explicit.
417
- # --------------------------------------------------------------------------
418
-
434
+ # @note Ignore is ignored on safe_copy file because it's explicit.
435
+ # @return nil
436
+ # --
419
437
  def safe_copy(to, root: nil, ignore: [])
420
438
  raise ArgumentError, "must give a root" unless root
421
439
  root = self.class.new(root)
@@ -433,31 +451,29 @@ class Pathutil
433
451
  end
434
452
  end
435
453
 
436
- # --------------------------------------------------------------------------
437
- # See: `self.class.normalize` as this is an alias.
438
- # --------------------------------------------------------------------------
439
-
454
+ # --
455
+ # @see `self.class.normalize` as this is an alias.
456
+ # --
440
457
  def normalize
441
458
  return @normalize ||= begin
442
459
  self.class.normalize
443
460
  end
444
461
  end
445
462
 
446
- # --------------------------------------------------------------------------
447
- # See: `self.class.encoding` as this is an alias.
448
- # --------------------------------------------------------------------------
449
-
463
+ # --
464
+ # @see `self.class.encoding` as this is an alias.
465
+ # --
450
466
  def encoding
451
467
  return @encoding ||= begin
452
468
  self.class.encoding
453
469
  end
454
470
  end
455
471
 
456
- # --------------------------------------------------------------------------
472
+ # --
473
+ # @note You can set the default encodings via the class.
457
474
  # Read took two steroid shots: it can normalize your string, and encode.
458
- # Note: You can set the default encodings via the class.
459
- # --------------------------------------------------------------------------
460
-
475
+ # @return String
476
+ # --
461
477
  def read(*args, **kwd)
462
478
  kwd[:encoding] ||= encoding
463
479
 
@@ -473,11 +489,11 @@ class Pathutil
473
489
  end
474
490
  end
475
491
 
476
- # --------------------------------------------------------------------------
492
+ # --
493
+ # @note You can set the default encodings via the class.
477
494
  # Binread took two steroid shots: it can normalize your string, and encode.
478
- # Note: You can set the default encodings via the class.
479
- # --------------------------------------------------------------------------
480
-
495
+ # @return String
496
+ # --
481
497
  def binread(*args, **kwd)
482
498
  kwd[:encoding] ||= encoding
483
499
 
@@ -493,11 +509,11 @@ class Pathutil
493
509
  end
494
510
  end
495
511
 
496
- # --------------------------------------------------------------------------
512
+ # --
513
+ # @note You can set the default encodings via the class.
497
514
  # Readlines took two steroid shots: it can normalize your string, and encode.
498
- # Note: You can set the default encodings via the class.
499
- # --------------------------------------------------------------------------
500
-
515
+ # @return Array<String>
516
+ # --
501
517
  def readlines(*args, **kwd)
502
518
  kwd[:encoding] ||= encoding
503
519
 
@@ -513,11 +529,11 @@ class Pathutil
513
529
  end
514
530
  end
515
531
 
516
- # --------------------------------------------------------------------------
532
+ # --
533
+ # @note You can set the default encodings via the class.
517
534
  # Write took two steroid shots: it can normalize your string, and encode.
518
- # Note: You can set the default encodings via the class.
519
- # --------------------------------------------------------------------------
520
-
535
+ # @return Fixnum<Bytes>
536
+ # --
521
537
  def write(data, *args, **kwd)
522
538
  kwd[:encoding] ||= encoding
523
539
 
@@ -533,11 +549,11 @@ class Pathutil
533
549
  end
534
550
  end
535
551
 
536
- # --------------------------------------------------------------------------
552
+ # --
553
+ # @note You can set the default encodings via the class.
537
554
  # Binwrite took two steroid shots: it can normalize your string, and encode.
538
- # Note: You can set the default encodings via the class.
539
- # --------------------------------------------------------------------------
540
-
555
+ # @return Fixnum<Bytes>
556
+ # --
541
557
  def binwrite(data, *args, **kwd)
542
558
  kwd[:encoding] ||= encoding
543
559
 
@@ -553,7 +569,7 @@ class Pathutil
553
569
  end
554
570
  end
555
571
 
556
- # --------------------------------------------------------------------------
572
+ # --
557
573
 
558
574
  def to_regexp(guard: true)
559
575
  Regexp.new((guard ? "\\A" : "") + Regexp.escape(
@@ -561,19 +577,68 @@ class Pathutil
561
577
  ))
562
578
  end
563
579
 
564
- # --------------------------------------------------------------------------
565
- # Expand the paths and return.
566
- # --------------------------------------------------------------------------
580
+ # --
581
+ # @todo See if you can speed this up by removing the enum and switching
582
+ # to something like start=true,false.
583
+ # --
567
584
 
585
+ def aggressive_cleanpath
586
+ return self.class.new("/") if root?
587
+
588
+ _out = split_path.each_with_object([]) do |part, out|
589
+ next if part == "." || (part == ".." && out.last == "")
590
+ if part == ".." && out.last && out.last != ".."
591
+ out.pop
592
+
593
+ else
594
+ out.push(
595
+ part
596
+ )
597
+ end
598
+ end
599
+
600
+ # --
601
+
602
+ return self.class.new("/") if _out == [""].freeze
603
+ return self.class.new(".") if _out.empty? && (end_with?(".") || relative?)
604
+ self.class.new(_out.join("/"))
605
+ end
606
+
607
+ # --
608
+
609
+ def conservative_cleanpath
610
+ _out = (path = split_path).to_enum.with_index(0).each_with_object([]) do |(part, i), out|
611
+ next if part == "." || (part == ".." && out.last == "")
612
+ out.push(
613
+ part
614
+ )
615
+ end
616
+
617
+ # --
618
+
619
+ if !_out.empty? && basename == "." && _out.last != "" && _out.last != ".."
620
+ _out << "."
621
+ end
622
+
623
+ # --
624
+
625
+ return self.class.new("/") if _out == [""].freeze
626
+ return self.class.new(".") if _out.empty? && (end_with?(".") || relative?)
627
+ return self.class.new(_out.join("/")).join("") if @path =~ /\/\z/ && _out.last != "." && _out.last != ".."
628
+ self.class.new(_out.join("/"))
629
+ end
630
+
631
+ # --
632
+ # Expand the paths and return.
633
+ # --
568
634
  private
569
635
  def expanded_paths(path)
570
636
  return expand_path, self.class.new(path).expand_path
571
637
  end
572
638
 
573
- # --------------------------------------------------------------------------
639
+ # --
574
640
  # Safely copy a file.
575
- # --------------------------------------------------------------------------
576
-
641
+ # --
577
642
  private
578
643
  def safe_copy_file(to, root: nil)
579
644
  raise Errno::EPERM, "#{self} not in #{root}" unless in_path?(root)
@@ -582,10 +647,9 @@ class Pathutil
582
647
  })
583
648
  end
584
649
 
585
- # --------------------------------------------------------------------------
650
+ # --
586
651
  # Safely copy a directory and it's sub-files.
587
- # --------------------------------------------------------------------------
588
-
652
+ # --
589
653
  private
590
654
  def safe_copy_directory(to, root: nil, ignore: [])
591
655
  ignore = [ignore].flatten.uniq
@@ -623,11 +687,11 @@ class Pathutil
623
687
  class << self
624
688
  attr_writer :encoding
625
689
 
626
- # ------------------------------------------------------------------------
690
+ # --
691
+ # @note We do nothing special here.
627
692
  # Get the current directory that Ruby knows about.
628
- # Note: We do nothing special here.
629
- # ------------------------------------------------------------------------
630
-
693
+ # @return Pathutil
694
+ # --
631
695
  def pwd
632
696
  new(
633
697
  Dir.pwd
@@ -637,23 +701,21 @@ class Pathutil
637
701
  alias gcwd pwd
638
702
  alias cwd pwd
639
703
 
640
- # ------------------------------------------------------------------------
641
- # Note: you are encouraged to override this if you need to.
704
+ # --
705
+ # @note you are encouraged to override this if you need to.
642
706
  # Aliases the default system encoding to us so that we can do most read
643
707
  # and write operations with that encoding, instead of being crazy.
644
- # ------------------------------------------------------------------------
645
-
708
+ # --
646
709
  def encoding
647
710
  return @encoding ||= begin
648
711
  Encoding.default_external
649
712
  end
650
713
  end
651
714
 
652
- # ------------------------------------------------------------------------
715
+ # --
653
716
  # Normalize CRLF -> LF on Windows reads, to ease your troubles.
654
717
  # Normalize LF -> CLRF on Windows write, to ease your troubles.
655
- # ------------------------------------------------------------------------
656
-
718
+ # --
657
719
  def normalize
658
720
  return @normalize ||= {
659
721
  :read => Gem.win_platform?,
@@ -661,12 +723,12 @@ class Pathutil
661
723
  }
662
724
  end
663
725
 
664
- # ------------------------------------------------------------------------
726
+ # --
665
727
  # Make a temporary directory.
666
- # Note: if you adruptly exit it will not remove the dir.
667
- # Note: this directory is removed on exit.
668
- # ------------------------------------------------------------------------
669
-
728
+ # @note if you adruptly exit it will not remove the dir.
729
+ # @note this directory is removed on exit.
730
+ # @return Pathutil
731
+ # --
670
732
  def tmpdir(*args)
671
733
  rtn = new(make_tmpname(*args)).tap(&:mkdir)
672
734
  ObjectSpace.define_finalizer(rtn, proc do
@@ -676,12 +738,12 @@ class Pathutil
676
738
  rtn
677
739
  end
678
740
 
679
- # ------------------------------------------------------------------------
741
+ # --
680
742
  # Make a temporary file.
681
- # Note: if you adruptly exit it will not remove the dir.
682
- # Note: this file is removed on exit.
683
- # ------------------------------------------------------------------------
684
-
743
+ # @note if you adruptly exit it will not remove the dir.
744
+ # @note this file is removed on exit.
745
+ # @return Pathutil
746
+ # --
685
747
  def tmpfile(*args)
686
748
  rtn = new(make_tmpname(*args)).tap(&:touch)
687
749
  ObjectSpace.define_finalizer(rtn, proc do
@@ -692,21 +754,23 @@ class Pathutil
692
754
  end
693
755
  end
694
756
 
695
- # --------------------------------------------------------------------------
757
+ # --
696
758
 
697
- rb_delegate :sub, :to => :@path, :wrap => true
698
- rb_delegate :chomp, :to => :@path, :wrap => true
699
- rb_delegate :gsub, :to => :@path, :wrap => true
700
- rb_delegate :=~, :to => :@path
701
- rb_delegate :==, :to => :@path
702
- rb_delegate :to_s, :to => :@path
703
- rb_delegate :freeze, :to => :@path
704
- rb_delegate :frozen?, :to => :@path
705
- rb_delegate :to_str, :to => :@path
706
- rb_delegate :"!~", :to => :@path
707
- rb_delegate :<=>, :to => :@path
759
+ rb_delegate :sub, :to => :@path, :wrap => true
760
+ rb_delegate :chomp, :to => :@path, :wrap => true
761
+ rb_delegate :gsub, :to => :@path, :wrap => true
762
+ rb_delegate :=~, :to => :@path
763
+ rb_delegate :==, :to => :@path
764
+ rb_delegate :to_s, :to => :@path
765
+ rb_delegate :freeze, :to => :@path
766
+ rb_delegate :end_with?, :to => :@path
767
+ rb_delegate :start_with?, :to => :@path
768
+ rb_delegate :frozen?, :to => :@path
769
+ rb_delegate :to_str, :to => :@path
770
+ rb_delegate :"!~", :to => :@path
771
+ rb_delegate :<=>, :to => :@path
708
772
 
709
- # --------------------------------------------------------------------------
773
+ # --
710
774
 
711
775
  rb_delegate :chmod, :to => :File, :args => { :after => :@path }
712
776
  rb_delegate :lchown, :to => :File, :args => { :after => :@path }
@@ -738,7 +802,7 @@ class Pathutil
738
802
  rb_delegate :open, :to => :File, :args => :@path
739
803
  rb_delegate :stat, :to => :File, :args => :@path
740
804
 
741
- # --------------------------------------------------------------------------
805
+ # --
742
806
 
743
807
  rb_delegate :pipe?, :to => :FileTest, :args => :@path
744
808
  rb_delegate :file?, :to => :FileTest, :args => :@path
@@ -763,7 +827,7 @@ class Pathutil
763
827
  rb_delegate :exist?, :to => :FileTest, :args => :@path
764
828
  rb_delegate :size?, :to => :FileTest, :args => :@path
765
829
 
766
- # --------------------------------------------------------------------------
830
+ # --
767
831
 
768
832
  rb_delegate :rm_rf, :to => :FileUtils, :args => :@path
769
833
  rb_delegate :rm_r, :to => :FileUtils, :args => :@path
@@ -775,13 +839,13 @@ class Pathutil
775
839
  rb_delegate :mkpath, :to => :FileUtils, :args => :@path
776
840
  rb_delegate :cp, :to => :FileUtils, :args => :@path
777
841
 
778
- # --------------------------------------------------------------------------
842
+ # --
779
843
 
780
844
  rb_delegate :each_child, :to => :children
781
845
  rb_delegate :each_entry, :to => :children
782
846
  rb_delegate :to_a, :to => :children
783
847
 
784
- # --------------------------------------------------------------------------
848
+ # --
785
849
 
786
850
  rb_delegate :opendir, :to => :Dir, :alias_of => :open
787
851
  rb_delegate :relative?, :to => :self, :alias_of => :absolute?, :bool => :reverse
@@ -789,7 +853,7 @@ class Pathutil
789
853
  rb_delegate :shellescape, :to => :Shellwords, :args => :@path
790
854
  rb_delegate :mkdir, :to => :Dir, :args => :@path
791
855
 
792
- # --------------------------------------------------------------------------
856
+ # --
793
857
 
794
858
  alias + join
795
859
  alias delete rm
@@ -798,6 +862,8 @@ class Pathutil
798
862
  alias last basename
799
863
  alias entries children
800
864
  alias make_symlink symlink
865
+ alias cleanpath_conservative conservative_cleanpath
866
+ alias cleanpath_aggressive aggressive_cleanpath
801
867
  alias fnmatch fnmatch?
802
868
  alias make_link link
803
869
  alias first dirname
@@ -2,7 +2,7 @@ class Pathutil
2
2
  module Helpers
3
3
  extend self
4
4
 
5
- # ------------------------------------------------------------------------
5
+ # --
6
6
 
7
7
  def allowed
8
8
  return @allowed ||= begin
@@ -15,11 +15,11 @@ class Pathutil
15
15
  end
16
16
  end
17
17
 
18
- # ------------------------------------------------------------------------
18
+ # --
19
19
  # Wraps around YAML and SafeYAML to provide alternatives to Rubies.
20
- # Note: We default aliases to yes so we can detect if you explicit true.
21
- # ------------------------------------------------------------------------
22
-
20
+ # @note We default aliases to yes so we can detect if you explicit true.
21
+ # @return Hash
22
+ # --
23
23
  def load_yaml(data, safe: true, whitelist_classes: self.allowed[:yaml][:classes], \
24
24
  whitelist_symbols: self.allowed[:yaml][:symbols], aliases: :yes)
25
25
 
@@ -46,10 +46,10 @@ class Pathutil
46
46
  end
47
47
  end
48
48
 
49
- # ------------------------------------------------------------------------
49
+ # --
50
50
  # Make a temporary name suitable for temporary files and directories.
51
- # ------------------------------------------------------------------------
52
-
51
+ # @return String
52
+ # --
53
53
  def make_tmpname(prefix = "", suffix = nil, root = nil)
54
54
  prefix = tmpname_prefix(prefix)
55
55
  suffix = tmpname_suffix(suffix)
@@ -60,7 +60,7 @@ class Pathutil
60
60
  ))
61
61
  end
62
62
 
63
- # ------------------------------------------------------------------------
63
+ # --
64
64
 
65
65
  private
66
66
  def tmpname_suffix(suffix)
@@ -69,11 +69,10 @@ class Pathutil
69
69
  suffix
70
70
  end
71
71
 
72
- # ------------------------------------------------------------------------
72
+ # --
73
73
  # Cleanup the temp name prefix, joining if necessary.
74
74
  # rubocop:disable Style/ParallelAssignment
75
- # ------------------------------------------------------------------------
76
-
75
+ # --
77
76
  private
78
77
  def tmpname_prefix(prefix)
79
78
  ext, prefix = prefix, "" if !prefix.is_a?(Array) && prefix.start_with?(".")
@@ -90,11 +89,10 @@ class Pathutil
90
89
  ]
91
90
  end
92
91
 
93
- # ------------------------------------------------------------------------
92
+ # --
94
93
  # Wrap around, cleanup, deprecate and use SafeYAML.
95
94
  # rubocop:enable Style/ParallelAssignment
96
- # ------------------------------------------------------------------------
97
-
95
+ # --
98
96
  private
99
97
  def setup_safe_yaml(whitelist_classes, aliases)
100
98
  warn "WARN: SafeYAML does not support disabling of aliases." if aliases && aliases != :yes
@@ -1,9 +1,7 @@
1
- # ----------------------------------------------------------------------------
2
1
  # Frozen-string-literal: true
3
2
  # Copyright: 2015-2016 Jordon Bedwell - MIT License
4
3
  # Encoding: utf-8
5
- # ----------------------------------------------------------------------------
6
4
 
7
5
  class Pathutil
8
- VERSION = "0.9.0"
6
+ VERSION = "0.10.0"
9
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pathutil
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordon Bedwell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-28 00:00:00.000000000 Z
11
+ date: 2016-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: forwardable-extended
@@ -57,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
57
  version: '0'
58
58
  requirements: []
59
59
  rubyforge_project:
60
- rubygems_version: 2.6.3
60
+ rubygems_version: 2.6.4
61
61
  signing_key:
62
62
  specification_version: 4
63
63
  summary: Almost like Pathname but just a little less insane.