fakefs 0.4.0 → 0.4.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.
@@ -0,0 +1,864 @@
1
+ module FakeFS
2
+ if RUBY_VERSION >= "1.9.3"
3
+
4
+ #
5
+ # = pathname.rb - From MRI 1.9.2
6
+ #
7
+ # Object-Oriented Pathname Class
8
+ #
9
+ # Author:: Tanaka Akira <akr@m17n.org>
10
+ # Documentation:: Author and Gavin Sinclair
11
+ #
12
+ # For documentation, see class Pathname.
13
+ #
14
+ class Pathname
15
+
16
+ # to_path is implemented so Pathname objects are usable with File.open, etc.
17
+ TO_PATH = :to_path
18
+
19
+ SAME_PATHS = if File::FNM_SYSCASE.nonzero?
20
+ proc {|a, b| a.casecmp(b).zero?}
21
+ else
22
+ proc {|a, b| a == b}
23
+ end
24
+
25
+ # :startdoc:
26
+
27
+ #
28
+ # Create a Pathname object from the given String (or String-like object).
29
+ # If +path+ contains a NUL character (<tt>\0</tt>), an ArgumentError is raised.
30
+ #
31
+ def initialize(path)
32
+ path = path.__send__(TO_PATH) if path.respond_to? TO_PATH
33
+ @path = path.dup
34
+
35
+ if /\0/ =~ @path
36
+ raise ArgumentError, "pathname contains \\0: #{@path.inspect}"
37
+ end
38
+
39
+ self.taint if @path.tainted?
40
+ end
41
+
42
+ def freeze() super; @path.freeze; self end
43
+ def taint() super; @path.taint; self end
44
+ def untaint() super; @path.untaint; self end
45
+
46
+ #
47
+ # Compare this pathname with +other+. The comparison is string-based.
48
+ # Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>)
49
+ # can refer to the same file.
50
+ #
51
+ def ==(other)
52
+ return false unless Pathname === other
53
+ other.to_s == @path
54
+ end
55
+ alias === ==
56
+ alias eql? ==
57
+
58
+ # Provides for comparing pathnames, case-sensitively.
59
+ def <=>(other)
60
+ return nil unless Pathname === other
61
+ @path.tr('/', "\0") <=> other.to_s.tr('/', "\0")
62
+ end
63
+
64
+ def hash # :nodoc:
65
+ @path.hash
66
+ end
67
+
68
+ # Return the path as a String.
69
+ def to_s
70
+ @path.dup
71
+ end
72
+
73
+ # to_path is implemented so Pathname objects are usable with File.open, etc.
74
+ alias_method TO_PATH, :to_s
75
+
76
+ def inspect # :nodoc:
77
+ "#<#{self.class}:#{@path}>"
78
+ end
79
+
80
+ # Return a pathname which is substituted by String#sub.
81
+ def sub(pattern, *rest, &block)
82
+ if block
83
+ path = @path.sub(pattern, *rest) {|*args|
84
+ begin
85
+ old = Thread.current[:pathname_sub_matchdata]
86
+ Thread.current[:pathname_sub_matchdata] = $~
87
+ eval("$~ = Thread.current[:pathname_sub_matchdata]", block.binding)
88
+ ensure
89
+ Thread.current[:pathname_sub_matchdata] = old
90
+ end
91
+ yield(*args)
92
+ }
93
+ else
94
+ path = @path.sub(pattern, *rest)
95
+ end
96
+ self.class.new(path)
97
+ end
98
+
99
+ if File::ALT_SEPARATOR
100
+ SEPARATOR_LIST = "#{Regexp.quote File::ALT_SEPARATOR}#{Regexp.quote File::SEPARATOR}"
101
+ SEPARATOR_PAT = /[#{SEPARATOR_LIST}]/
102
+ else
103
+ SEPARATOR_LIST = "#{Regexp.quote File::SEPARATOR}"
104
+ SEPARATOR_PAT = /#{Regexp.quote File::SEPARATOR}/
105
+ end
106
+
107
+ # Return a pathname which the extension of the basename is substituted by
108
+ # <i>repl</i>.
109
+ #
110
+ # If self has no extension part, <i>repl</i> is appended.
111
+ def sub_ext(repl)
112
+ ext = File.extname(@path)
113
+ self.class.new(@path.chomp(ext) + repl)
114
+ end
115
+
116
+ # chop_basename(path) -> [pre-basename, basename] or nil
117
+ def chop_basename(path)
118
+ base = File.basename(path)
119
+ if /\A#{SEPARATOR_PAT}?\z/o =~ base
120
+ return nil
121
+ else
122
+ return path[0, path.rindex(base)], base
123
+ end
124
+ end
125
+ private :chop_basename
126
+
127
+ # split_names(path) -> prefix, [name, ...]
128
+ def split_names(path)
129
+ names = []
130
+ while r = chop_basename(path)
131
+ path, basename = r
132
+ names.unshift basename
133
+ end
134
+ return path, names
135
+ end
136
+ private :split_names
137
+
138
+ def prepend_prefix(prefix, relpath)
139
+ if relpath.empty?
140
+ File.dirname(prefix)
141
+ elsif /#{SEPARATOR_PAT}/o =~ prefix
142
+ prefix = File.dirname(prefix)
143
+ prefix = File.join(prefix, "") if File.basename(prefix + 'a') != 'a'
144
+ prefix + relpath
145
+ else
146
+ prefix + relpath
147
+ end
148
+ end
149
+ private :prepend_prefix
150
+
151
+ # Returns clean pathname of +self+ with consecutive slashes and useless dots
152
+ # removed. The filesystem is not accessed.
153
+ #
154
+ # If +consider_symlink+ is +true+, then a more conservative algorithm is used
155
+ # to avoid breaking symbolic linkages. This may retain more <tt>..</tt>
156
+ # entries than absolutely necessary, but without accessing the filesystem,
157
+ # this can't be avoided. See #realpath.
158
+ #
159
+ def cleanpath(consider_symlink=false)
160
+ if consider_symlink
161
+ cleanpath_conservative
162
+ else
163
+ cleanpath_aggressive
164
+ end
165
+ end
166
+
167
+ #
168
+ # Clean the path simply by resolving and removing excess "." and ".." entries.
169
+ # Nothing more, nothing less.
170
+ #
171
+ def cleanpath_aggressive
172
+ path = @path
173
+ names = []
174
+ pre = path
175
+ while r = chop_basename(pre)
176
+ pre, base = r
177
+ case base
178
+ when '.'
179
+ when '..'
180
+ names.unshift base
181
+ else
182
+ if names[0] == '..'
183
+ names.shift
184
+ else
185
+ names.unshift base
186
+ end
187
+ end
188
+ end
189
+ if /#{SEPARATOR_PAT}/o =~ File.basename(pre)
190
+ names.shift while names[0] == '..'
191
+ end
192
+ self.class.new(prepend_prefix(pre, File.join(*names)))
193
+ end
194
+ private :cleanpath_aggressive
195
+
196
+ # has_trailing_separator?(path) -> bool
197
+ def has_trailing_separator?(path)
198
+ if r = chop_basename(path)
199
+ pre, basename = r
200
+ pre.length + basename.length < path.length
201
+ else
202
+ false
203
+ end
204
+ end
205
+ private :has_trailing_separator?
206
+
207
+ # add_trailing_separator(path) -> path
208
+ def add_trailing_separator(path)
209
+ if File.basename(path + 'a') == 'a'
210
+ path
211
+ else
212
+ File.join(path, "") # xxx: Is File.join is appropriate to add separator?
213
+ end
214
+ end
215
+ private :add_trailing_separator
216
+
217
+ def del_trailing_separator(path)
218
+ if r = chop_basename(path)
219
+ pre, basename = r
220
+ pre + basename
221
+ elsif /#{SEPARATOR_PAT}+\z/o =~ path
222
+ $` + File.dirname(path)[/#{SEPARATOR_PAT}*\z/o]
223
+ else
224
+ path
225
+ end
226
+ end
227
+ private :del_trailing_separator
228
+
229
+ def cleanpath_conservative
230
+ path = @path
231
+ names = []
232
+ pre = path
233
+ while r = chop_basename(pre)
234
+ pre, base = r
235
+ names.unshift base if base != '.'
236
+ end
237
+ if /#{SEPARATOR_PAT}/o =~ File.basename(pre)
238
+ names.shift while names[0] == '..'
239
+ end
240
+ if names.empty?
241
+ self.class.new(File.dirname(pre))
242
+ else
243
+ if names.last != '..' && File.basename(path) == '.'
244
+ names << '.'
245
+ end
246
+ result = prepend_prefix(pre, File.join(*names))
247
+ if /\A(?:\.|\.\.)\z/ !~ names.last && has_trailing_separator?(path)
248
+ self.class.new(add_trailing_separator(result))
249
+ else
250
+ self.class.new(result)
251
+ end
252
+ end
253
+ end
254
+ private :cleanpath_conservative
255
+
256
+ #
257
+ # Returns the real (absolute) pathname of +self+ in the actual
258
+ # filesystem not containing symlinks or useless dots.
259
+ #
260
+ # All components of the pathname must exist when this method is
261
+ # called.
262
+ #
263
+ def realpath(basedir=nil)
264
+ self.class.new(File.realpath(@path, basedir))
265
+ end
266
+
267
+ #
268
+ # Returns the real (absolute) pathname of +self+ in the actual filesystem.
269
+ # The real pathname doesn't contain symlinks or useless dots.
270
+ #
271
+ # The last component of the real pathname can be nonexistent.
272
+ #
273
+ def realdirpath(basedir=nil)
274
+ self.class.new(File.realdirpath(@path, basedir))
275
+ end
276
+
277
+ # #parent returns the parent directory.
278
+ #
279
+ # This is same as <tt>self + '..'</tt>.
280
+ def parent
281
+ self + '..'
282
+ end
283
+
284
+ # #mountpoint? returns +true+ if <tt>self</tt> points to a mountpoint.
285
+ def mountpoint?
286
+ begin
287
+ stat1 = self.lstat
288
+ stat2 = self.parent.lstat
289
+ stat1.dev == stat2.dev && stat1.ino == stat2.ino ||
290
+ stat1.dev != stat2.dev
291
+ rescue Errno::ENOENT
292
+ false
293
+ end
294
+ end
295
+
296
+ #
297
+ # #root? is a predicate for root directories. I.e. it returns +true+ if the
298
+ # pathname consists of consecutive slashes.
299
+ #
300
+ # It doesn't access actual filesystem. So it may return +false+ for some
301
+ # pathnames which points to roots such as <tt>/usr/..</tt>.
302
+ #
303
+ def root?
304
+ !!(chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o =~ @path)
305
+ end
306
+
307
+ # Predicate method for testing whether a path is absolute.
308
+ # It returns +true+ if the pathname begins with a slash.
309
+ def absolute?
310
+ !relative?
311
+ end
312
+
313
+ # The opposite of #absolute?
314
+ def relative?
315
+ path = @path
316
+ while r = chop_basename(path)
317
+ path, basename = r
318
+ end
319
+ path == ''
320
+ end
321
+
322
+ #
323
+ # Iterates over each component of the path.
324
+ #
325
+ # Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }
326
+ # # yields "usr", "bin", and "ruby".
327
+ #
328
+ def each_filename # :yield: filename
329
+ return to_enum(__method__) unless block_given?
330
+ prefix, names = split_names(@path)
331
+ names.each {|filename| yield filename }
332
+ nil
333
+ end
334
+
335
+ # Iterates over and yields a new Pathname object
336
+ # for each element in the given path in descending order.
337
+ #
338
+ # Pathname.new('/path/to/some/file.rb').descend {|v| p v}
339
+ # #<Pathname:/>
340
+ # #<Pathname:/path>
341
+ # #<Pathname:/path/to>
342
+ # #<Pathname:/path/to/some>
343
+ # #<Pathname:/path/to/some/file.rb>
344
+ #
345
+ # Pathname.new('path/to/some/file.rb').descend {|v| p v}
346
+ # #<Pathname:path>
347
+ # #<Pathname:path/to>
348
+ # #<Pathname:path/to/some>
349
+ # #<Pathname:path/to/some/file.rb>
350
+ #
351
+ # It doesn't access actual filesystem.
352
+ #
353
+ # This method is available since 1.8.5.
354
+ #
355
+ def descend
356
+ vs = []
357
+ ascend {|v| vs << v }
358
+ vs.reverse_each {|v| yield v }
359
+ nil
360
+ end
361
+
362
+ # Iterates over and yields a new Pathname object
363
+ # for each element in the given path in ascending order.
364
+ #
365
+ # Pathname.new('/path/to/some/file.rb').ascend {|v| p v}
366
+ # #<Pathname:/path/to/some/file.rb>
367
+ # #<Pathname:/path/to/some>
368
+ # #<Pathname:/path/to>
369
+ # #<Pathname:/path>
370
+ # #<Pathname:/>
371
+ #
372
+ # Pathname.new('path/to/some/file.rb').ascend {|v| p v}
373
+ # #<Pathname:path/to/some/file.rb>
374
+ # #<Pathname:path/to/some>
375
+ # #<Pathname:path/to>
376
+ # #<Pathname:path>
377
+ #
378
+ # It doesn't access actual filesystem.
379
+ #
380
+ # This method is available since 1.8.5.
381
+ #
382
+ def ascend
383
+ path = @path
384
+ yield self
385
+ while r = chop_basename(path)
386
+ path, name = r
387
+ break if path.empty?
388
+ yield self.class.new(del_trailing_separator(path))
389
+ end
390
+ end
391
+
392
+ #
393
+ # Pathname#+ appends a pathname fragment to this one to produce a new Pathname
394
+ # object.
395
+ #
396
+ # p1 = Pathname.new("/usr") # Pathname:/usr
397
+ # p2 = p1 + "bin/ruby" # Pathname:/usr/bin/ruby
398
+ # p3 = p1 + "/etc/passwd" # Pathname:/etc/passwd
399
+ #
400
+ # This method doesn't access the file system; it is pure string manipulation.
401
+ #
402
+ def +(other)
403
+ other = Pathname.new(other) unless Pathname === other
404
+ Pathname.new(plus(@path, other.to_s))
405
+ end
406
+
407
+ def plus(path1, path2) # -> path
408
+ prefix2 = path2
409
+ index_list2 = []
410
+ basename_list2 = []
411
+ while r2 = chop_basename(prefix2)
412
+ prefix2, basename2 = r2
413
+ index_list2.unshift prefix2.length
414
+ basename_list2.unshift basename2
415
+ end
416
+ return path2 if prefix2 != ''
417
+ prefix1 = path1
418
+ while true
419
+ while !basename_list2.empty? && basename_list2.first == '.'
420
+ index_list2.shift
421
+ basename_list2.shift
422
+ end
423
+ break unless r1 = chop_basename(prefix1)
424
+ prefix1, basename1 = r1
425
+ next if basename1 == '.'
426
+ if basename1 == '..' || basename_list2.empty? || basename_list2.first != '..'
427
+ prefix1 = prefix1 + basename1
428
+ break
429
+ end
430
+ index_list2.shift
431
+ basename_list2.shift
432
+ end
433
+ r1 = chop_basename(prefix1)
434
+ if !r1 && /#{SEPARATOR_PAT}/o =~ File.basename(prefix1)
435
+ while !basename_list2.empty? && basename_list2.first == '..'
436
+ index_list2.shift
437
+ basename_list2.shift
438
+ end
439
+ end
440
+ if !basename_list2.empty?
441
+ suffix2 = path2[index_list2.first..-1]
442
+ r1 ? File.join(prefix1, suffix2) : prefix1 + suffix2
443
+ else
444
+ r1 ? prefix1 : File.dirname(prefix1)
445
+ end
446
+ end
447
+ private :plus
448
+
449
+ #
450
+ # Pathname#join joins pathnames.
451
+ #
452
+ # <tt>path0.join(path1, ..., pathN)</tt> is the same as
453
+ # <tt>path0 + path1 + ... + pathN</tt>.
454
+ #
455
+ def join(*args)
456
+ args.unshift self
457
+ result = args.pop
458
+ result = Pathname.new(result) unless Pathname === result
459
+ return result if result.absolute?
460
+ args.reverse_each {|arg|
461
+ arg = Pathname.new(arg) unless Pathname === arg
462
+ result = arg + result
463
+ return result if result.absolute?
464
+ }
465
+ result
466
+ end
467
+
468
+ #
469
+ # Returns the children of the directory (files and subdirectories, not
470
+ # recursive) as an array of Pathname objects. By default, the returned
471
+ # pathnames will have enough information to access the files. If you set
472
+ # +with_directory+ to +false+, then the returned pathnames will contain the
473
+ # filename only.
474
+ #
475
+ # For example:
476
+ # pn = Pathname("/usr/lib/ruby/1.8")
477
+ # pn.children
478
+ # # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
479
+ # Pathname:/usr/lib/ruby/1.8/Env.rb,
480
+ # Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
481
+ # pn.children(false)
482
+ # # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]
483
+ #
484
+ # Note that the result never contain the entries <tt>.</tt> and <tt>..</tt> in
485
+ # the directory because they are not children.
486
+ #
487
+ # This method has existed since 1.8.1.
488
+ #
489
+ def children(with_directory=true)
490
+ with_directory = false if @path == '.'
491
+ result = []
492
+ Dir.foreach(@path) {|e|
493
+ next if e == '.' || e == '..'
494
+ if with_directory
495
+ result << self.class.new(File.join(@path, e))
496
+ else
497
+ result << self.class.new(e)
498
+ end
499
+ }
500
+ result
501
+ end
502
+
503
+ # Iterates over the children of the directory
504
+ # (files and subdirectories, not recursive).
505
+ # It yields Pathname object for each child.
506
+ # By default, the yielded pathnames will have enough information to access the files.
507
+ # If you set +with_directory+ to +false+, then the returned pathnames will contain the filename only.
508
+ #
509
+ # Pathname("/usr/local").each_child {|f| p f }
510
+ # #=> #<Pathname:/usr/local/share>
511
+ # # #<Pathname:/usr/local/bin>
512
+ # # #<Pathname:/usr/local/games>
513
+ # # #<Pathname:/usr/local/lib>
514
+ # # #<Pathname:/usr/local/include>
515
+ # # #<Pathname:/usr/local/sbin>
516
+ # # #<Pathname:/usr/local/src>
517
+ # # #<Pathname:/usr/local/man>
518
+ #
519
+ # Pathname("/usr/local").each_child(false) {|f| p f }
520
+ # #=> #<Pathname:share>
521
+ # # #<Pathname:bin>
522
+ # # #<Pathname:games>
523
+ # # #<Pathname:lib>
524
+ # # #<Pathname:include>
525
+ # # #<Pathname:sbin>
526
+ # # #<Pathname:src>
527
+ # # #<Pathname:man>
528
+ #
529
+ def each_child(with_directory=true, &b)
530
+ children(with_directory).each(&b)
531
+ end
532
+
533
+ #
534
+ # #relative_path_from returns a relative path from the argument to the
535
+ # receiver. If +self+ is absolute, the argument must be absolute too. If
536
+ # +self+ is relative, the argument must be relative too.
537
+ #
538
+ # #relative_path_from doesn't access the filesystem. It assumes no symlinks.
539
+ #
540
+ # ArgumentError is raised when it cannot find a relative path.
541
+ #
542
+ # This method has existed since 1.8.1.
543
+ #
544
+ def relative_path_from(base_directory)
545
+ dest_directory = self.cleanpath.to_s
546
+ base_directory = base_directory.cleanpath.to_s
547
+ dest_prefix = dest_directory
548
+ dest_names = []
549
+ while r = chop_basename(dest_prefix)
550
+ dest_prefix, basename = r
551
+ dest_names.unshift basename if basename != '.'
552
+ end
553
+ base_prefix = base_directory
554
+ base_names = []
555
+ while r = chop_basename(base_prefix)
556
+ base_prefix, basename = r
557
+ base_names.unshift basename if basename != '.'
558
+ end
559
+ unless SAME_PATHS[dest_prefix, base_prefix]
560
+ raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
561
+ end
562
+ while !dest_names.empty? &&
563
+ !base_names.empty? &&
564
+ SAME_PATHS[dest_names.first, base_names.first]
565
+ dest_names.shift
566
+ base_names.shift
567
+ end
568
+ if base_names.include? '..'
569
+ raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
570
+ end
571
+ base_names.fill('..')
572
+ relpath_names = base_names + dest_names
573
+ if relpath_names.empty?
574
+ Pathname.new('.')
575
+ else
576
+ Pathname.new(File.join(*relpath_names))
577
+ end
578
+ end
579
+ end
580
+
581
+ class Pathname # * IO *
582
+ #
583
+ # #each_line iterates over the line in the file. It yields a String object
584
+ # for each line.
585
+ #
586
+ # This method has existed since 1.8.1.
587
+ #
588
+ def each_line(*args, &block) # :yield: line
589
+ IO.foreach(@path, *args, &block)
590
+ end
591
+
592
+ # See <tt>IO.read</tt>. Returns all data from the file, or the first +N+ bytes
593
+ # if specified.
594
+ def read(*args) IO.read(@path, *args) end
595
+
596
+ # See <tt>IO.binread</tt>. Returns all the bytes from the file, or the first +N+
597
+ # if specified.
598
+ def binread(*args) IO.binread(@path, *args) end
599
+
600
+ # See <tt>IO.readlines</tt>. Returns all the lines from the file.
601
+ def readlines(*args) IO.readlines(@path, *args) end
602
+
603
+ # See <tt>IO.sysopen</tt>.
604
+ def sysopen(*args) IO.sysopen(@path, *args) end
605
+ end
606
+
607
+
608
+ class Pathname # * File *
609
+
610
+ # See <tt>File.atime</tt>. Returns last access time.
611
+ def atime() File.atime(@path) end
612
+
613
+ # See <tt>File.ctime</tt>. Returns last (directory entry, not file) change time.
614
+ def ctime() File.ctime(@path) end
615
+
616
+ # See <tt>File.mtime</tt>. Returns last modification time.
617
+ def mtime() File.mtime(@path) end
618
+
619
+ # See <tt>File.chmod</tt>. Changes permissions.
620
+ def chmod(mode) File.chmod(mode, @path) end
621
+
622
+ # See <tt>File.lchmod</tt>.
623
+ def lchmod(mode) File.lchmod(mode, @path) end
624
+
625
+ # See <tt>File.chown</tt>. Change owner and group of file.
626
+ def chown(owner, group) File.chown(owner, group, @path) end
627
+
628
+ # See <tt>File.lchown</tt>.
629
+ def lchown(owner, group) File.lchown(owner, group, @path) end
630
+
631
+ # See <tt>File.fnmatch</tt>. Return +true+ if the receiver matches the given
632
+ # pattern.
633
+ def fnmatch(pattern, *args) File.fnmatch(pattern, @path, *args) end
634
+
635
+ # See <tt>File.fnmatch?</tt> (same as #fnmatch).
636
+ def fnmatch?(pattern, *args) File.fnmatch?(pattern, @path, *args) end
637
+
638
+ # See <tt>File.ftype</tt>. Returns "type" of file ("file", "directory",
639
+ # etc).
640
+ def ftype() File.ftype(@path) end
641
+
642
+ # See <tt>File.link</tt>. Creates a hard link.
643
+ def make_link(old) File.link(old, @path) end
644
+
645
+ # See <tt>File.open</tt>. Opens the file for reading or writing.
646
+ def open(*args, &block) # :yield: file
647
+ File.open(@path, *args, &block)
648
+ end
649
+
650
+ # See <tt>File.readlink</tt>. Read symbolic link.
651
+ def readlink() self.class.new(File.readlink(@path)) end
652
+
653
+ # See <tt>File.rename</tt>. Rename the file.
654
+ def rename(to) File.rename(@path, to) end
655
+
656
+ # See <tt>File.stat</tt>. Returns a <tt>File::Stat</tt> object.
657
+ def stat() File.stat(@path) end
658
+
659
+ # See <tt>File.lstat</tt>.
660
+ def lstat() File.lstat(@path) end
661
+
662
+ # See <tt>File.symlink</tt>. Creates a symbolic link.
663
+ def make_symlink(old) File.symlink(old, @path) end
664
+
665
+ # See <tt>File.truncate</tt>. Truncate the file to +length+ bytes.
666
+ def truncate(length) File.truncate(@path, length) end
667
+
668
+ # See <tt>File.utime</tt>. Update the access and modification times.
669
+ def utime(atime, mtime) File.utime(atime, mtime, @path) end
670
+
671
+ # See <tt>File.basename</tt>. Returns the last component of the path.
672
+ def basename(*args) self.class.new(File.basename(@path, *args)) end
673
+
674
+ # See <tt>File.dirname</tt>. Returns all but the last component of the path.
675
+ def dirname() self.class.new(File.dirname(@path)) end
676
+
677
+ # See <tt>File.extname</tt>. Returns the file's extension.
678
+ def extname() File.extname(@path) end
679
+
680
+ # See <tt>File.expand_path</tt>.
681
+ def expand_path(*args) self.class.new(File.expand_path(@path, *args)) end
682
+
683
+ # See <tt>File.split</tt>. Returns the #dirname and the #basename in an
684
+ # Array.
685
+ def split() File.split(@path).map {|f| self.class.new(f) } end
686
+ end
687
+
688
+
689
+ class Pathname # * FileTest *
690
+
691
+ # See <tt>FileTest.blockdev?</tt>.
692
+ def blockdev?() FileTest.blockdev?(@path) end
693
+
694
+ # See <tt>FileTest.chardev?</tt>.
695
+ def chardev?() FileTest.chardev?(@path) end
696
+
697
+ # See <tt>FileTest.executable?</tt>.
698
+ def executable?() FileTest.executable?(@path) end
699
+
700
+ # See <tt>FileTest.executable_real?</tt>.
701
+ def executable_real?() FileTest.executable_real?(@path) end
702
+
703
+ # See <tt>FileTest.exist?</tt>.
704
+ def exist?() FileTest.exist?(@path) end
705
+
706
+ # See <tt>FileTest.grpowned?</tt>.
707
+ def grpowned?() FileTest.grpowned?(@path) end
708
+
709
+ # See <tt>FileTest.directory?</tt>.
710
+ def directory?() FileTest.directory?(@path) end
711
+
712
+ # See <tt>FileTest.file?</tt>.
713
+ def file?() FileTest.file?(@path) end
714
+
715
+ # See <tt>FileTest.pipe?</tt>.
716
+ def pipe?() FileTest.pipe?(@path) end
717
+
718
+ # See <tt>FileTest.socket?</tt>.
719
+ def socket?() FileTest.socket?(@path) end
720
+
721
+ # See <tt>FileTest.owned?</tt>.
722
+ def owned?() FileTest.owned?(@path) end
723
+
724
+ # See <tt>FileTest.readable?</tt>.
725
+ def readable?() FileTest.readable?(@path) end
726
+
727
+ # See <tt>FileTest.world_readable?</tt>.
728
+ def world_readable?() FileTest.world_readable?(@path) end
729
+
730
+ # See <tt>FileTest.readable_real?</tt>.
731
+ def readable_real?() FileTest.readable_real?(@path) end
732
+
733
+ # See <tt>FileTest.setuid?</tt>.
734
+ def setuid?() FileTest.setuid?(@path) end
735
+
736
+ # See <tt>FileTest.setgid?</tt>.
737
+ def setgid?() FileTest.setgid?(@path) end
738
+
739
+ # See <tt>FileTest.size</tt>.
740
+ def size() FileTest.size(@path) end
741
+
742
+ # See <tt>FileTest.size?</tt>.
743
+ def size?() FileTest.size?(@path) end
744
+
745
+ # See <tt>FileTest.sticky?</tt>.
746
+ def sticky?() FileTest.sticky?(@path) end
747
+
748
+ # See <tt>FileTest.symlink?</tt>.
749
+ def symlink?() FileTest.symlink?(@path) end
750
+
751
+ # See <tt>FileTest.writable?</tt>.
752
+ def writable?() FileTest.writable?(@path) end
753
+
754
+ # See <tt>FileTest.world_writable?</tt>.
755
+ def world_writable?() FileTest.world_writable?(@path) end
756
+
757
+ # See <tt>FileTest.writable_real?</tt>.
758
+ def writable_real?() FileTest.writable_real?(@path) end
759
+
760
+ # See <tt>FileTest.zero?</tt>.
761
+ def zero?() FileTest.zero?(@path) end
762
+ end
763
+
764
+
765
+ class Pathname # * Dir *
766
+ # See <tt>Dir.glob</tt>. Returns or yields Pathname objects.
767
+ def Pathname.glob(*args) # :yield: pathname
768
+ if block_given?
769
+ Dir.glob(*args) {|f| yield self.new(f) }
770
+ else
771
+ Dir.glob(*args).map {|f| self.new(f) }
772
+ end
773
+ end
774
+
775
+ # See <tt>Dir.getwd</tt>. Returns the current working directory as a Pathname.
776
+ def Pathname.getwd() self.new(Dir.getwd) end
777
+ class << self; alias pwd getwd end
778
+
779
+ # Return the entries (files and subdirectories) in the directory, each as a
780
+ # Pathname object.
781
+ def entries() Dir.entries(@path).map {|f| self.class.new(f) } end
782
+
783
+ # Iterates over the entries (files and subdirectories) in the directory. It
784
+ # yields a Pathname object for each entry.
785
+ #
786
+ # This method has existed since 1.8.1.
787
+ def each_entry(&block) # :yield: pathname
788
+ Dir.foreach(@path) {|f| yield self.class.new(f) }
789
+ end
790
+
791
+ # See <tt>Dir.mkdir</tt>. Create the referenced directory.
792
+ def mkdir(*args) Dir.mkdir(@path, *args) end
793
+
794
+ # See <tt>Dir.rmdir</tt>. Remove the referenced directory.
795
+ def rmdir() Dir.rmdir(@path) end
796
+
797
+ # See <tt>Dir.open</tt>.
798
+ def opendir(&block) # :yield: dir
799
+ Dir.open(@path, &block)
800
+ end
801
+ end
802
+
803
+
804
+ class Pathname # * Find *
805
+ #
806
+ # Pathname#find is an iterator to traverse a directory tree in a depth first
807
+ # manner. It yields a Pathname for each file under "this" directory.
808
+ #
809
+ # Since it is implemented by <tt>find.rb</tt>, <tt>Find.prune</tt> can be used
810
+ # to control the traverse.
811
+ #
812
+ # If +self+ is <tt>.</tt>, yielded pathnames begin with a filename in the
813
+ # current directory, not <tt>./</tt>.
814
+ #
815
+ def find(&block) # :yield: pathname
816
+ require 'find'
817
+ if @path == '.'
818
+ Find.find(@path) {|f| yield self.class.new(f.sub(%r{\A\./}, '')) }
819
+ else
820
+ Find.find(@path) {|f| yield self.class.new(f) }
821
+ end
822
+ end
823
+ end
824
+
825
+
826
+ class Pathname # * FileUtils *
827
+ # See <tt>FileUtils.mkpath</tt>. Creates a full path, including any
828
+ # intermediate directories that don't yet exist.
829
+ def mkpath
830
+ require 'fileutils'
831
+ FileUtils.mkpath(@path)
832
+ nil
833
+ end
834
+
835
+ # See <tt>FileUtils.rm_r</tt>. Deletes a directory and all beneath it.
836
+ def rmtree
837
+ # The name "rmtree" is borrowed from File::Path of Perl.
838
+ # File::Path provides "mkpath" and "rmtree".
839
+ require 'fileutils'
840
+ FileUtils.rm_r(@path)
841
+ nil
842
+ end
843
+ end
844
+
845
+
846
+ class Pathname # * mixed *
847
+ # Removes a file or directory, using <tt>File.unlink</tt> or
848
+ # <tt>Dir.unlink</tt> as necessary.
849
+ def unlink()
850
+ begin
851
+ Dir.unlink @path
852
+ rescue Errno::ENOTDIR
853
+ File.unlink @path
854
+ end
855
+ end
856
+ alias delete unlink
857
+ end
858
+
859
+ class Pathname
860
+ undef =~
861
+ end
862
+ end # RUBY_VERSION >= 1.9.3
863
+ end
864
+