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