filepath 0.1 → 0.2
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/.yardopts +1 -1
- data/README.md +8 -6
- data/Rakefile +3 -1
- data/lib/filepath.rb +95 -68
- data/spec/filepath_spec.rb +50 -1
- metadata +20 -9
data/.yardopts
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
FilePath
|
2
2
|
========
|
3
3
|
|
4
|
-
|
5
|
-
general; a modern replacement for the standard Pathname.
|
4
|
+
filepath is a small library that helps dealing with files, directories and
|
5
|
+
paths in general; a modern replacement for the standard Pathname.
|
6
|
+
|
7
|
+
filepath is built around two main classes: `FilePath`, that represents paths,
|
8
|
+
and `FilePathList`, lists of paths. The instances of these classes are
|
9
|
+
immutable objects with dozens of convience methods for common operations such
|
10
|
+
as calculating relative paths, concatenating paths, finding all the files in
|
11
|
+
a directory or modifing all the extensions of a list of file names at once.
|
6
12
|
|
7
|
-
`FilePath` instances are immutable objects with dozens of convience methods
|
8
|
-
for common operations such as calculating relative paths, concatenating paths
|
9
|
-
or finding all the files in a directory. There is also a companion class
|
10
|
-
`FilePathList` to perform operations on multiple files at once.
|
11
13
|
|
12
14
|
Features and examples
|
13
15
|
---------------------
|
data/Rakefile
CHANGED
@@ -13,9 +13,11 @@ Bones {
|
|
13
13
|
email 'gioele@svario.it'
|
14
14
|
url 'http://github.com/gioele/filepath'
|
15
15
|
|
16
|
-
version '0.
|
16
|
+
version '0.2'
|
17
17
|
|
18
18
|
ignore_file '.gitignore'
|
19
|
+
|
20
|
+
depend_on 'bones-rspec', :development => true
|
19
21
|
}
|
20
22
|
|
21
23
|
require File.join(File.dirname(__FILE__), 'spec/tasks')
|
data/lib/filepath.rb
CHANGED
@@ -27,7 +27,7 @@ class FilePath
|
|
27
27
|
raw_paths = raw_paths.first
|
28
28
|
end
|
29
29
|
|
30
|
-
paths = raw_paths.map { |p|
|
30
|
+
paths = raw_paths.map { |p| p.as_path }
|
31
31
|
|
32
32
|
frags = []
|
33
33
|
paths.each { |path| frags += path.fragments }
|
@@ -40,12 +40,12 @@ class FilePath
|
|
40
40
|
#
|
41
41
|
# @example Append a string
|
42
42
|
#
|
43
|
-
#
|
43
|
+
# "a/b".as_path / "c" #=> <a/b/c>
|
44
44
|
#
|
45
45
|
# @example Append another FilePath
|
46
46
|
#
|
47
|
-
# home =
|
48
|
-
# conf_dir =
|
47
|
+
# home = (ENV["HOME"] || "/root").as_path
|
48
|
+
# conf_dir = '.config'.as_path
|
49
49
|
#
|
50
50
|
# home / conf_dir #=> </home/user/.config>
|
51
51
|
#
|
@@ -82,15 +82,17 @@ class FilePath
|
|
82
82
|
end
|
83
83
|
|
84
84
|
|
85
|
-
# Calculates the relative path from
|
85
|
+
# Calculates the relative path from a given directory.
|
86
86
|
#
|
87
|
-
# @param [FilePath, String] base the
|
87
|
+
# @param [FilePath, String] base the directory to use as base for the
|
88
88
|
# relative path
|
89
89
|
#
|
90
90
|
# @return [FilePath] the relative path
|
91
|
+
#
|
92
|
+
# @note this method operates on the normalized paths
|
91
93
|
|
92
94
|
def relative_to(base)
|
93
|
-
base =
|
95
|
+
base = base.as_path
|
94
96
|
|
95
97
|
if self.absolute? != base.absolute?
|
96
98
|
self_abs = self.absolute? ? "absolute" : "relative"
|
@@ -101,21 +103,37 @@ class FilePath
|
|
101
103
|
raise msg # FIXME: argerror error class
|
102
104
|
end
|
103
105
|
|
104
|
-
self_frags = self.
|
105
|
-
base_frags = base.
|
106
|
+
self_frags = self.normalized_fragments
|
107
|
+
base_frags = base.normalized_fragments
|
108
|
+
|
109
|
+
base_frags_tmp = base_frags.dup
|
106
110
|
num_same = self_frags.find_index do |frag|
|
107
|
-
|
111
|
+
base_frags_tmp.delete_at(0) != frag
|
108
112
|
end
|
109
113
|
|
110
114
|
# find_index returns nil if `self` is a subset of `base`
|
111
|
-
num_same ||=
|
115
|
+
num_same ||= self_frags.length
|
112
116
|
|
113
|
-
num_parent_dirs =
|
114
|
-
left_in_self =
|
117
|
+
num_parent_dirs = base_frags.length - num_same
|
118
|
+
left_in_self = self_frags[num_same..-1]
|
115
119
|
|
116
120
|
frags = [".."] * num_parent_dirs + left_in_self
|
121
|
+
normalized_frags = normalized_relative_frags(frags)
|
117
122
|
|
118
|
-
return FilePath.join(
|
123
|
+
return FilePath.join(normalized_frags)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Calculates the relative path from a given file.
|
127
|
+
#
|
128
|
+
# @param [FilePath, String] base the file to use as base for the
|
129
|
+
# relative path
|
130
|
+
#
|
131
|
+
# @return [FilePath] the relative path
|
132
|
+
#
|
133
|
+
# @see #relative_to
|
134
|
+
|
135
|
+
def relative_to_file(base_file)
|
136
|
+
return relative_to(base_file.as_path.parent_dir)
|
119
137
|
end
|
120
138
|
|
121
139
|
|
@@ -128,11 +146,11 @@ class FilePath
|
|
128
146
|
|
129
147
|
def filename
|
130
148
|
if self.root?
|
131
|
-
return
|
149
|
+
return ''.as_path
|
132
150
|
end
|
133
151
|
|
134
152
|
filename = self.normalized_fragments.last
|
135
|
-
return
|
153
|
+
return filename.as_path
|
136
154
|
end
|
137
155
|
|
138
156
|
alias :basename :filename
|
@@ -157,7 +175,7 @@ class FilePath
|
|
157
175
|
|
158
176
|
def replace_filename(new_path)
|
159
177
|
dir = self.parent_dir
|
160
|
-
return dir /
|
178
|
+
return dir / new_path
|
161
179
|
end
|
162
180
|
|
163
181
|
alias :replace_basename :replace_filename
|
@@ -232,21 +250,24 @@ class FilePath
|
|
232
250
|
def replace_extension(new_ext) # FIXME: accept block
|
233
251
|
if !self.extension?
|
234
252
|
if new_ext.nil?
|
235
|
-
|
253
|
+
new_filename = filename
|
236
254
|
else
|
237
|
-
|
255
|
+
new_filename = filename.to_s + '.' + new_ext
|
238
256
|
end
|
239
257
|
else
|
240
258
|
if new_ext.nil?
|
241
259
|
pattern = /\.[^.]*?\Z/
|
242
|
-
|
260
|
+
new_filename = filename.to_s.sub(pattern, '')
|
243
261
|
else
|
244
|
-
pattern = '.' + extension
|
245
|
-
|
262
|
+
pattern = Regexp.new('.' + extension + '\\Z')
|
263
|
+
new_filename = filename.to_s.sub(pattern, '.' + new_ext)
|
246
264
|
end
|
247
265
|
end
|
248
266
|
|
249
|
-
|
267
|
+
frags = @fragments[0..-2]
|
268
|
+
frags << new_filename
|
269
|
+
|
270
|
+
return FilePath.join(frags)
|
250
271
|
end
|
251
272
|
|
252
273
|
alias :replace_ext :replace_extension
|
@@ -264,6 +285,16 @@ class FilePath
|
|
264
285
|
alias :remove_ext :remove_extension
|
265
286
|
|
266
287
|
|
288
|
+
# Matches a pattern against this path.
|
289
|
+
#
|
290
|
+
# @param [Regexp, Object] pattern the pattern to match against
|
291
|
+
# this path
|
292
|
+
#
|
293
|
+
# @return [Fixnum, nil] the position of the pattern in the path, or
|
294
|
+
# nil if there is no match
|
295
|
+
#
|
296
|
+
# @note this method operates on the normalized path
|
297
|
+
|
267
298
|
def =~(pattern)
|
268
299
|
return self.to_s =~ pattern
|
269
300
|
end
|
@@ -319,11 +350,7 @@ class FilePath
|
|
319
350
|
# @yield [path] TODO
|
320
351
|
|
321
352
|
def ascend(max_depth = nil, &block)
|
322
|
-
max_depth
|
323
|
-
(1..max_depth).reverse_each do |limit|
|
324
|
-
frags = @fragments.take(limit)
|
325
|
-
yield FilePath.join(frags)
|
326
|
-
end
|
353
|
+
iterate(max_depth, :reverse_each, &block)
|
327
354
|
end
|
328
355
|
|
329
356
|
# Iterates over all the directory that lead to the current path.
|
@@ -334,8 +361,13 @@ class FilePath
|
|
334
361
|
# @yield [path] TODO
|
335
362
|
|
336
363
|
def descend(max_depth = nil, &block)
|
364
|
+
iterate(max_depth, :each, &block)
|
365
|
+
end
|
366
|
+
|
367
|
+
# @private
|
368
|
+
def iterate(max_depth, method, &block)
|
337
369
|
max_depth ||= @fragments.length
|
338
|
-
(1..max_depth).
|
370
|
+
(1..max_depth).send(method) do |limit|
|
339
371
|
frags = @fragments.take(limit)
|
340
372
|
yield FilePath.join(frags)
|
341
373
|
end
|
@@ -355,19 +387,25 @@ class FilePath
|
|
355
387
|
|
356
388
|
# @return [String] this path converted to a String
|
357
389
|
#
|
358
|
-
# @note this method operates on the normalized
|
390
|
+
# @note this method operates on the normalized path
|
359
391
|
|
360
392
|
def to_s
|
361
393
|
return self.normalized_fragments.join(SEPARATOR).sub(%r{^//}, SEPARATOR)
|
362
394
|
end
|
363
395
|
|
364
396
|
|
397
|
+
# @return [FilePath] the path itself.
|
398
|
+
def as_path
|
399
|
+
self
|
400
|
+
end
|
401
|
+
|
402
|
+
|
365
403
|
def inspect
|
366
404
|
return '<' + self.to_raw_string + '>'
|
367
405
|
end
|
368
406
|
|
369
407
|
def ==(other)
|
370
|
-
return self.to_s ==
|
408
|
+
return self.to_s == other.as_path.to_s
|
371
409
|
end
|
372
410
|
|
373
411
|
# @private
|
@@ -403,7 +441,7 @@ class FilePath
|
|
403
441
|
# remove '..' fragments following a root delimiter
|
404
442
|
frags.delete_at(i)
|
405
443
|
i -= 1
|
406
|
-
elsif frags[i] == '..' && frags[i-1] != '..'
|
444
|
+
elsif frags[i] == '..' && frags[i-1] != '..' && i >= 1
|
407
445
|
# remove every fragment followed by a ".." marker
|
408
446
|
frags.delete_at(i)
|
409
447
|
frags.delete_at(i-1)
|
@@ -420,63 +458,52 @@ class FilePath
|
|
420
458
|
path = if !self.absolute?
|
421
459
|
self
|
422
460
|
else
|
423
|
-
|
461
|
+
base_dir.as_path / self
|
424
462
|
end
|
425
463
|
|
426
464
|
return path.resolve_link
|
427
465
|
end
|
428
466
|
|
429
467
|
def resolve_link
|
430
|
-
return
|
468
|
+
return File.readlink(self.to_s).as_path
|
431
469
|
end
|
432
470
|
end
|
433
471
|
|
434
472
|
module FileInfo
|
435
|
-
|
436
|
-
|
473
|
+
# @private
|
474
|
+
def self.define_filetest_method(filepath_method, filetest_method = nil)
|
475
|
+
filetest_method ||= filepath_method
|
476
|
+
define_method(filepath_method) do
|
477
|
+
return FileTest.send(filetest_method, self.to_s)
|
478
|
+
end
|
437
479
|
end
|
438
480
|
|
439
|
-
|
440
|
-
FileTest.symlink?(self.to_s)
|
441
|
-
end
|
442
|
-
alias symlink? link?
|
481
|
+
define_filetest_method :file?
|
443
482
|
|
444
|
-
|
445
|
-
|
446
|
-
end
|
483
|
+
define_filetest_method :link?, :symlink?
|
484
|
+
alias :symlink? :link?
|
447
485
|
|
448
|
-
|
449
|
-
FileTest.exists?(self.to_s)
|
450
|
-
end
|
451
|
-
alias exist? exists?
|
486
|
+
define_filetest_method :directory?
|
452
487
|
|
453
|
-
|
454
|
-
|
455
|
-
end
|
488
|
+
define_filetest_method :exists?
|
489
|
+
alias :exist? :exists?
|
456
490
|
|
457
|
-
|
458
|
-
FileTest.writable?(self.to_s)
|
459
|
-
end
|
491
|
+
define_filetest_method :readable?
|
460
492
|
|
461
|
-
|
462
|
-
FileTest.executable?(self.to_s)
|
463
|
-
end
|
493
|
+
define_filetest_method :writeable?
|
464
494
|
|
465
|
-
|
466
|
-
FileTest.setgid?(self.to_s)
|
467
|
-
end
|
495
|
+
define_filetest_method :executable?
|
468
496
|
|
469
|
-
|
470
|
-
|
471
|
-
|
497
|
+
define_filetest_method :setgid?
|
498
|
+
|
499
|
+
define_filetest_method :setuid?
|
500
|
+
|
501
|
+
define_filetest_method :empty?, :zero?
|
502
|
+
alias :zero? :empty?
|
472
503
|
|
473
504
|
def hidden?
|
474
505
|
@fragments.last.start_with('.') # FIXME: windows, mac
|
475
506
|
end
|
476
|
-
|
477
|
-
def empty?
|
478
|
-
FileTest.zero?(self.to_s)
|
479
|
-
end
|
480
507
|
end
|
481
508
|
|
482
509
|
module FileManipulationMethods
|
@@ -489,7 +516,7 @@ class FilePath
|
|
489
516
|
end
|
490
517
|
end
|
491
518
|
|
492
|
-
module
|
519
|
+
module DirectoryMethods
|
493
520
|
def entries(pattern = '*')
|
494
521
|
if !self.directory?
|
495
522
|
raise Errno::ENOTDIR.new(self.to_s)
|
@@ -518,7 +545,7 @@ class FilePath
|
|
518
545
|
include PathResolution
|
519
546
|
include FileInfo
|
520
547
|
include FileManipulationMethods
|
521
|
-
include
|
548
|
+
include DirectoryMethods
|
522
549
|
end
|
523
550
|
|
524
551
|
class String
|
data/spec/filepath_spec.rb
CHANGED
@@ -81,12 +81,15 @@ describe FilePath do
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
describe "#relative_to
|
84
|
+
describe "#relative_to" do
|
85
85
|
test_data = [
|
86
86
|
['/a/b/c', '/a/b', 'c'],
|
87
87
|
['/a/b/c', '/a/d', '../b/c'],
|
88
88
|
['/a/b/c', '/a/b/c/d', '..'],
|
89
89
|
['/a/b/c', '/a/b/c', '.'],
|
90
|
+
['a/d', 'a/b/c', '../../d'],
|
91
|
+
['a/e/f', 'a/b/c/d', '../../../e/f'],
|
92
|
+
['a/c', 'a/b/..', 'c'],
|
90
93
|
]
|
91
94
|
test_data.each do |path, base, result|
|
92
95
|
it "says that `#{path}` relative to `#{base}` is `#{result}`" do
|
@@ -109,6 +112,22 @@ describe FilePath do
|
|
109
112
|
end
|
110
113
|
end
|
111
114
|
|
115
|
+
describe "#relative_to_file" do
|
116
|
+
test_data = [
|
117
|
+
['/a/b/c', '/a/d', 'b/c'],
|
118
|
+
['/a/b/c', '/a/b/c/d', '.'],
|
119
|
+
['/a/b/c', '/a/b/c', 'c'],
|
120
|
+
['a/d', 'a/b/c', '../d'],
|
121
|
+
['a/e/f', 'a/b/c/d', '../../e/f'],
|
122
|
+
]
|
123
|
+
test_data.each do |path, base, result|
|
124
|
+
it "says that `#{path}` relative to the file `#{base}` is `#{result}`" do
|
125
|
+
p = FilePath.new(path)
|
126
|
+
p.relative_to_file(base).should == result
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
112
131
|
describe "#replace_filename" do
|
113
132
|
test_data = [
|
114
133
|
['foo/bar', 'quux', 'foo/quux'],
|
@@ -220,6 +239,10 @@ describe FilePath do
|
|
220
239
|
it "matches `/foo/bar` with /o\\/ba" do
|
221
240
|
FilePath.new('/foo/bar').should =~ /o\/b/
|
222
241
|
end
|
242
|
+
|
243
|
+
it "matches `/foo/bar/../quux` with /foo\\/quux/" do
|
244
|
+
FilePath.new('/foo/bar/../quux').should =~ /foo\/quux/
|
245
|
+
end
|
223
246
|
end
|
224
247
|
|
225
248
|
describe "#absolute?" do
|
@@ -232,6 +255,26 @@ describe FilePath do
|
|
232
255
|
end
|
233
256
|
end
|
234
257
|
|
258
|
+
describe "#normalized" do
|
259
|
+
test_data = [
|
260
|
+
['a', 'a'],
|
261
|
+
['a/b/c', 'a/b/c'],
|
262
|
+
['a/../c', 'c'],
|
263
|
+
['a/b/..', 'a'],
|
264
|
+
['../a', '../a'],
|
265
|
+
['../../a', '../../a'],
|
266
|
+
['../a/..', '..'],
|
267
|
+
['/', '/'],
|
268
|
+
['/..', '/'],
|
269
|
+
['/../../../a', '/a'],
|
270
|
+
]
|
271
|
+
test_data.each do |path, result|
|
272
|
+
it "turns `#{path}` into `#{result}`" do
|
273
|
+
FilePath.new(path).normalized.to_raw_string.should == result
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
235
278
|
describe "#ascend" do
|
236
279
|
it "goes through all the fragments of an absolute path" do
|
237
280
|
steps = []
|
@@ -300,6 +343,12 @@ describe FilePath do
|
|
300
343
|
end
|
301
344
|
end
|
302
345
|
|
346
|
+
describe "#as_path" do
|
347
|
+
it "returns the path itself" do
|
348
|
+
@root.as_path.should be(@root)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
303
352
|
describe "#==(String)" do
|
304
353
|
test_data = [
|
305
354
|
['./', '.'],
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filepath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.2'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bones-rspec
|
16
|
+
requirement: &15445240 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.0.1
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *15445240
|
14
25
|
- !ruby/object:Gem::Dependency
|
15
26
|
name: bones
|
16
|
-
requirement: &
|
27
|
+
requirement: &15444620 !ruby/object:Gem::Requirement
|
17
28
|
none: false
|
18
29
|
requirements:
|
19
30
|
- - ! '>='
|
@@ -21,11 +32,11 @@ dependencies:
|
|
21
32
|
version: 3.7.3
|
22
33
|
type: :development
|
23
34
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
-
description: ! '
|
26
|
-
|
35
|
+
version_requirements: *15444620
|
36
|
+
description: ! 'filepath is a small library that helps dealing with files, directories
|
37
|
+
and
|
27
38
|
|
28
|
-
general; a modern replacement for the standard Pathname.'
|
39
|
+
paths in general; a modern replacement for the standard Pathname.'
|
29
40
|
email: gioele@svario.it
|
30
41
|
executables: []
|
31
42
|
extensions: []
|
@@ -67,6 +78,6 @@ rubyforge_project: filepath
|
|
67
78
|
rubygems_version: 1.8.12
|
68
79
|
signing_key:
|
69
80
|
specification_version: 3
|
70
|
-
summary:
|
71
|
-
in general; a modern replacement for the standard Pathname.
|
81
|
+
summary: filepath is a small library that helps dealing with files, directories and
|
82
|
+
paths in general; a modern replacement for the standard Pathname.
|
72
83
|
test_files: []
|