path 1.3.0

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,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