pathutil 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 312093b72daeed797421e82320e9b69dbe8cca1c
4
+ data.tar.gz: be2774aba80baf6d8ec0638ba69a5014d5ca2bdf
5
+ SHA512:
6
+ metadata.gz: c66c018dc735686f536246dd21ada663d5e676add05f1eca73a351bbd636c49a0aaf1bc0269294266d4922a591feeddeef8114c8d33b032cacc1cfdda1d73004
7
+ data.tar.gz: 9103cd6a157ae019af799844af46116158500317942575a4f8e1f939fabed3003f8af1bbe06eac26f8f0d1b8758758154bea80fbf7f457bb9aa1a7313a8155ad
data/Gemfile ADDED
@@ -0,0 +1,22 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015-2016 Jordon Bedwell - MIT License
3
+ # Encoding: utf-8
4
+
5
+ source "https://rubygems.org"
6
+ gem "rake", :require => false
7
+ gemspec
8
+
9
+ group :test do
10
+ gem "codeclimate-test-reporter", :require => false
11
+ gem "safe_yaml", :require => false
12
+ end
13
+
14
+ group :development do
15
+ gem "rspec", :require => false
16
+ gem "rspec-helpers", :require => false
17
+ gem "rubocop", :github => "bbatsov/rubocop", :require => false
18
+ gem "luna-rspec-formatters", :require => false
19
+ gem "benchmark-ips", :require => false
20
+ gem "simple-ansi", :require => false
21
+ gem "pry", :require => false
22
+ end
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2015-2016 Jordon Bedwell
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included
11
+ in all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ # Frozen-string-literal: true
2
+ # Copyright: 2015-2016 Jordon Bedwell - MIT License
3
+ # Encoding: utf-8
4
+
5
+ require "open3"
6
+ require "rspec/core/rake_task"
7
+ require_relative "benchmark/support/task"
8
+ require "simple/ansi"
9
+ require "pathutil"
10
+ require "json"
11
+
12
+ task :default => [:spec]
13
+ RSpec::Core::RakeTask.new :spec
14
+ BenchmarkTask.new :benchmark
15
+ task :test => :spec
16
+
17
+ namespace :diff do
18
+ desc "List methods we have that Pathname doesn't."
19
+ task :methods do
20
+ methods = Pathutil.instance_methods - Pathname.instance_methods - Object.instance_methods
21
+ methods.each do |method|
22
+ $stdout.print "- ", "`", method, "`", "\n"
23
+ end
24
+ end
25
+ end
26
+
27
+ namespace :missing do
28
+ desc "List methods we are missing."
29
+ task :methods do
30
+ methods = Pathname.instance_methods - Pathutil.instance_methods - Object.instance_methods
31
+ methods-= [
32
+ :cleanpath
33
+ ]
34
+
35
+ methods.each do |method|
36
+ $stdout.puts method
37
+ end
38
+ end
39
+ end
40
+
41
+ namespace :pathname do
42
+ desc "List all of Pathnames methods."
43
+ task :methods do
44
+ methods = Pathname.instance_methods - Object.instance_methods
45
+ methods.each_with_index do |method, index|
46
+ $stdout.print method
47
+ unless index == methods.size - 1
48
+ $stdout.print ", "
49
+ end
50
+ end
51
+
52
+ $stdout.puts
53
+ end
54
+ end
55
+
56
+ desc "List all of Pathutils methods."
57
+ task :methods do
58
+ methods = Pathutil.instance_methods - Object.instance_methods
59
+ methods.each_with_index do |method, index|
60
+ $stdout.print "`", method, "`"
61
+ $stdout.print ", " unless index == methods.size - 1
62
+ end
63
+
64
+ $stdout.puts
65
+ end
data/lib/pathutil.rb ADDED
@@ -0,0 +1,783 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2015-2016 Jordon Bedwell - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ require "forwardable/extended"
8
+ require "find"
9
+
10
+ #
11
+
12
+ class Pathutil
13
+ extend Forwardable::Extended
14
+ self.class.send(:attr_writer, :encoding)
15
+ attr_writer :encoding
16
+
17
+ #
18
+
19
+ class << self
20
+
21
+ # ------------------------------------------------------------------------
22
+ # Aliases the default system encoding to us so that we can do most read
23
+ # and write operations with that encoding, instead of being crazy.
24
+ # @note you are encouraged to override this if you need to.
25
+ # ------------------------------------------------------------------------
26
+
27
+ def encoding
28
+ return @encoding ||= begin
29
+ Encoding.default_external
30
+ end
31
+ end
32
+
33
+ # ------------------------------------------------------------------------
34
+ # Normalize CRLF -> LF on Windows reads, to ease your troubles.
35
+ # Normalize LF -> CLRF on Windows write, to ease their troubles.
36
+ # ------------------------------------------------------------------------
37
+
38
+ def normalize
39
+ return @normalize ||= {
40
+ :read => Gem.win_platform?,
41
+ :write => Gem.win_platform?
42
+ }
43
+ end
44
+ end
45
+
46
+ # --------------------------------------------------------------------------
47
+
48
+ def initialize(path)
49
+ @path = path.to_s
50
+ end
51
+
52
+ # --------------------------------------------------------------------------
53
+
54
+ def to_pathname
55
+ Pathname.new(
56
+ self
57
+ )
58
+ end
59
+
60
+ # --------------------------------------------------------------------------
61
+
62
+ def read_yaml(safe: true, whitelist_classes: [], throw_missing: false)
63
+ require "yaml"
64
+
65
+ unless safe
66
+ return YAML.load(
67
+ read
68
+ )
69
+ end
70
+
71
+ if !YAML.respond_to?(:safe_load)
72
+ setup_safe_yaml whitelist_classes
73
+ SafeYAML.load(read, {
74
+ :raise_on_unknown_tag => true
75
+ })
76
+
77
+ else
78
+ YAML.safe_load(read, {
79
+ :whitelist_classes => whitelist_classes
80
+ })
81
+ end
82
+ rescue Errno::ENOENT
83
+ throw_missing ? raise : (
84
+ return {}
85
+ )
86
+ end
87
+
88
+ # --------------------------------------------------------------------------
89
+
90
+ def read_json(throw_missing: false)
91
+ JSON.parse(
92
+ read
93
+ )
94
+
95
+ rescue Errno::ENOENT
96
+ throw_missing ? raise : (
97
+ return {}
98
+ )
99
+ end
100
+
101
+ # --------------------------------------------------------------------------
102
+ # Splits the path into all parts so that you can do step by step comparisons
103
+ # @note The blank part is intentionally left there so that you can rejoin.
104
+ #
105
+ # @example
106
+ # Pathutil.new("/my/path").split_path # => [
107
+ # "", "my", "path"
108
+ # ]
109
+ # --------------------------------------------------------------------------
110
+
111
+ def split_path
112
+ @path.split(
113
+ File::SEPARATOR
114
+ )
115
+ end
116
+
117
+ # --------------------------------------------------------------------------
118
+ # @see `String#==` for more details.
119
+ # A stricter version of `==` that also makes sure the object matches.
120
+ # @param [Pathutil] other the comparee.
121
+ # @return true, false
122
+ # --------------------------------------------------------------------------
123
+
124
+ def ===(other)
125
+ other.is_a?(self.class) && @path == other
126
+ end
127
+
128
+ # --------------------------------------------------------------------------
129
+ # @example Pathutil.new("/hello") >= Pathutil.new("/") # => true
130
+ # @example Pathutil.new("/hello") >= Pathutil.new("/hello") # => true
131
+ # Checks to see if a path falls within a path and deeper or is the other.
132
+ # @param path the path that should be above the object.
133
+ # @return true, false
134
+ # --------------------------------------------------------------------------
135
+
136
+ def >=(other)
137
+ mine, other = expanded_paths(other)
138
+ return true if other == mine
139
+ mine.in_path?(other)
140
+ end
141
+
142
+ # --------------------------------------------------------------------------
143
+ # @example Pathutil.new("/hello/world") > Pathutil.new("/hello") # => true
144
+ # Strictly checks to see if a path is deeper but within the path of the other.
145
+ # @param path the path that should be above the object.
146
+ # @return true, false
147
+ # --------------------------------------------------------------------------
148
+
149
+ def >(other)
150
+ mine, other = expanded_paths(other)
151
+ return false if other == mine
152
+ mine.in_path?(other)
153
+ end
154
+
155
+ # --------------------------------------------------------------------------
156
+ # @example Pathutil.new("/") < Pathutil.new("/hello") # => true
157
+ # Strictly check to see if a path is behind other path but within it.
158
+ # @param path the path that should be below the object.
159
+ # @return true, false
160
+ # --------------------------------------------------------------------------
161
+
162
+ def <(other)
163
+ mine, other = expanded_paths(other)
164
+ return false if other == mine
165
+ other.in_path?(mine)
166
+ end
167
+
168
+ # --------------------------------------------------------------------------
169
+ # Check to see if a path is behind the other path butt within it.
170
+ # @example Pathutil.new("/hello") < Pathutil.new("/hello") # => true
171
+ # @example Pathutil.new("/") < Pathutil.new("/hello") # => true
172
+ # @param path the path that should be below the object.
173
+ # @return true, false
174
+ # --------------------------------------------------------------------------
175
+
176
+ def <=(other)
177
+ mine, other = expanded_paths(other)
178
+ return true if other == mine
179
+ other.in_path?(mine)
180
+ end
181
+
182
+ # --------------------------------------------------------------------------
183
+ # @note "./" is considered relative.
184
+ # Check to see if the path is absolute, as in: starts with "/"
185
+ # @return true, false
186
+ # --------------------------------------------------------------------------
187
+
188
+ def absolute?
189
+ @path.start_with?("/")
190
+ end
191
+
192
+ # --------------------------------------------------------------------------
193
+ # Break apart the path and yield each with the previous parts.
194
+ # @return Enumerator if no block is given.
195
+ #
196
+ # @example
197
+ # Pathutil.new("/hello/world").ascend.to_a # => [
198
+ # "/", "/hello", "/hello/world"
199
+ # ]
200
+ #
201
+ # @example
202
+ # Pathutil.new("/hello/world").ascend do |path|
203
+ # $stdout.puts path
204
+ # end
205
+ #
206
+ # /
207
+ # /hello
208
+ # /hello/world
209
+ # --------------------------------------------------------------------------
210
+
211
+ def ascend
212
+ unless block_given?
213
+ return to_enum(
214
+ __method__
215
+ )
216
+ end
217
+
218
+ yield(
219
+ path = self
220
+ )
221
+
222
+ while (new_path = path.dirname)
223
+ if path == new_path || new_path == "."
224
+ break
225
+ else
226
+ path = new_path
227
+ yield new_path
228
+ end
229
+ end
230
+
231
+ nil
232
+ end
233
+
234
+ # --------------------------------------------------------------------------
235
+ # Break apart the path in reverse order and descend into the path.
236
+ # @return Enumerator if no block is given.
237
+ #
238
+ # @example
239
+ # Pathutil.new("/hello/world").descend.to_a # => [
240
+ # "/hello/world", "/hello", "/"
241
+ # ]
242
+ #
243
+ # @example
244
+ # Pathutil.new("/hello/world").descend do |path|
245
+ # $stdout.puts path
246
+ # end
247
+ #
248
+ # /hello/world
249
+ # /hello
250
+ # /
251
+ # --------------------------------------------------------------------------
252
+
253
+ def descend
254
+ return ascend.to_a.reverse.to_enum unless block_given?
255
+ ascend.to_a.reverse_each do |val|
256
+ yield val
257
+ end
258
+
259
+ nil
260
+ end
261
+
262
+ # --------------------------------------------------------------------------
263
+ # Wraps `readlines` and allows you to yield on the result.
264
+ #
265
+ # @example
266
+ # Pathutil.new("/hello/world").each_line do |line|
267
+ # $stdout.puts line
268
+ # end
269
+ #
270
+ # Hello
271
+ # World
272
+ # --------------------------------------------------------------------------
273
+
274
+ def each_line
275
+ return to_enum(__method__) unless block_given?
276
+ readlines.each do |line|
277
+ yield line
278
+ end
279
+
280
+ nil
281
+ end
282
+
283
+ # --------------------------------------------------------------------------
284
+ # @see `File#fnmatch` for more information.
285
+ # Unlike traditional `fnmatch`, with this one `Regexp` is allowed.
286
+ # @param [String, Regexp] matcher the matcher used, can be a `Regexp`
287
+ # @example Pathutil.new("/hello").fnmatch?("/hello") # => true
288
+ # @example Pathutil.new("/hello").fnmatch?(/h/) # => true
289
+ # @return true, false
290
+ # --------------------------------------------------------------------------
291
+
292
+ def fnmatch?(matcher)
293
+ matcher.is_a?(Regexp) ? !!(self =~ matcher) : \
294
+ File.fnmatch(self, matcher)
295
+ end
296
+
297
+ # --------------------------------------------------------------------------
298
+ # Allows you to quickly determine if the file is the root folder.
299
+ # @return true, false
300
+ # --------------------------------------------------------------------------
301
+
302
+ def root?
303
+ self == File::SEPARATOR
304
+ end
305
+
306
+ # --------------------------------------------------------------------------
307
+ # @param [Pathutil, String] path the reference.
308
+ # Allows you to check if the current path is in the path you want.
309
+ # @return true, false
310
+ # --------------------------------------------------------------------------
311
+
312
+ def in_path?(path)
313
+ path = self.class.new(path).expand_path.split_path
314
+ mine = (symlink?? expand_path.realpath : expand_path).split_path
315
+ path.each_with_index { |part, index| return false if mine[index] != part }
316
+ true
317
+ end
318
+
319
+ # --------------------------------------------------------------------------
320
+
321
+ def inspect
322
+ "#<#{self.class}:#{@path}>"
323
+ end
324
+
325
+ # --------------------------------------------------------------------------
326
+ # Grab all of the children from the current directory, including hidden.
327
+ # @return Array<Pathutils>
328
+ # --------------------------------------------------------------------------
329
+
330
+ def children
331
+ ary = []
332
+
333
+ Dir.foreach(@path) do |path|
334
+ if path == "." || path == ".."
335
+ next
336
+ else
337
+ path = self.class.new(File.join(@path, path))
338
+ yield path if block_given?
339
+ ary.push(
340
+ path
341
+ )
342
+ end
343
+ end
344
+
345
+ ary
346
+ end
347
+
348
+ # --------------------------------------------------------------------------
349
+ # @see `File::Constants` for a list of flags.
350
+ # Allows you to glob however you wish to glob in the current `Pathutils`
351
+ # @param [String] flags the flags you want to ship to the glob.
352
+ # @param [String] pattern the pattern A.K.A: "**/*"
353
+ # @return Enumerator unless a block is given.
354
+ # --------------------------------------------------------------------------
355
+
356
+ def glob(pattern, flags = 0)
357
+ unless block_given?
358
+ return to_enum(
359
+ __method__, pattern, flags
360
+ )
361
+ end
362
+
363
+ chdir do
364
+ Dir.glob(pattern, flags).each do |file|
365
+ yield self.class.new(
366
+ File.join(@path, file)
367
+ )
368
+ end
369
+ end
370
+
371
+ nil
372
+ end
373
+
374
+ # --------------------------------------------------------------------------
375
+ # @note you do not need to ship a block at all.
376
+ # Move to the current directory temporarily (or for good) and do work son.
377
+ # @return 0, 1 if no block given
378
+ # --------------------------------------------------------------------------
379
+
380
+ def chdir
381
+ if !block_given?
382
+ Dir.chdir(
383
+ @path
384
+ )
385
+
386
+ else
387
+ Dir.chdir @path do
388
+ yield
389
+ end
390
+ end
391
+ end
392
+
393
+ # --------------------------------------------------------------------------
394
+ # @return Enumerator if no block is given.
395
+ # Find all files without care and yield the given block.
396
+ # @see Find.find
397
+ # --------------------------------------------------------------------------
398
+
399
+ def find
400
+ return to_enum(__method__) unless block_given?
401
+ Find.find @path do |val|
402
+ yield self.class.new(val)
403
+ end
404
+ end
405
+
406
+ # --------------------------------------------------------------------------
407
+ # Splits the path returning each part (filename) back to you.
408
+ # @return Enumerator if no block is given.
409
+ # --------------------------------------------------------------------------
410
+
411
+ def each_filename
412
+ return to_enum(__method__) unless block_given?
413
+ @path.split(File::SEPARATOR).delete_if(&:empty?).each do |file|
414
+ yield file
415
+ end
416
+ end
417
+
418
+ # --------------------------------------------------------------------------
419
+
420
+ def parent
421
+ self.class.new(File.join(
422
+ @path, ".."
423
+ ))
424
+ end
425
+
426
+ # --------------------------------------------------------------------------
427
+ # Split the file into its dirname and basename, so you can do stuff.
428
+ # @return File.dirname, File.basename
429
+ # --------------------------------------------------------------------------
430
+
431
+ def split
432
+ File.split(@path).collect! do |path|
433
+ self.class.new(path)
434
+ end
435
+ end
436
+
437
+ # --------------------------------------------------------------------------
438
+ # Replace a files extension with your given extension.
439
+ # --------------------------------------------------------------------------
440
+
441
+ def sub_ext(ext)
442
+ self.class.new(
443
+ "#{@path.gsub(/\..+$/, "")}#{ext}"
444
+ )
445
+ end
446
+
447
+ # --------------------------------------------------------------------------
448
+ # A less complex version of `relative_path_from` that simply uses a
449
+ # `Regexp` and returns the full path if it cannot be relatively determined.
450
+ # @return Pathutils the relative path if it can be determined or is relative.
451
+ # @return Pathutils the full path if relative path cannot be determined
452
+ # --------------------------------------------------------------------------
453
+
454
+ def relative_path_from(from)
455
+ from = self.class.new(from).expand_path.gsub(%r!/$!, "")
456
+ self.class.new(expand_path.gsub(%r!^#{from.regexp_escape}/!, ""))
457
+ end
458
+
459
+ # --------------------------------------------------------------------------
460
+ # Expands the path and left joins the root to the path.
461
+ # @param [String, Pathutil] root the root you wish to enforce on it.
462
+ # @return Pathutil the enforced path with given root.
463
+ # --------------------------------------------------------------------------
464
+
465
+ def enforce_root(root)
466
+ curr, root = expanded_paths(root)
467
+ if curr.in_path?(root)
468
+ return curr
469
+
470
+ else
471
+ File.join(
472
+ root, curr
473
+ )
474
+ end
475
+ end
476
+
477
+ # --------------------------------------------------------------------------
478
+ # Copy a directory, allowing symlinks if the link falls inside of the root.
479
+ # --------------------------------------------------------------------------
480
+
481
+ def safe_copy(to, root: nil)
482
+ raise ArgumentError, "must give a root" unless root
483
+ to = self.class.new(to)
484
+
485
+ root = self.class.new(root)
486
+ return safe_copy_directory(to, :root => root) if directory?
487
+ safe_copy_file(to, :root => root)
488
+ end
489
+
490
+ # --------------------------------------------------------------------------
491
+ # @see `self.class.normalize` as this is an alias.
492
+ # --------------------------------------------------------------------------
493
+
494
+ def normalize
495
+ return @normalize ||= begin
496
+ self.class.normalize
497
+ end
498
+ end
499
+
500
+ # --------------------------------------------------------------------------
501
+ # @see `self.class.encoding` as this is an alias.
502
+ # --------------------------------------------------------------------------
503
+
504
+ def encoding
505
+ return @encoding ||= begin
506
+ self.class.encoding
507
+ end
508
+ end
509
+
510
+ # --------------------------------------------------------------------------
511
+ # Read took two steroid shots: it can normalize your string, and encode.
512
+ # --------------------------------------------------------------------------
513
+
514
+ def read(*args, **kwd)
515
+ kwd[:encoding] ||= encoding
516
+
517
+ if normalize[:read]
518
+ File.read(self, *args, kwd).encode({
519
+ :universal_newline => true
520
+ })
521
+
522
+ else
523
+ File.read(
524
+ self, *args, kwd
525
+ )
526
+ end
527
+ end
528
+
529
+ # --------------------------------------------------------------------------
530
+ # Binread took two steroid shots: it can normalize your string, and encode.
531
+ # --------------------------------------------------------------------------
532
+
533
+ def binread(*args, **kwd)
534
+ kwd[:encoding] ||= encoding
535
+
536
+ if normalize[:read]
537
+ File.binread(self, *args, kwd).encode({
538
+ :universal_newline => true
539
+ })
540
+
541
+ else
542
+ File.read(
543
+ self, *args, kwd
544
+ )
545
+ end
546
+ end
547
+
548
+ # --------------------------------------------------------------------------
549
+ # Readlines took two steroid shots: it can normalize your string, and encode.
550
+ # --------------------------------------------------------------------------
551
+
552
+ def readlines(*args, **kwd)
553
+ kwd[:encoding] ||= encoding
554
+
555
+ if normalize[:read]
556
+ File.readlines(self, *args, kwd).encode({
557
+ :universal_newline => true
558
+ })
559
+
560
+ else
561
+ File.readlines(
562
+ self, *args, kwd
563
+ )
564
+ end
565
+ end
566
+
567
+ # --------------------------------------------------------------------------
568
+ # Write took two steroid shots: it can normalize your string, and encode.
569
+ # --------------------------------------------------------------------------
570
+
571
+ def write(data, *args, **kwd)
572
+ kwd[:encoding] ||= encoding
573
+
574
+ if normalize[:write]
575
+ File.write(self, data.encode(
576
+ :crlf_newline => true
577
+ ), *args, kwd)
578
+
579
+ else
580
+ File.write(
581
+ self, data, *args, kwd
582
+ )
583
+ end
584
+ end
585
+
586
+ # --------------------------------------------------------------------------
587
+ # Binwrite took two steroid shots: it can normalize your string, and encode.
588
+ # --------------------------------------------------------------------------
589
+
590
+ def binwrite(data, *args, **kwd)
591
+ kwd[:encoding] ||= encoding
592
+
593
+ if normalize[:write]
594
+ File.binwrite(self, data.encode(
595
+ :crlf_newline => true
596
+ ), *args, kwd)
597
+
598
+ else
599
+ File.binwrite(
600
+ self, data, *args, kwd
601
+ )
602
+ end
603
+ end
604
+
605
+ # --------------------------------------------------------------------------
606
+ # @api returns the current objects expanded path and their expanded path.
607
+ # --------------------------------------------------------------------------
608
+
609
+ private
610
+ def expanded_paths(path)
611
+ return expand_path, self.class.new(path).expand_path
612
+ end
613
+
614
+ # --------------------------------------------------------------------------
615
+
616
+ private
617
+ def safe_copy_file(to, root: nil)
618
+ raise Errno::EPERM, "#{self} not in #{root}" unless in_path?(root)
619
+ FileUtils.cp(self, to, {
620
+ :preserve => true
621
+ })
622
+ end
623
+
624
+ # --------------------------------------------------------------------------
625
+
626
+ private
627
+ def safe_copy_directory(to, root: nil)
628
+ if !in_path?(root)
629
+ raise Errno::EPERM, "#{self} not in #{
630
+ root
631
+ }"
632
+
633
+ else
634
+ to.mkdir_p unless to.exist?
635
+ children do |file|
636
+ if !file.in_path?(root)
637
+ raise Errno::EPERM, "#{file} not in #{
638
+ root
639
+ }"
640
+
641
+ elsif file.file?
642
+ FileUtils.cp(file, to, {
643
+ :preserve => true
644
+ })
645
+
646
+ else
647
+ path = file.realpath
648
+ path.safe_copy(to.join(file.basename), {
649
+ :root => root
650
+ })
651
+ end
652
+ end
653
+ end
654
+ end
655
+
656
+ # --------------------------------------------------------------------------
657
+
658
+ private
659
+ def setup_safe_yaml(whitelist_classes)
660
+ warn "WARN: SafeYAML will be removed when Ruby 2.0 goes EOL."
661
+ require "safe_yaml/load"
662
+
663
+ SafeYAML.restore_defaults!
664
+ whitelist_classes.map(&SafeYAML.method(
665
+ :whitelist_class!
666
+ ))
667
+ end
668
+
669
+ # --------------------------------------------------------------------------
670
+
671
+ rb_delegate :sub, :to => :@path, :wrap => true
672
+ rb_delegate :chomp, :to => :@path, :wrap => true
673
+ rb_delegate :gsub, :to => :@path, :wrap => true
674
+ rb_delegate :=~, :to => :@path
675
+ rb_delegate :==, :to => :@path
676
+ rb_delegate :to_s, :to => :@path
677
+ rb_delegate :freeze, :to => :@path
678
+ rb_delegate :frozen?, :to => :@path
679
+ rb_delegate :to_str, :to => :@path
680
+ rb_delegate :"!~", :to => :@path
681
+ rb_delegate :<=>, :to => :@path
682
+
683
+ # --------------------------------------------------------------------------
684
+
685
+ rb_delegate :basename, :to => :File, :args => :@path, :wrap => true
686
+ rb_delegate :dirname, :to => :File, :args => :@path, :wrap => true
687
+ rb_delegate :readlink, :to => :File, :args => :@path, :wrap => true
688
+ rb_delegate :expand_path, :to => :File, :args => :@path, :wrap => true
689
+ rb_delegate :realdirpath, :to => :File, :args => :@path, :wrap => true
690
+ rb_delegate :realpath, :to => :File, :args => :@path, :wrap => true
691
+ rb_delegate :rename, :to => :File, :args => :@path, :wrap => true
692
+ rb_delegate :join, :to => :File, :args => :@path, :wrap => true
693
+ rb_delegate :size, :to => :File, :args => :@path
694
+ rb_delegate :link, :to => :File, :args => :@path
695
+ rb_delegate :atime, :to => :File, :args => :@path
696
+ rb_delegate :chown, :to => :File, :args => :@path
697
+ rb_delegate :ctime, :to => :File, :args => :@path
698
+ rb_delegate :lstat, :to => :File, :args => :@path
699
+ rb_delegate :utime, :to => :File, :args => :@path
700
+ rb_delegate :lchmod, :to => :File, :args => :@path
701
+ rb_delegate :sysopen, :to => :File, :args => :@path
702
+ rb_delegate :birthtime, :to => :File, :args => :@path
703
+ rb_delegate :mountpoint?, :to => :File, :args => :@path
704
+ rb_delegate :truncate, :to => :File, :args => :@path
705
+ rb_delegate :symlink, :to => :File, :args => :@path
706
+ rb_delegate :extname, :to => :File, :args => :@path
707
+ rb_delegate :lchown, :to => :File, :args => :@path
708
+ rb_delegate :zero?, :to => :File, :args => :@path
709
+ rb_delegate :ftype, :to => :File, :args => :@path
710
+ rb_delegate :chmod, :to => :File, :args => :@path
711
+ rb_delegate :mtime, :to => :File, :args => :@path
712
+ rb_delegate :open, :to => :File, :args => :@path
713
+ rb_delegate :stat, :to => :File, :args => :@path
714
+
715
+ # --------------------------------------------------------------------------
716
+
717
+ rb_delegate :pipe?, :to => :FileTest, :args => :@path
718
+ rb_delegate :file?, :to => :FileTest, :args => :@path
719
+ rb_delegate :owned?, :to => :FileTest, :args => :@path
720
+ rb_delegate :setgid?, :to => :FileTest, :args => :@path
721
+ rb_delegate :socket?, :to => :FileTest, :args => :@path
722
+ rb_delegate :readable?, :to => :FileTest, :args => :@path
723
+ rb_delegate :blockdev?, :to => :FileTest, :args => :@path
724
+ rb_delegate :directory?, :to => :FileTest, :args => :@path
725
+ rb_delegate :readable_real?, :to => :FileTest, :args => :@path
726
+ rb_delegate :world_readable?, :to => :FileTest, :args => :@path
727
+ rb_delegate :executable_real?, :to => :FileTest, :args => :@path
728
+ rb_delegate :world_writable?, :to => :FileTest, :args => :@path
729
+ rb_delegate :writable_real?, :to => :FileTest, :args => :@path
730
+ rb_delegate :executable?, :to => :FileTest, :args => :@path
731
+ rb_delegate :writable?, :to => :FileTest, :args => :@path
732
+ rb_delegate :grpowned?, :to => :FileTest, :args => :@path
733
+ rb_delegate :chardev?, :to => :FileTest, :args => :@path
734
+ rb_delegate :symlink?, :to => :FileTest, :args => :@path
735
+ rb_delegate :sticky?, :to => :FileTest, :args => :@path
736
+ rb_delegate :setuid?, :to => :FileTest, :args => :@path
737
+ rb_delegate :exist?, :to => :FileTest, :args => :@path
738
+ rb_delegate :size?, :to => :FileTest, :args => :@path
739
+
740
+ # --------------------------------------------------------------------------
741
+
742
+ rb_delegate :rm_rf, :to => :FileUtils, :args => :@path
743
+ rb_delegate :rm_r, :to => :FileUtils, :args => :@path
744
+ rb_delegate :rm, :to => :FileUtils, :args => :@path
745
+ rb_delegate :cp_r, :to => :FileUtils, :args => :@path
746
+ rb_delegate :touch, :to => :FileUtils, :args => :@path
747
+ rb_delegate :mkdir_p, :to => :FileUtils, :args => :@path
748
+ rb_delegate :mkpath, :to => :FileUtils, :args => :@path
749
+ rb_delegate :cp, :to => :FileUtils, :args => :@path
750
+
751
+ # --------------------------------------------------------------------------
752
+
753
+ rb_delegate :each_child, :to => :children
754
+ rb_delegate :each_entry, :to => :children
755
+ rb_delegate :to_a, :to => :children
756
+
757
+ # --------------------------------------------------------------------------
758
+
759
+ rb_delegate :opendir, :to => :Dir, :alias_of => :open
760
+ rb_delegate :relative?, :to => :self, :alias_of => :absolute?, :bool => :reverse
761
+ rb_delegate :regexp_escape, :to => :Regexp, :args => :@path, :alias_of => :escape
762
+ rb_delegate :to_regexp, :to => :Regexp, :args => :@path, :alias_of => :new
763
+ rb_delegate :shellescape, :to => :Shellwords, :args => :@path
764
+ rb_delegate :mkdir, :to => :Dir, :args => :@path
765
+
766
+ # --------------------------------------------------------------------------
767
+ # alias last basename, alias first dirname, alias ext extname
768
+ # --------------------------------------------------------------------------
769
+
770
+ alias + join
771
+ alias delete rm
772
+ alias rmtree rm_r
773
+ alias to_path to_s
774
+ alias last basename
775
+ alias entries children
776
+ alias make_symlink symlink
777
+ alias fnmatch fnmatch?
778
+ alias make_link link
779
+ alias first dirname
780
+ alias rmdir rm_r
781
+ alias unlink rm
782
+ alias / join
783
+ end
@@ -0,0 +1,9 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2015-2016 Jordon Bedwell - MIT License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ class Pathutil
8
+ VERSION = "0.0.1"
9
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pathutil
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jordon Bedwell
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: forwardable-extended
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.4'
27
+ description: Like Pathname but a little less insane.
28
+ email:
29
+ - jordon@envygeeks.io
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - Gemfile
35
+ - LICENSE
36
+ - Rakefile
37
+ - lib/pathutil.rb
38
+ - lib/pathutil/version.rb
39
+ homepage: http://github.com/envygeeks/pathutils
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.5.1
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Almost like Pathname but just a little less insane.
63
+ test_files: []