pathname 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c42dd90f7949c457dd8225ff9f04ab3919a972ec4c4f41781784ee22e3957c47
4
+ data.tar.gz: 67971cc891a87efcadb29c62dea3bf429d74c5261711a83b8ccd45bbb2322028
5
+ SHA512:
6
+ metadata.gz: 0bc313f05de84a963277fb5814202b52c73dec674b195944f4255f80fc35b72a9dd00baea026826438524393baac08da00a723dcdc1fcf24bb49dff24a323be2
7
+ data.tar.gz: 1f4f1ec1ca815d7e857929ba474378d80b6e36ce5071fac4b3c1c12799a5a38eb951fc68361395274957c02ee67864dca30b8a2310d4521b65c51d97354b4788
@@ -0,0 +1,24 @@
1
+ name: build
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 2.7, 2.6, 2.5, head ]
11
+ os: [ ubuntu-latest, macos-latest ]
12
+ runs-on: ${{ matrix.os }}
13
+ steps:
14
+ - uses: actions/checkout@master
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: |
21
+ gem install bundler --no-document
22
+ bundle install
23
+ - name: Run test
24
+ run: rake compile test
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake"
6
+ gem "rake-compiler"
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,36 @@
1
+ # Pathname
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/pathname`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'pathname'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install pathname
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/hsbpathname.
36
+
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.test_files = FileList["test/**/test_*.rb"]
7
+ end
8
+
9
+ require 'rake/extensiontask'
10
+ Rake::ExtensionTask.new("pathname")
11
+
12
+ task :default => [:compile, :test]
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "pathname"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: false
2
+ require 'mkmf'
3
+ have_func("rb_file_s_birthtime")
4
+ create_makefile('pathname')
@@ -0,0 +1,599 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # = pathname.rb
4
+ #
5
+ # Object-Oriented Pathname Class
6
+ #
7
+ # Author:: Tanaka Akira <akr@m17n.org>
8
+ # Documentation:: Author and Gavin Sinclair
9
+ #
10
+ # For documentation, see class Pathname.
11
+ #
12
+
13
+ require 'pathname.so'
14
+
15
+ class Pathname
16
+
17
+ # :stopdoc:
18
+
19
+ # to_path is implemented so Pathname objects are usable with File.open, etc.
20
+ TO_PATH = :to_path
21
+
22
+ SAME_PATHS = if File::FNM_SYSCASE.nonzero?
23
+ # Avoid #zero? here because #casecmp can return nil.
24
+ proc {|a, b| a.casecmp(b) == 0}
25
+ else
26
+ proc {|a, b| a == b}
27
+ end
28
+
29
+
30
+ if File::ALT_SEPARATOR
31
+ SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}"
32
+ SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
33
+ else
34
+ SEPARATOR_LIST = "#{Regexp.quote File::SEPARATOR}"
35
+ SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
36
+ end
37
+
38
+ if File.dirname('A:') == 'A:.' # DOSish drive letter
39
+ ABSOLUTE_PATH = /\A(?:[A-Za-z]:|#{SEPARATOR_PAT})/o
40
+ else
41
+ ABSOLUTE_PATH = /\A#{SEPARATOR_PAT}/o
42
+ end
43
+ private_constant :ABSOLUTE_PATH
44
+
45
+ # :startdoc:
46
+
47
+ # chop_basename(path) -> [pre-basename, basename] or nil
48
+ def chop_basename(path) # :nodoc:
49
+ base = File.basename(path)
50
+ if /\A#{SEPARATOR_PAT}?\z/o.match?(base)
51
+ return nil
52
+ else
53
+ return path[0, path.rindex(base)], base
54
+ end
55
+ end
56
+ private :chop_basename
57
+
58
+ # split_names(path) -> prefix, [name, ...]
59
+ def split_names(path) # :nodoc:
60
+ names = []
61
+ while r = chop_basename(path)
62
+ path, basename = r
63
+ names.unshift basename
64
+ end
65
+ return path, names
66
+ end
67
+ private :split_names
68
+
69
+ def prepend_prefix(prefix, relpath) # :nodoc:
70
+ if relpath.empty?
71
+ File.dirname(prefix)
72
+ elsif /#{SEPARATOR_PAT}/o.match?(prefix)
73
+ prefix = File.dirname(prefix)
74
+ prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
75
+ prefix + relpath
76
+ else
77
+ prefix + relpath
78
+ end
79
+ end
80
+ private :prepend_prefix
81
+
82
+ # Returns clean pathname of +self+ with consecutive slashes and useless dots
83
+ # removed. The filesystem is not accessed.
84
+ #
85
+ # If +consider_symlink+ is +true+, then a more conservative algorithm is used
86
+ # to avoid breaking symbolic linkages. This may retain more +..+
87
+ # entries than absolutely necessary, but without accessing the filesystem,
88
+ # this can't be avoided.
89
+ #
90
+ # See Pathname#realpath.
91
+ #
92
+ def cleanpath(consider_symlink=false)
93
+ if consider_symlink
94
+ cleanpath_conservative
95
+ else
96
+ cleanpath_aggressive
97
+ end
98
+ end
99
+
100
+ #
101
+ # Clean the path simply by resolving and removing excess +.+ and +..+ entries.
102
+ # Nothing more, nothing less.
103
+ #
104
+ def cleanpath_aggressive # :nodoc:
105
+ path = @path
106
+ names = []
107
+ pre = path
108
+ while r = chop_basename(pre)
109
+ pre, base = r
110
+ case base
111
+ when '.'
112
+ when '..'
113
+ names.unshift base
114
+ else
115
+ if names[0] == '..'
116
+ names.shift
117
+ else
118
+ names.unshift base
119
+ end
120
+ end
121
+ end
122
+ pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
123
+ if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
124
+ names.shift while names[0] == '..'
125
+ end
126
+ self.class.new(prepend_prefix(pre, File.join(*names)))
127
+ end
128
+ private :cleanpath_aggressive
129
+
130
+ # has_trailing_separator?(path) -> bool
131
+ def has_trailing_separator?(path) # :nodoc:
132
+ if r = chop_basename(path)
133
+ pre, basename = r
134
+ pre.length + basename.length < path.length
135
+ else
136
+ false
137
+ end
138
+ end
139
+ private :has_trailing_separator?
140
+
141
+ # add_trailing_separator(path) -> path
142
+ def add_trailing_separator(path) # :nodoc:
143
+ if File.basename(path + 'a') == 'a'
144
+ path
145
+ else
146
+ File.join(path, "") # xxx: Is File.join is appropriate to add separator?
147
+ end
148
+ end
149
+ private :add_trailing_separator
150
+
151
+ def del_trailing_separator(path) # :nodoc:
152
+ if r = chop_basename(path)
153
+ pre, basename = r
154
+ pre + basename
155
+ elsif /#{SEPARATOR_PAT}+\z/o =~ path
156
+ $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o]
157
+ else
158
+ path
159
+ end
160
+ end
161
+ private :del_trailing_separator
162
+
163
+ def cleanpath_conservative # :nodoc:
164
+ path = @path
165
+ names = []
166
+ pre = path
167
+ while r = chop_basename(pre)
168
+ pre, base = r
169
+ names.unshift base if base != '.'
170
+ end
171
+ pre.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
172
+ if /#{SEPARATOR_PAT}/o.match?(File.basename(pre))
173
+ names.shift while names[0] == '..'
174
+ end
175
+ if names.empty?
176
+ self.class.new(File.dirname(pre))
177
+ else
178
+ if names.last != '..' && File.basename(path) == '.'
179
+ names << '.'
180
+ end
181
+ result = prepend_prefix(pre, File.join(*names))
182
+ if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path)
183
+ self.class.new(add_trailing_separator(result))
184
+ else
185
+ self.class.new(result)
186
+ end
187
+ end
188
+ end
189
+ private :cleanpath_conservative
190
+
191
+ # Returns the parent directory.
192
+ #
193
+ # This is same as <code>self + '..'</code>.
194
+ def parent
195
+ self + '..'
196
+ end
197
+
198
+ # Returns +true+ if +self+ points to a mountpoint.
199
+ def mountpoint?
200
+ begin
201
+ stat1 = self.lstat
202
+ stat2 = self.parent.lstat
203
+ stat1.dev != stat2.dev || stat1.ino == stat2.ino
204
+ rescue Errno::ENOENT
205
+ false
206
+ end
207
+ end
208
+
209
+ #
210
+ # Predicate method for root directories. Returns +true+ if the
211
+ # pathname consists of consecutive slashes.
212
+ #
213
+ # It doesn't access the filesystem. So it may return +false+ for some
214
+ # pathnames which points to roots such as <tt>/usr/..</tt>.
215
+ #
216
+ def root?
217
+ chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o.match?(@path)
218
+ end
219
+
220
+ # Predicate method for testing whether a path is absolute.
221
+ #
222
+ # It returns +true+ if the pathname begins with a slash.
223
+ #
224
+ # p = Pathname.new('/im/sure')
225
+ # p.absolute?
226
+ # #=> true
227
+ #
228
+ # p = Pathname.new('not/so/sure')
229
+ # p.absolute?
230
+ # #=> false
231
+ def absolute?
232
+ ABSOLUTE_PATH.match? @path
233
+ end
234
+
235
+ # The opposite of Pathname#absolute?
236
+ #
237
+ # It returns +false+ if the pathname begins with a slash.
238
+ #
239
+ # p = Pathname.new('/im/sure')
240
+ # p.relative?
241
+ # #=> false
242
+ #
243
+ # p = Pathname.new('not/so/sure')
244
+ # p.relative?
245
+ # #=> true
246
+ def relative?
247
+ !absolute?
248
+ end
249
+
250
+ #
251
+ # Iterates over each component of the path.
252
+ #
253
+ # Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }
254
+ # # yields "usr", "bin", and "ruby".
255
+ #
256
+ # Returns an Enumerator if no block was given.
257
+ #
258
+ # enum = Pathname.new("/usr/bin/ruby").each_filename
259
+ # # ... do stuff ...
260
+ # enum.each { |e| ... }
261
+ # # yields "usr", "bin", and "ruby".
262
+ #
263
+ def each_filename # :yield: filename
264
+ return to_enum(__method__) unless block_given?
265
+ _, names = split_names(@path)
266
+ names.each {|filename| yield filename }
267
+ nil
268
+ end
269
+
270
+ # Iterates over and yields a new Pathname object
271
+ # for each element in the given path in descending order.
272
+ #
273
+ # Pathname.new('/path/to/some/file.rb').descend {|v| p v}
274
+ # #<Pathname:/>
275
+ # #<Pathname:/path>
276
+ # #<Pathname:/path/to>
277
+ # #<Pathname:/path/to/some>
278
+ # #<Pathname:/path/to/some/file.rb>
279
+ #
280
+ # Pathname.new('path/to/some/file.rb').descend {|v| p v}
281
+ # #<Pathname:path>
282
+ # #<Pathname:path/to>
283
+ # #<Pathname:path/to/some>
284
+ # #<Pathname:path/to/some/file.rb>
285
+ #
286
+ # Returns an Enumerator if no block was given.
287
+ #
288
+ # enum = Pathname.new("/usr/bin/ruby").descend
289
+ # # ... do stuff ...
290
+ # enum.each { |e| ... }
291
+ # # yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby.
292
+ #
293
+ # It doesn't access the filesystem.
294
+ #
295
+ def descend
296
+ return to_enum(__method__) unless block_given?
297
+ vs = []
298
+ ascend {|v| vs << v }
299
+ vs.reverse_each {|v| yield v }
300
+ nil
301
+ end
302
+
303
+ # Iterates over and yields a new Pathname object
304
+ # for each element in the given path in ascending order.
305
+ #
306
+ # Pathname.new('/path/to/some/file.rb').ascend {|v| p v}
307
+ # #<Pathname:/path/to/some/file.rb>
308
+ # #<Pathname:/path/to/some>
309
+ # #<Pathname:/path/to>
310
+ # #<Pathname:/path>
311
+ # #<Pathname:/>
312
+ #
313
+ # Pathname.new('path/to/some/file.rb').ascend {|v| p v}
314
+ # #<Pathname:path/to/some/file.rb>
315
+ # #<Pathname:path/to/some>
316
+ # #<Pathname:path/to>
317
+ # #<Pathname:path>
318
+ #
319
+ # Returns an Enumerator if no block was given.
320
+ #
321
+ # enum = Pathname.new("/usr/bin/ruby").ascend
322
+ # # ... do stuff ...
323
+ # enum.each { |e| ... }
324
+ # # yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /.
325
+ #
326
+ # It doesn't access the filesystem.
327
+ #
328
+ def ascend
329
+ return to_enum(__method__) unless block_given?
330
+ path = @path
331
+ yield self
332
+ while r = chop_basename(path)
333
+ path, = r
334
+ break if path.empty?
335
+ yield self.class.new(del_trailing_separator(path))
336
+ end
337
+ end
338
+
339
+ #
340
+ # Appends a pathname fragment to +self+ to produce a new Pathname object.
341
+ #
342
+ # p1 = Pathname.new("/usr") # Pathname:/usr
343
+ # p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby
344
+ # p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
345
+ #
346
+ # # / is aliased to +.
347
+ # p4 = p1 / "bin/ruby" # Pathname:/usr/bin/ruby
348
+ # p5 = p1 / "/etc/passwd" # Pathname:/etc/passwd
349
+ #
350
+ # This method doesn't access the file system; it is pure string manipulation.
351
+ #
352
+ def +(other)
353
+ other = Pathname.new(other) unless Pathname === other
354
+ Pathname.new(plus(@path, other.to_s))
355
+ end
356
+ alias / +
357
+
358
+ def plus(path1, path2) # -> path # :nodoc:
359
+ prefix2 = path2
360
+ index_list2 = []
361
+ basename_list2 = []
362
+ while r2 = chop_basename(prefix2)
363
+ prefix2, basename2 = r2
364
+ index_list2.unshift prefix2.length
365
+ basename_list2.unshift basename2
366
+ end
367
+ return path2 if prefix2 != ''
368
+ prefix1 = path1
369
+ while true
370
+ while !basename_list2.empty? && basename_list2.first == '.'
371
+ index_list2.shift
372
+ basename_list2.shift
373
+ end
374
+ break unless r1 = chop_basename(prefix1)
375
+ prefix1, basename1 = r1
376
+ next if basename1 == '.'
377
+ if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
378
+ prefix1 = prefix1 + basename1
379
+ break
380
+ end
381
+ index_list2.shift
382
+ basename_list2.shift
383
+ end
384
+ r1 = chop_basename(prefix1)
385
+ if !r1 && (r1 = /#{SEPARATOR_PAT}/o.match?(File.basename(prefix1)))
386
+ while !basename_list2.empty? && basename_list2.first == '..'
387
+ index_list2.shift
388
+ basename_list2.shift
389
+ end
390
+ end
391
+ if !basename_list2.empty?
392
+ suffix2 = path2[index_list2.first..-1]
393
+ r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
394
+ else
395
+ r1 ? prefix1 : File.dirname(prefix1)
396
+ end
397
+ end
398
+ private :plus
399
+
400
+ #
401
+ # Joins the given pathnames onto +self+ to create a new Pathname object.
402
+ #
403
+ # path0 = Pathname.new("/usr") # Pathname:/usr
404
+ # path0 = path0.join("bin/ruby") # Pathname:/usr/bin/ruby
405
+ # # is the same as
406
+ # path1 = Pathname.new("/usr") + "bin/ruby" # Pathname:/usr/bin/ruby
407
+ # path0 == path1
408
+ # #=> true
409
+ #
410
+ def join(*args)
411
+ return self if args.empty?
412
+ result = args.pop
413
+ result = Pathname.new(result) unless Pathname === result
414
+ return result if result.absolute?
415
+ args.reverse_each {|arg|
416
+ arg = Pathname.new(arg) unless Pathname === arg
417
+ result = arg + result
418
+ return result if result.absolute?
419
+ }
420
+ self + result
421
+ end
422
+
423
+ #
424
+ # Returns the children of the directory (files and subdirectories, not
425
+ # recursive) as an array of Pathname objects.
426
+ #
427
+ # By default, the returned pathnames will have enough information to access
428
+ # the files. If you set +with_directory+ to +false+, then the returned
429
+ # pathnames will contain the filename only.
430
+ #
431
+ # For example:
432
+ # pn = Pathname("/usr/lib/ruby/1.8")
433
+ # pn.children
434
+ # # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
435
+ # Pathname:/usr/lib/ruby/1.8/Env.rb,
436
+ # Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
437
+ # pn.children(false)
438
+ # # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
439
+ #
440
+ # Note that the results never contain the entries +.+ and +..+ in
441
+ # the directory because they are not children.
442
+ #
443
+ def children(with_directory=true)
444
+ with_directory = false if @path == '.'
445
+ result = []
446
+ Dir.foreach(@path) {|e|
447
+ next if e == '.' || e == '..'
448
+ if with_directory
449
+ result << self.class.new(File.join(@path, e))
450
+ else
451
+ result << self.class.new(e)
452
+ end
453
+ }
454
+ result
455
+ end
456
+
457
+ # Iterates over the children of the directory
458
+ # (files and subdirectories, not recursive).
459
+ #
460
+ # It yields Pathname object for each child.
461
+ #
462
+ # By default, the yielded pathnames will have enough information to access
463
+ # the files.
464
+ #
465
+ # If you set +with_directory+ to +false+, then the returned pathnames will
466
+ # contain the filename only.
467
+ #
468
+ # Pathname("/usr/local").each_child {|f| p f }
469
+ # #=> #<Pathname:/usr/local/share>
470
+ # # #<Pathname:/usr/local/bin>
471
+ # # #<Pathname:/usr/local/games>
472
+ # # #<Pathname:/usr/local/lib>
473
+ # # #<Pathname:/usr/local/include>
474
+ # # #<Pathname:/usr/local/sbin>
475
+ # # #<Pathname:/usr/local/src>
476
+ # # #<Pathname:/usr/local/man>
477
+ #
478
+ # Pathname("/usr/local").each_child(false) {|f| p f }
479
+ # #=> #<Pathname:share>
480
+ # # #<Pathname:bin>
481
+ # # #<Pathname:games>
482
+ # # #<Pathname:lib>
483
+ # # #<Pathname:include>
484
+ # # #<Pathname:sbin>
485
+ # # #<Pathname:src>
486
+ # # #<Pathname:man>
487
+ #
488
+ # Note that the results never contain the entries +.+ and +..+ in
489
+ # the directory because they are not children.
490
+ #
491
+ # See Pathname#children
492
+ #
493
+ def each_child(with_directory=true, &b)
494
+ children(with_directory).each(&b)
495
+ end
496
+
497
+ #
498
+ # Returns a relative path from the given +base_directory+ to the receiver.
499
+ #
500
+ # If +self+ is absolute, then +base_directory+ must be absolute too.
501
+ #
502
+ # If +self+ is relative, then +base_directory+ must be relative too.
503
+ #
504
+ # This method doesn't access the filesystem. It assumes no symlinks.
505
+ #
506
+ # ArgumentError is raised when it cannot find a relative path.
507
+ #
508
+ # Note that this method does not handle situations where the case sensitivity
509
+ # of the filesystem in use differs from the operating system default.
510
+ #
511
+ def relative_path_from(base_directory)
512
+ base_directory = Pathname.new(base_directory) unless base_directory.is_a? Pathname
513
+ dest_directory = self.cleanpath.to_s
514
+ base_directory = base_directory.cleanpath.to_s
515
+ dest_prefix = dest_directory
516
+ dest_names = []
517
+ while r = chop_basename(dest_prefix)
518
+ dest_prefix, basename = r
519
+ dest_names.unshift basename if basename != '.'
520
+ end
521
+ base_prefix = base_directory
522
+ base_names = []
523
+ while r = chop_basename(base_prefix)
524
+ base_prefix, basename = r
525
+ base_names.unshift basename if basename != '.'
526
+ end
527
+ unless SAME_PATHS[dest_prefix, base_prefix]
528
+ raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
529
+ end
530
+ while !dest_names.empty? &&
531
+ !base_names.empty? &&
532
+ SAME_PATHS[dest_names.first, base_names.first]
533
+ dest_names.shift
534
+ base_names.shift
535
+ end
536
+ if base_names.include? '..'
537
+ raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
538
+ end
539
+ base_names.fill('..')
540
+ relpath_names = base_names + dest_names
541
+ if relpath_names.empty?
542
+ Pathname.new('.')
543
+ else
544
+ Pathname.new(File.join(*relpath_names))
545
+ end
546
+ end
547
+ end
548
+
549
+
550
+ class Pathname # * Find *
551
+ #
552
+ # Iterates over the directory tree in a depth first manner, yielding a
553
+ # Pathname for each file under "this" directory.
554
+ #
555
+ # Returns an Enumerator if no block is given.
556
+ #
557
+ # Since it is implemented by the standard library module Find, Find.prune can
558
+ # be used to control the traversal.
559
+ #
560
+ # If +self+ is +.+, yielded pathnames begin with a filename in the
561
+ # current directory, not +./+.
562
+ #
563
+ # See Find.find
564
+ #
565
+ def find(ignore_error: true) # :yield: pathname
566
+ return to_enum(__method__, ignore_error: ignore_error) unless block_given?
567
+ require 'find'
568
+ if @path == '.'
569
+ Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.sub(%r{\A\./}, '')) }
570
+ else
571
+ Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) }
572
+ end
573
+ end
574
+ end
575
+
576
+
577
+ class Pathname # * FileUtils *
578
+ # Creates a full path, including any intermediate directories that don't yet
579
+ # exist.
580
+ #
581
+ # See FileUtils.mkpath and FileUtils.mkdir_p
582
+ def mkpath
583
+ require 'fileutils'
584
+ FileUtils.mkpath(@path)
585
+ nil
586
+ end
587
+
588
+ # Recursively deletes a directory, including all directories beneath it.
589
+ #
590
+ # See FileUtils.rm_r
591
+ def rmtree
592
+ # The name "rmtree" is borrowed from File::Path of Perl.
593
+ # File::Path provides "mkpath" and "rmtree".
594
+ require 'fileutils'
595
+ FileUtils.rm_r(@path)
596
+ nil
597
+ end
598
+ end
599
+