pathutil 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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.