fakefs 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+