pa 1.0.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.
data/lib/pa/dir.rb ADDED
@@ -0,0 +1,195 @@
1
+ =begin
2
+ == ls family
3
+ * Dir[*path] _support globbing_
4
+ * Pa.glob(*path,o),(){} _support globbing with option and block_
5
+ * each(path),(){} each_r(),(){} _support Enumerator. not support globbing_
6
+ * ls(path) ls_r(path) _sample ls. not support globbing._
7
+
8
+ === Example
9
+ tmp/
10
+ filea
11
+ dira/fileb
12
+
13
+ ls("tmp") => ["filea", "dira"]
14
+ ls_r("tmp") => ["filea", "dira", "dira/fileb"]
15
+ ls_r("tmp"){|pa, rel| rel.count('/')==1} => ["dira/fileb"]
16
+
17
+ each("tmp") => Enumerate<Pa>
18
+ each("tmp") {|pa| Pa.rm pa if pa.file?}
19
+ each("tmp").with_object([]){|pa,m| m<<pa.dir} #=> ["tmp", "tmp/dira"]
20
+
21
+ =end
22
+ class Pa
23
+ module ClassMethods::Dir
24
+
25
+ # path globbing, exclude '.' '..' for :dotmatch
26
+ # @note glob is * ** ? [set] {a,b}
27
+ #
28
+ # @overload glob(*paths, o={})
29
+ # @param [String] path
30
+ # @param [Hash] o option
31
+ # @option o [Boolean] :dotmatch glob not match dot file by default.
32
+ # @option o [Boolean] :pathname wildcard doesn't match /
33
+ # @option o [Boolean] :noescape makes '\\' ordinary
34
+ # @return [Array<Pa>]
35
+ # @overload glob(*paths, o={})
36
+ # @yieldparam [Pa] path
37
+ # @return [nil]
38
+ def glob(*args, &blk)
39
+ paths, o = args.extract_options
40
+ paths.map!{|v|get(v)}
41
+
42
+ flag = 0
43
+ o.each do |option, value|
44
+ flag |= File.const_get("FNM_#{option.upcase}") if value
45
+ end
46
+
47
+ ret = Dir.glob(paths, flag)
48
+
49
+ # delete . .. for '.*'
50
+ ret.tap{|paths| %w(. ..).each{|v| paths.delete(v)}}
51
+ ret.map!{|path|Pa(path)}
52
+
53
+ if blk
54
+ ret.each {|pa|
55
+ blk.call pa
56
+ }
57
+ else
58
+ ret
59
+ end
60
+ end
61
+
62
+ # is directory empty?
63
+ #
64
+ # @param [String] path
65
+ # @return [Boolean]
66
+ def empty?(path) Dir.entries(get(path)).empty? end
67
+
68
+ # traverse directory
69
+ # @note raise Errno::ENOTDIR, Errno::ENOENT
70
+ #
71
+ # @example
72
+ # each '.' do |pa|
73
+ # p pa.path #=> "foo" not "./foo"
74
+ # end
75
+ # # => '/home' ..
76
+ #
77
+ # each('.', error: true).with_object([]) do |(pa,err),m|
78
+ # ...
79
+ # end
80
+ #
81
+ # @overload each(path=".", o={})
82
+ # @param [String,Pa] path
83
+ # @prarm [Hash] o
84
+ # @option o [Boolean] :nodot (false) include dot file
85
+ # @option o [Boolean] :nobackup (false) include backup file
86
+ # @option o [Boolean] :error (false) yield(pa, err) instead of raise Errno::EPERM when Dir.open(dir)
87
+ # @return [Enumerator<Pa>]
88
+ # @overload each(path=".", o={})
89
+ # @yieldparam [Pa] path
90
+ # @return [nil]
91
+ def each(*args, &blk)
92
+ return Pa.to_enum(:each, *args) unless blk
93
+
94
+ (path,), o = args.extract_options
95
+ path = path ? get(path) : "."
96
+ raise Errno::ENOENT, "`#{path}' doesn't exists." unless File.exists?(path)
97
+ raise Errno::ENOTDIR, "`#{path}' not a directoyr." unless File.directory?(path)
98
+
99
+ begin
100
+ dir = Dir.open(path)
101
+ rescue Errno::EPERM => err
102
+ end
103
+ raise err if err and !o[:error]
104
+
105
+ while (entry=dir.read)
106
+ next if %w(. ..).include? entry
107
+ next if o[:nodot] and entry=~/^\./
108
+ next if o[:nobackup] and entry=~/~$/
109
+
110
+ # => "foo" not "./foo"
111
+ pa = path=="." ? Pa(entry) : Pa(File.join(path, entry))
112
+ if o[:error]
113
+ blk.call pa, err
114
+ else
115
+ blk.call pa
116
+ end
117
+ end
118
+ end
119
+
120
+ # each with recursive
121
+ # @see each
122
+ #
123
+ # * each_r() skip Exception
124
+ # * each_r(){pa, err}
125
+ #
126
+ # @overload each_r(path=".", o={})
127
+ # @return [Enumerator<Pa>]
128
+ # @overload each_r(path=".", o={})
129
+ # @yieldparam [Pa] pa
130
+ # @yieldparam [String] relative relative path
131
+ # @yieldparam [Errno::ENOENT,Errno::EPERM] err
132
+ # @return [nil]
133
+ def each_r(*args, &blk)
134
+ return Pa.to_enum(:each_r, *args) if not blk
135
+
136
+ (path,), o = args.extract_options
137
+ path ||= "."
138
+
139
+ _each_r(path, "", o, &blk)
140
+ end
141
+
142
+ # @param [String] path
143
+ def _each_r path, relative, o, &blk
144
+ o.merge!(error: true)
145
+ Pa.each(path, o) do |pa1, err|
146
+ relative1 = Pa.join(relative, pa1.b)
147
+
148
+ blk.call pa1, relative1, err
149
+
150
+ if pa1.directory?
151
+ _each_r(pa1.p, relative1, o, &blk)
152
+ end
153
+ end
154
+ end
155
+ private :_each_r
156
+
157
+ # list directory contents
158
+ # @see each
159
+ #
160
+ # block form is a filter.
161
+ #
162
+ # @Example
163
+ # Pa.ls(".") {|pa, fname| pa.directory?} # list only directories
164
+ #
165
+ # @overload ls(path=".", o={})
166
+ # @return [Array<String>]
167
+ # @overload ls(path=".", o={})
168
+ # @yieldparam [Pa] pa
169
+ # @yieldparam [String] fname
170
+ # @return [Array<String>]
171
+ def ls *args, &blk
172
+ blk ||= proc {true}
173
+ each(*args).with_object([]) { |pa,m|
174
+ m<<pa.fname if blk.call(pa, pa.fname)
175
+ }
176
+ end
177
+
178
+ # ls with recursive
179
+ # @see ls
180
+ #
181
+ # @overload ls_r(path=".", o={})
182
+ # @return [Array<String>]
183
+ # @overload ls_r(path=".", o={})
184
+ # @yieldparam [Pa] pa
185
+ # @yieldparam [String] rel
186
+ # @return [Array<String>]
187
+ def ls_r *args, &blk
188
+ blk ||= proc {true}
189
+ each_r(*args).with_object([]) { |(pa,rel),m|
190
+ m<<rel if blk.call(pa, rel)
191
+ }
192
+ end
193
+
194
+ end
195
+ end
data/lib/pa/path.rb ADDED
@@ -0,0 +1,301 @@
1
+ class Pa
2
+ NAME_EXT_PAT = /^(.+?)(?:\.([^.]+))?$/
3
+ module ClassMethods::Path
4
+
5
+ # alias from File.absolute_path
6
+ # @param [String,Pa] path
7
+ # @return [String]
8
+ def absolute(path); File.absolute_path(get(path)) end
9
+
10
+ # alias from File.expand_path
11
+ # @param [String,Pa] path
12
+ # @return [String]
13
+ def expand(path); File.expand_path(get(path)) end
14
+
15
+ # shorten a path,
16
+ # convert /home/user/file to ~/file
17
+ #
18
+ # @param [String,Pa] path
19
+ # @return [String]
20
+ def shorten(path);
21
+ get(path).sub(%r!^#{Regexp.escape(ENV["HOME"])}!, "~")
22
+ end
23
+
24
+ # return current work directory
25
+ # @return [String] path
26
+ def pwd() Dir.getwd end
27
+
28
+ # @return [Pa] path
29
+ def pwd2() Pa(Dir.getwd) end
30
+
31
+ # change directory
32
+ #
33
+ # @param [String,Pa] path
34
+ def cd(path=ENV["HOME"], &blk) Dir.chdir(get(path), &blk) end
35
+
36
+ # get path of an object.
37
+ #
38
+ # return obj#path if object has a 'path' instance method
39
+ #
40
+ # @param [String,#path] obj
41
+ # @return [String,nil] path
42
+ def get obj
43
+ if obj.respond_to?(:path)
44
+ obj.path
45
+ elsif String === obj
46
+ obj
47
+ else
48
+ raise Error, "not support type -- #{obj.inspect}(#{obj.class})"
49
+ end
50
+ end
51
+
52
+ # extname of a path
53
+ #
54
+ # @example
55
+ # "a.ogg" => "ogg"
56
+ # "a" => nil
57
+ #
58
+ # @param [String,Pa] path
59
+ # @return [String]
60
+ def extname path
61
+ _, ext = get(path).match(/\.([^.]+)$/).to_a
62
+ ext
63
+ end
64
+
65
+ # is path an absolute path ?
66
+ #
67
+ # @param [String,Pa] path
68
+ # @return [Boolean]
69
+ def absolute?(path) path=get(path); File.absolute_path(path) == path end
70
+
71
+ # get a basename of a path
72
+ #
73
+ # @example
74
+ # Pa.basename("foo.bar.c", ext: true) #=> \["foo.bar", "c"]
75
+ #
76
+ # @param [String,Pa] name
77
+ # @param [Hash] o options
78
+ # @option o [Boolean, String] :ext (false) return \[name, ext] if true
79
+ #
80
+ # @return [String] basename of a path unless o[:ext]
81
+ # @return [Array<String>] \[name, ext] if o[:ext].
82
+ def basename(name, o={})
83
+ name = File.basename(get(name))
84
+ if o[:ext]
85
+ name, ext = name.match(NAME_EXT_PAT).captures
86
+ [ name, (ext || "")]
87
+ else
88
+ name
89
+ end
90
+ end
91
+
92
+ # split path
93
+ #
94
+ # @example
95
+ # path="/home/a/file"
96
+ # split(path) #=> "/home/a", "file"
97
+ # split(path, :all) #=> "/", "home", "a", "file"
98
+ #
99
+ # @param [String,Pa] name
100
+ # @param [Hash] o option
101
+ # @option o [Boolean] :all split all parts
102
+ # @return [Array<String>]
103
+ def split(name, o={})
104
+ dir, fname = File.split(get(name))
105
+ ret = Array.wrap(basename(fname, o))
106
+
107
+ if o[:all]
108
+ loop do
109
+ dir1, fname = File.split(dir)
110
+ break if dir1 == dir
111
+ ret.unshift fname
112
+ dir = dir1
113
+ end
114
+ end
115
+ ret.unshift dir
116
+ ret
117
+ end
118
+
119
+ # join paths, skip nil and empty string.
120
+ #
121
+ # @param [*Array<String>] *paths
122
+ # @return [String]
123
+ def join *paths
124
+ paths.map!{|v|get(v)}
125
+
126
+ # skip nil
127
+ paths.compact!
128
+
129
+ # skip empty string
130
+ paths.delete("")
131
+
132
+ File.join(*paths)
133
+ end
134
+
135
+ # get parent path
136
+ #
137
+ # @param [String,Pa] path
138
+ # @param [Fixnum] n up level
139
+ # @return [String]
140
+ def parent path, n=1
141
+ path = get(path)
142
+ n.times do
143
+ path = File.dirname(path)
144
+ end
145
+ path
146
+ end
147
+
148
+ # link
149
+ #
150
+ # @overload ln(src, dest)
151
+ # @overload ln([src,..], directory)
152
+ #
153
+ # @param [Array<String>, String] src_s support globbing
154
+ # @param [String,Pa] dest
155
+ # @param [Hash] o option
156
+ # @option o [Boolean] :force overwrite if exists.
157
+ # @return [nil]
158
+ def ln(src_s, dest, o={}) _ln(File.method(:link), src_s, dest, o) end
159
+
160
+ # ln force
161
+ #
162
+ # @see ln
163
+ # @return [nil]
164
+ def ln_f(src_s, dest, o) o[:force]=true; _ln(File.method(:link), src_s, dest, o) end
165
+
166
+ # symbol link
167
+ #
168
+ # @see ln
169
+ # @return [nil]
170
+ def symln(src_s, dest, o) _ln(File.method(:symlink), src_s, dest, o) end
171
+ alias symlink ln
172
+
173
+ # symln force
174
+ #
175
+ # @see ln
176
+ # @return [nil]
177
+ def symln_f(src_s, dest, o) o[:force]=true; _ln(File.method(:symlink), src_s, dest, o) end
178
+
179
+ # @param [Array,String,#path] src_s
180
+ # @param [String,#path] dest
181
+ def _ln(method, src_s, dest, o={})
182
+ dest = get(dest)
183
+ glob(*Array.wrap(src_s)) {|src|
184
+ src = get(src)
185
+ dest = File.join(dest, File.basename(src)) if File.directory?(dest)
186
+ Pa.rm_r(dest) if o[:force] and File.exists?(dest)
187
+ method.call(src, dest)
188
+ }
189
+ end
190
+ private :_ln
191
+
192
+ # @see File.readlink
193
+ def readlink(path) File.readlink(get(path)) end
194
+
195
+ # is path a dangling symlink?
196
+ #
197
+ # a dangling symlink is a dead symlink.
198
+ #
199
+ # @param [String,Pa] path
200
+ # @return [Boolean]
201
+ def dangling? path
202
+ path=get(path)
203
+ if File.symlink?(path)
204
+ src = File.readlink(path)
205
+ not File.exists?(src)
206
+ else
207
+ nil
208
+ end
209
+ end # def dsymlink?
210
+
211
+ def realpath(path) File.realpath(get(path)) end
212
+
213
+ end
214
+ end
215
+
216
+ class Pa
217
+ =begin
218
+
219
+ attribute absolute and dir return String, method absolute_path(), dirname() return Pa
220
+
221
+ Pa("/home/a").dir #=> "/home"
222
+ Pa("/home/a").dirname #=> Pa("/home")
223
+
224
+ == methods from String
225
+ * +
226
+ * [g]sub[!] match =~
227
+ * start_with? end_with?
228
+
229
+ =end
230
+ module Path
231
+ # @return [String]
232
+ attr_reader :absolute, :dir, :base, :name, :ext, :fext, :short
233
+
234
+ def initialize_variables
235
+ super
236
+ @absolute = File.absolute_path(@path)
237
+ @dir = File.dirname(@path)
238
+ @base = File.basename(@path)
239
+ @name, @ext = @base.match(NAME_EXT_PAT).captures
240
+ @ext ||= ""
241
+ @fext = @ext.empty? ? "" : "."+@ext
242
+ end
243
+
244
+ alias a absolute
245
+ alias d dir
246
+ alias b base
247
+ alias n name
248
+ alias fname base
249
+ alias fn fname
250
+ alias e ext
251
+ alias fe fext
252
+
253
+ def short
254
+ @short ||= Pa.shorten(@path)
255
+ end
256
+
257
+ # @return [Pa] absolute path
258
+ def absolute2() @absolute2 ||= Pa(absolute) end
259
+
260
+ # @return [Pa] dirname
261
+ # @example
262
+ # Pa(__FILE__).dirname.join('.opts')
263
+ def dir2() @dir2 ||= Pa(dir) end
264
+
265
+ # add string to path
266
+ #
267
+ # @example
268
+ # pa = Pa('/home/foo/a.txt')
269
+ # pa+'~' #=> new Pa('/home/foo/a.txt~')
270
+ #
271
+ # @param [String] str
272
+ # @return [Pa]
273
+ def +(str) Pa(path+str) end
274
+
275
+ # @return [Pa]
276
+ def sub(*args,&blk) Pa(path.sub(*args,&blk)) end
277
+
278
+ # @return [Pa]
279
+ def gsub(*args,&blk) Pa(path.gsub(*args,&blk)) end
280
+
281
+ # @return [Pa]
282
+ def sub!(*args,&blk) self.replace path.sub(*args,&blk) end
283
+
284
+ # @return [Pa]
285
+ def gsub!(*args,&blk) self.replace path.gsub(*args,&blk) end
286
+
287
+ # @return [MatchData]
288
+ def match(*args,&blk) path.match(*args,&blk) end
289
+
290
+ # @return [Boolean]
291
+ def start_with?(*args) path.start_with?(*args) end
292
+
293
+ # @return [Boolean]
294
+ def end_with?(*args) path.end_with?(*args) end
295
+
296
+ def =~(regexp) path =~ regexp end
297
+
298
+ def ==(other) self.path == other.path end
299
+ end
300
+ end
301
+
data/lib/pa/state.rb ADDED
@@ -0,0 +1,67 @@
1
+ class Pa
2
+ module ClassMethods::State
3
+
4
+ # @see File.chmod
5
+ def chmod(mode, *paths) paths.map!{|v|get(v)}; File.chmod(mode, *paths) end
6
+
7
+ # @see File.lchmod
8
+ def lchmod(mode, *paths) paths.map!{|v|get(v)}; File.lchmod(mode, *paths) end
9
+
10
+ # @see File.chown
11
+ def chown(user, group=nil, *paths) paths.map!{|v|get(v)}; File.chown(user, group, *paths) end
12
+
13
+ # @see File.lchown
14
+ def lchown(user, group=nil, *paths) paths.map!{|v|get(v)}; File.lchown(user, group, *paths) end
15
+
16
+ # @see File.utime
17
+ def utime(atime, mtime, *paths) paths.map!{|v|get(v)}; File.utime(atime, mtime, *paths) end
18
+
19
+
20
+ # get file type
21
+ #
22
+ # file types:
23
+ # "chardev" "blockdev" "symlink" ..
24
+ #
25
+ # @param [String] path
26
+ # @return [String]
27
+ def type(path)
28
+ case (t=File.ftype(get(path)))
29
+ when "characterSpecial"
30
+ "chardev"
31
+ when "blockSpecial"
32
+ "blockdev"
33
+ when "link"
34
+ "symlink"
35
+ else
36
+ t
37
+ end
38
+ end # def type
39
+
40
+
41
+ # is path a mountpoint?
42
+ #
43
+ # @param[String] path
44
+ # @return [Boolean]
45
+ def mountpoint? path
46
+ path=get(path)
47
+ begin
48
+ stat1 = File.lstat(path)
49
+ stat2 = File.lstat(File.join(path, '..'))
50
+ stat1.dev == stat2.dev && stat1.ino == stat2.ino || stat1.dev != stat2.dev
51
+ rescue Errno::ENOENT
52
+ false
53
+ end
54
+ end
55
+ end
56
+
57
+ module State
58
+ def chmod(mode); File.chmod(mode, path) end
59
+ def lchmod(mode); File.lchmod(mode, path) end
60
+ def chown(uid, gid=nil); File.chown(uid, gid, path) end
61
+ def lchown(uid, gid=nil); File.lchown(uid, gid, path) end
62
+ def utime(atime, mtime); File.utime(atime, mtime, path) end
63
+ end
64
+
65
+ end
66
+
67
+