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 +4 -4
- data/lib/pathutil.rb +262 -196
- data/lib/pathutil/helpers.rb +13 -15
- data/lib/pathutil/version.rb +1 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff3970eccd4ba23f0967096b403f8877d817e7b1
|
4
|
+
data.tar.gz: f56f0ec8f93744500a8a8cce865eae14789492af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
#
|
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
|
-
#
|
28
|
-
#
|
29
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
|
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
|
-
#
|
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
|
-
#
|
117
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
151
|
-
#
|
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
|
-
#
|
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
|
-
#
|
172
|
-
#
|
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
|
-
#
|
201
|
-
#
|
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
|
-
#
|
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
|
-
#
|
244
|
+
# --
|
245
|
+
# @example Pathutil.new("/hello").fnmatch?("/hello") # => true
|
234
246
|
# Unlike traditional `fnmatch`, with this one `Regexp` is allowed.
|
235
|
-
#
|
236
|
-
#
|
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
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
667
|
-
#
|
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
|
-
#
|
682
|
-
#
|
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,
|
698
|
-
rb_delegate :chomp,
|
699
|
-
rb_delegate :gsub,
|
700
|
-
rb_delegate :=~,
|
701
|
-
rb_delegate :==,
|
702
|
-
rb_delegate :to_s,
|
703
|
-
rb_delegate :freeze,
|
704
|
-
rb_delegate :
|
705
|
-
rb_delegate :
|
706
|
-
rb_delegate :
|
707
|
-
rb_delegate
|
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
|
data/lib/pathutil/helpers.rb
CHANGED
@@ -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
|
-
#
|
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
|
data/lib/pathutil/version.rb
CHANGED
@@ -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.
|
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.
|
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-
|
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.
|
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.
|