path 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,132 @@
1
+ class Path
2
+ # @!group File
3
+
4
+ # Returns last access time. See +File.atime+.
5
+ def atime
6
+ File.atime(@path)
7
+ end
8
+
9
+ # Returns last change time (of the directory entry, not the file itself).
10
+ # See +File.ctime+.
11
+ def ctime
12
+ File.ctime(@path)
13
+ end
14
+
15
+ # Returns last modification time. See +File.mtime+.
16
+ def mtime
17
+ File.mtime(@path)
18
+ end
19
+
20
+ # Changes permissions of +path+. See +File.chmod+.
21
+ def chmod(mode)
22
+ File.chmod(mode, @path)
23
+ end
24
+
25
+ # Changes permissions of +path+, not following symlink. See +File.lchmod+.
26
+ def lchmod(mode)
27
+ File.lchmod(mode, @path)
28
+ end
29
+
30
+ # Changes the owner and group of the file. See +File.chown+.
31
+ def chown(owner, group)
32
+ File.chown(owner, group, @path)
33
+ end
34
+
35
+ # Changes the owner and group of +path+, not following symlink.
36
+ # See +File.lchown+.
37
+ def lchown(owner, group)
38
+ File.lchown(owner, group, @path)
39
+ end
40
+
41
+ # Returns "type" of file ("file", "directory", etc). See +File.ftype+.
42
+ def ftype
43
+ File.ftype(@path)
44
+ end
45
+
46
+ # Creates a hard link to +target+ and returns self.
47
+ #
48
+ # Raises Errno::EEXIST if self already exist.
49
+ # See +File.link+ (arguments are swapped).
50
+ def make_link(target)
51
+ File.link(target, @path)
52
+ self
53
+ end
54
+
55
+ # Reads the symbolic link. See +File.readlink+.
56
+ def readlink
57
+ Path.new(File.readlink(@path))
58
+ end
59
+
60
+ # Renames the file and returns the new Path. See +File.rename+.
61
+ def rename(to)
62
+ File.rename(@path, to)
63
+ Path(to)
64
+ end
65
+
66
+ # Returns the stat of +path+ as a +File::Stat+ object. See +File.stat+.
67
+ def stat
68
+ File.stat(@path)
69
+ end
70
+
71
+ # Returns the stat of +path+ as a +File::Stat+ object, not following symlink. See +File.lstat+.
72
+ def lstat
73
+ File.lstat(@path)
74
+ end
75
+
76
+ # Returns the file size in bytes. See +File.size+.
77
+ def size
78
+ File.size(@path)
79
+ end
80
+
81
+ # Creates a symbolic link to +target+ and returns self.
82
+ #
83
+ # Raises Errno::EEXIST if self already exist.
84
+ # See +File.symlink+ (arguments are swapped).
85
+ def make_symlink(target)
86
+ File.symlink(target, @path)
87
+ self
88
+ end
89
+
90
+ # Truncates the file to +length+ bytes. See +File.truncate+.
91
+ def truncate(length)
92
+ File.truncate(@path, length)
93
+ end
94
+
95
+ # Removes a file using +File.unlink+.
96
+ # This is incompatible with Pathname#unlink,
97
+ # which can also remove directories.
98
+ # Use {#rmdir} or {#rm_r} for directories.
99
+ def unlink
100
+ File.unlink @path
101
+ end
102
+ alias :delete :unlink
103
+
104
+ # Updates the access and modification times. See +File.utime+.
105
+ def utime(atime, mtime)
106
+ File.utime(atime, mtime, @path)
107
+ end
108
+
109
+ # Expands +path+, making it absolute.
110
+ # If the path is relative, it is expanded with the current working directory,
111
+ # unless +dir+ is given as an argument. See +File.expand_path+.
112
+ def expand(*args)
113
+ Path.new(File.expand_path(@path, *args))
114
+ end
115
+ alias :expand_path :expand
116
+
117
+ # Returns the real (absolute) path of +self+ in the actual
118
+ # filesystem not containing symlinks or useless dots.
119
+ #
120
+ # All components of the path must exist when this method is called.
121
+ def realpath(basedir=nil)
122
+ Path.new(real_path_internal(true, basedir))
123
+ end
124
+
125
+ # Returns the real (absolute) path of +self+ in the actual filesystem.
126
+ # The real path doesn't contain symlinks or useless dots.
127
+ #
128
+ # The last component of the real path can be nonexistent.
129
+ def realdirpath(basedir=nil)
130
+ Path.new(real_path_internal(false, basedir))
131
+ end
132
+ end
@@ -0,0 +1,151 @@
1
+ # All methods from FileTest and all predicates from File are included
2
+
3
+ class Path
4
+ # @!group File predicates
5
+
6
+ # See +File.blockdev?+.
7
+ def blockdev?
8
+ File.blockdev?(@path)
9
+ end
10
+
11
+ # See +File.chardev?+.
12
+ def chardev?
13
+ File.chardev?(@path)
14
+ end
15
+
16
+ # See +File.executable?+.
17
+ def executable?
18
+ File.executable?(@path)
19
+ end
20
+
21
+ # See +File.executable_real?+.
22
+ def executable_real?
23
+ File.executable_real?(@path)
24
+ end
25
+
26
+ # See +File.exist?+.
27
+ def exist?
28
+ File.exist?(@path)
29
+ end
30
+ alias :exists? :exist?
31
+
32
+ # See +File.grpowned?+.
33
+ def grpowned?
34
+ File.grpowned?(@path)
35
+ end
36
+
37
+ # See +File.directory?+.
38
+ def directory?
39
+ File.directory?(@path)
40
+ end
41
+ alias :dir? :directory?
42
+
43
+ # See +File.file?+.
44
+ def file?
45
+ File.file?(@path)
46
+ end
47
+
48
+ # See +File.pipe?+.
49
+ def pipe?
50
+ File.pipe?(@path)
51
+ end
52
+
53
+ # See +File.socket?+.
54
+ def socket?
55
+ File.socket?(@path)
56
+ end
57
+
58
+ # See +File.owned?+.
59
+ def owned?
60
+ File.owned?(@path)
61
+ end
62
+
63
+ # See +File.readable?+.
64
+ def readable?
65
+ File.readable?(@path)
66
+ end
67
+
68
+ if File.respond_to? :world_readable?
69
+ # See +File.world_readable?+.
70
+ def world_readable?
71
+ File.world_readable?(@path)
72
+ end
73
+ else
74
+ def world_readable?
75
+ mode = File.stat(@path).mode & 0777
76
+ mode if (mode & 04).nonzero?
77
+ end
78
+ end
79
+
80
+ # See +File.readable_real?+.
81
+ def readable_real?
82
+ File.readable_real?(@path)
83
+ end
84
+
85
+ # See +File.setuid?+.
86
+ def setuid?
87
+ File.setuid?(@path)
88
+ end
89
+
90
+ # See +File.setgid?+.
91
+ def setgid?
92
+ File.setgid?(@path)
93
+ end
94
+
95
+ # See +File.size?+.
96
+ def size?
97
+ File.size?(@path)
98
+ end
99
+
100
+ # See +File.sticky?+.
101
+ def sticky?
102
+ File.sticky?(@path)
103
+ end
104
+
105
+ # See +File.symlink?+.
106
+ def symlink?
107
+ File.symlink?(@path)
108
+ end
109
+
110
+ # See +File.writable?+.
111
+ def writable?
112
+ File.writable?(@path)
113
+ end
114
+
115
+ if File.respond_to? :world_writable?
116
+ # See +File.world_writable?+.
117
+ def world_writable?
118
+ File.world_writable?(@path)
119
+ end
120
+ else
121
+ def world_writable?
122
+ mode = File.stat(@path).mode & 0777
123
+ mode if (mode & 02).nonzero?
124
+ end
125
+ end
126
+
127
+ # See +File.writable_real?+.
128
+ def writable_real?
129
+ File.writable_real?(@path)
130
+ end
131
+
132
+ # See +File.zero?+.
133
+ # empty? is not defined in File/FileTest, but is is clearer.
134
+ def zero?
135
+ File.zero?(@path)
136
+ end
137
+ alias :empty? :zero?
138
+
139
+ # See +File.identical?+.
140
+ def identical?(path)
141
+ File.identical?(@path, path)
142
+ end
143
+
144
+ # Only in File, not FileTest
145
+
146
+ # Return +true+ if the receiver matches the given pattern.
147
+ # See +File.fnmatch?+.
148
+ def fnmatch?(pattern, *args)
149
+ File.fnmatch?(pattern, @path, *args)
150
+ end
151
+ end
@@ -0,0 +1,109 @@
1
+ require 'fileutils'
2
+
3
+ class Path
4
+ # @!group File utilities
5
+
6
+ # Creates a full path, including any intermediate directories that don't yet exist.
7
+ # See +FileUtils.mkpath+.
8
+ def mkpath
9
+ FileUtils.mkpath(@path)
10
+ self
11
+ end
12
+ alias :mkdir_p :mkpath
13
+
14
+ # Deletes a directory and all beneath it. See +FileUtils.rm_r+.
15
+ def rmtree
16
+ # The name "rmtree" is borrowed from File::Path of Perl.
17
+ # File::Path provides "mkpath" and "rmtree".
18
+ FileUtils.rm_r(@path)
19
+ self
20
+ end
21
+ alias :rm_r :rmtree
22
+
23
+ # Removes the file using +FileUtils.rm+.
24
+ def rm
25
+ FileUtils.rm(@path)
26
+ self
27
+ end
28
+
29
+ # Removes the file, ignoring errors, using +FileUtils.rm_f+.
30
+ def rm_f
31
+ FileUtils.rm_f(@path)
32
+ self
33
+ end
34
+ alias :safe_unlink :rm_f
35
+
36
+ # Removes the file or directory recursively, ignoring errors,
37
+ # using +FileUtils.rm_f+.
38
+ def rm_rf
39
+ FileUtils.rm_rf(@path)
40
+ self
41
+ end
42
+
43
+ # Copies the file to +to+. See +FileUtils.cp+.
44
+ def cp(to)
45
+ # TODO: remove :preserve when all implement it correctly (r31123)
46
+ FileUtils.cp(@path, to, :preserve => true)
47
+ end
48
+ alias :copy :cp
49
+
50
+ # Copies the file or directory recursively to the directory +to+.
51
+ # See +FileUtils.cp_r+.
52
+ def cp_r(to)
53
+ FileUtils.cp_r(@path, to)
54
+ end
55
+
56
+ # Updates access and modification time or create an empty file.
57
+ def touch
58
+ if exist?
59
+ now = Time.now
60
+ File.utime(now, now, @path)
61
+ else
62
+ open('w') {}
63
+ end
64
+ self
65
+ end
66
+
67
+ # {#touch} preceded by +dir.+{#mkpath}.
68
+ def touch!
69
+ dir.mkpath
70
+ touch
71
+ end
72
+
73
+ # Moves +self+ to the +to+ directory.
74
+ def mv(to)
75
+ FileUtils.mv(@path, to)
76
+ to
77
+ end
78
+ alias :move :mv
79
+
80
+ # Install +file+ into +path+ (the "prefix", which should be a directory).
81
+ # If +file+ is not same as +path/file+, replaces it.
82
+ # See +FileUtils.install+ (arguments are swapped).
83
+ def install(file, options = {})
84
+ FileUtils.install(file, @path, options)
85
+ end
86
+
87
+ # Recusively changes permissions. See +FileUtils.chmod_R+ and +File.chmod+.
88
+ def chmod_r(mode)
89
+ FileUtils.chmod_R(mode, @path)
90
+ end
91
+
92
+ # Recusively changes owner and group. See +FileUtils.chown_R+ and +File.chown+.
93
+ def chown_r(owner, group)
94
+ FileUtils.chown_R(owner, group, @path)
95
+ end
96
+
97
+ # Whether the contents of +path+ and +file+ are identical.
98
+ # See +FileUtils.compare_file+.
99
+ def has_same_contents?(file)
100
+ FileUtils.compare_file(@path, file)
101
+ end
102
+
103
+ # Returns whether +self+ is newer than all +others+.
104
+ # Non-existent files are older than any file.
105
+ # See +FileUtils.uptodate?+.
106
+ def uptodate?(*others)
107
+ FileUtils.uptodate?(@path, others)
108
+ end
109
+ end
@@ -0,0 +1,23 @@
1
+ class Path
2
+ # Path#find is an iterator to traverse a directory tree in a depth first
3
+ # manner. It yields a Path for each file under "this" directory.
4
+ #
5
+ # Returns an enumerator if no block is given.
6
+ #
7
+ # Since it is implemented by +find.rb+, +Find.prune+ can be used
8
+ # to control the traversal.
9
+ #
10
+ # If +self+ is +.+, yielded paths begin with a filename in the
11
+ # current directory, not +./+.
12
+ #
13
+ # @yieldparam [Path] path
14
+ def find
15
+ return to_enum(__method__) unless block_given?
16
+ require 'find'
17
+ if @path == '.'
18
+ Find.find(@path) { |f| yield Path.new(f.sub(%r{\A\./}, '')) }
19
+ else
20
+ Find.find(@path) { |f| yield Path.new(f) }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,163 @@
1
+ class Path
2
+ class << self
3
+ # @!group Identity
4
+
5
+ # Creates a new Path. See {#initialize}.
6
+ def new(*args)
7
+ if args.size == 1 and Path === args.first
8
+ args.first
9
+ else
10
+ super(*args)
11
+ end
12
+ end
13
+ alias :[] :new
14
+
15
+ # A class constructor.
16
+ #
17
+ # %w[foo bar].map(&Path) # == [Path('foo'), Path('bar')]
18
+ def to_proc
19
+ lambda { |path| new(path) }
20
+ end
21
+
22
+ # Whether +object+ looks like a path.
23
+ # The current test checks if the object responds to
24
+ # #to_path, #path or #to_str.
25
+ def like? object
26
+ [:to_path, :path, :to_str].any? { |meth| object.respond_to? meth }
27
+ end
28
+
29
+ # A matcher responding to #===. Useful for case clauses, grep, etc.
30
+ # See {Path.like?}.
31
+ #
32
+ # case obj
33
+ # when Path.like then Path(obj)
34
+ # # ...
35
+ # end
36
+ def like
37
+ @like ||= begin
38
+ matcher = Object.new
39
+ def matcher.===(object)
40
+ Path.like?(object)
41
+ end
42
+ matcher
43
+ end
44
+ end
45
+ end
46
+
47
+ # @!group Identity
48
+
49
+ # Creates a new Path.
50
+ # If multiple arguments are given, they are joined with File.join.
51
+ # The path will have File::ALT_SEPARATOR replaced with '/' and
52
+ # if it begins with a '~', it will be expanded (using File.expand_path).
53
+ # Accepts an Array of Strings, a Tempfile, anything that respond to #path,
54
+ # #to_path or #to_str with a String and defaults to calling #to_s.
55
+ #
56
+ # @param parts [Array<String>, Tempfile, #to_path, #path, #to_str, #to_s] the path-like object(s)
57
+ def initialize(*parts)
58
+ path = parts.size > 1 ? File.join(*parts) : parts.first
59
+ @path = case path
60
+ when Tempfile
61
+ @_tmpfile = path # We would not want it to be GC'd
62
+ path.path.dup
63
+ when String
64
+ path.dup
65
+ else
66
+ if path.respond_to? :to_path and String === path.to_path
67
+ path.to_path.dup
68
+ elsif path.respond_to? :path and String === path.path
69
+ path.path.dup
70
+ elsif path.respond_to? :to_str and String === path.to_str
71
+ path.to_str.dup
72
+ else
73
+ path.to_s.dup
74
+ end
75
+ end
76
+
77
+ init
78
+ end
79
+
80
+ # Returns the +path+ as a String.
81
+ # {#path} is implemented for better readability (+file.path+ instead of +file.to_s+) and as an accessor.
82
+ # {#to_path} is implemented so Path objects are usable with +open+, etc.
83
+ # {#to_str} is implemented so Path objects are usable with +open+, etc with Ruby 1.8 (it is not defined in Ruby 1.9).
84
+ attr_reader :path
85
+ alias :to_s :path
86
+ alias :to_path :path
87
+ alias :to_str :path if RUBY_VERSION < '1.9'
88
+
89
+ # Compare this path with +other+. The comparison is string-based.
90
+ # Be aware that two different paths (+foo.txt+ and +./foo.txt+)
91
+ # can refer to the same file.
92
+ def == other
93
+ Path === other and @path == other.path
94
+ end
95
+ alias :eql? :==
96
+
97
+ # Provides for comparing paths, case-sensitively.
98
+ def <=>(other)
99
+ return nil unless Path === other
100
+ @path.tr('/', "\0") <=> other.path.tr('/', "\0")
101
+ end
102
+
103
+ # The hash value of the +path+.
104
+ def hash
105
+ @path.hash
106
+ end
107
+
108
+ # Returns the +path+ as a Symbol.
109
+ def to_sym
110
+ @path.to_sym
111
+ end
112
+
113
+ # A representation of the +path+.
114
+ def inspect
115
+ "#<Path #{@path}>"
116
+ end
117
+
118
+ # YAML loading.
119
+ def yaml_initialize(tag, ivars)
120
+ @path = ivars['path']
121
+ init
122
+ end
123
+
124
+ # Psych loading.
125
+ def init_with(coder)
126
+ @path = coder['path']
127
+ init
128
+ end
129
+
130
+ # JSON dumping.
131
+ def to_json(*args)
132
+ {
133
+ 'json_class' => 'Path',
134
+ 'data' => @path
135
+ }.to_json(*args)
136
+ end
137
+
138
+ # JSON loading.
139
+ def self.json_create json
140
+ new json['data']
141
+ end
142
+
143
+ # Marshal dumping.
144
+ def marshal_dump
145
+ @path
146
+ end
147
+
148
+ # Marshal loading.
149
+ def marshal_load path
150
+ @path = path
151
+ init
152
+ end
153
+ end
154
+
155
+ unless defined?(NO_PATH_GLOBAL_FUNCTION)
156
+ module Kernel
157
+ # A shorthand method to create a {Path}. Same as {Path.new}.
158
+ def Path(*args)
159
+ Path.new(*args)
160
+ end
161
+ private :Path
162
+ end
163
+ end