pa 1.0.3 → 1.1.3

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