pathname3 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +45 -0
- data/LICENSE +22 -0
- data/README +62 -0
- data/lib/pathname3.rb +573 -0
- data/pathname3.gemspec +31 -0
- data/test/lib/test_pathname.rb +486 -0
- data/test/lib/test_pathname3.rb +377 -0
- metadata +61 -0
@@ -0,0 +1,377 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'pathname3'
|
5
|
+
|
6
|
+
require 'fileutils'
|
7
|
+
require 'tmpdir'
|
8
|
+
require 'enumerator'
|
9
|
+
|
10
|
+
class TestPathname < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def self.define_assertion(name, &block)
|
13
|
+
@defassert_num ||= {}
|
14
|
+
@defassert_num[name] ||= 0
|
15
|
+
@defassert_num[name] += 1
|
16
|
+
define_method("test_#{name}_#{@defassert_num[name]}", &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.defassert(name, result, *args)
|
20
|
+
define_assertion(name) {
|
21
|
+
assert_equal(result, self.send(name, *args), "#{name}(#{args.map {|a| a.inspect }.join(', ')})")
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
DOSISH = File::ALT_SEPARATOR != nil
|
26
|
+
DOSISH_DRIVE_LETTER = File.dirname("A:") == "A:."
|
27
|
+
DOSISH_UNC = File.dirname("//") == "//"
|
28
|
+
|
29
|
+
def cleanpath_aggressive(path)
|
30
|
+
Pathname.new(path).cleanpath.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
defassert(:cleanpath_aggressive, '/', '/')
|
34
|
+
defassert(:cleanpath_aggressive, '.', '')
|
35
|
+
defassert(:cleanpath_aggressive, '.', '.')
|
36
|
+
defassert(:cleanpath_aggressive, '..', '..')
|
37
|
+
defassert(:cleanpath_aggressive, 'a', 'a')
|
38
|
+
defassert(:cleanpath_aggressive, '/', '/.')
|
39
|
+
defassert(:cleanpath_aggressive, '/', '/..')
|
40
|
+
defassert(:cleanpath_aggressive, '/a', '/a')
|
41
|
+
defassert(:cleanpath_aggressive, '.', './')
|
42
|
+
defassert(:cleanpath_aggressive, '..', '../')
|
43
|
+
defassert(:cleanpath_aggressive, 'a', 'a/')
|
44
|
+
defassert(:cleanpath_aggressive, 'a/b', 'a//b')
|
45
|
+
defassert(:cleanpath_aggressive, 'a', 'a/.')
|
46
|
+
defassert(:cleanpath_aggressive, 'a', 'a/./')
|
47
|
+
defassert(:cleanpath_aggressive, '.', 'a/..')
|
48
|
+
defassert(:cleanpath_aggressive, '.', 'a/../')
|
49
|
+
defassert(:cleanpath_aggressive, '/a', '/a/.')
|
50
|
+
defassert(:cleanpath_aggressive, '..', './..')
|
51
|
+
defassert(:cleanpath_aggressive, '..', '../.')
|
52
|
+
defassert(:cleanpath_aggressive, '..', './../')
|
53
|
+
defassert(:cleanpath_aggressive, '..', '.././')
|
54
|
+
defassert(:cleanpath_aggressive, '/', '/./..')
|
55
|
+
defassert(:cleanpath_aggressive, '/', '/../.')
|
56
|
+
defassert(:cleanpath_aggressive, '/', '/./../')
|
57
|
+
defassert(:cleanpath_aggressive, '/', '/.././')
|
58
|
+
defassert(:cleanpath_aggressive, 'a/b/c', 'a/b/c')
|
59
|
+
defassert(:cleanpath_aggressive, 'b/c', './b/c')
|
60
|
+
defassert(:cleanpath_aggressive, 'a/c', 'a/./c')
|
61
|
+
defassert(:cleanpath_aggressive, 'a/b', 'a/b/.')
|
62
|
+
defassert(:cleanpath_aggressive, '.', 'a/../.')
|
63
|
+
defassert(:cleanpath_aggressive, '/a', '/../.././../a')
|
64
|
+
defassert(:cleanpath_aggressive, '../../d', 'a/b/../../../../c/../d')
|
65
|
+
|
66
|
+
if DOSISH_UNC
|
67
|
+
defassert(:cleanpath_aggressive, '//a/b/c', '//a/b/c/')
|
68
|
+
else
|
69
|
+
defassert(:cleanpath_aggressive, '/', '///')
|
70
|
+
defassert(:cleanpath_aggressive, '/a', '///a')
|
71
|
+
defassert(:cleanpath_aggressive, '/', '///..')
|
72
|
+
defassert(:cleanpath_aggressive, '/', '///.')
|
73
|
+
defassert(:cleanpath_aggressive, '/', '///a/../..')
|
74
|
+
end
|
75
|
+
|
76
|
+
def plus(path1, path2) # -> path
|
77
|
+
(Pathname.new(path1) + Pathname.new(path2)).to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
defassert(:plus, '/', '/', '/')
|
81
|
+
defassert(:plus, 'a/b', 'a', 'b')
|
82
|
+
defassert(:plus, 'a', 'a', '.')
|
83
|
+
defassert(:plus, 'b', '.', 'b')
|
84
|
+
defassert(:plus, '.', '.', '.')
|
85
|
+
defassert(:plus, 'a/b', 'a', '/b')
|
86
|
+
|
87
|
+
defassert(:plus, '/', '/', '..')
|
88
|
+
defassert(:plus, '.', 'a', '..')
|
89
|
+
defassert(:plus, 'a', 'a/b', '..')
|
90
|
+
defassert(:plus, '../..', '..', '..')
|
91
|
+
defassert(:plus, '/c', '/', '../c')
|
92
|
+
defassert(:plus, 'c', 'a', '../c')
|
93
|
+
defassert(:plus, 'a/c', 'a/b', '../c')
|
94
|
+
defassert(:plus, '../../c', '..', '../c')
|
95
|
+
|
96
|
+
defassert(:plus, 'a/b/d/e', 'a//b/c', '../d//e')
|
97
|
+
|
98
|
+
def relative?(path)
|
99
|
+
Pathname.new(path).relative?
|
100
|
+
end
|
101
|
+
|
102
|
+
defassert(:relative?, false, '/')
|
103
|
+
defassert(:relative?, false, '/a')
|
104
|
+
defassert(:relative?, false, '/..')
|
105
|
+
defassert(:relative?, true, 'a')
|
106
|
+
defassert(:relative?, true, 'a/b')
|
107
|
+
|
108
|
+
if DOSISH_DRIVE_LETTER
|
109
|
+
defassert(:relative?, false, 'A:')
|
110
|
+
defassert(:relative?, false, 'A:/')
|
111
|
+
defassert(:relative?, false, 'A:/a')
|
112
|
+
end
|
113
|
+
|
114
|
+
if File.dirname('//') == '//'
|
115
|
+
defassert(:relative?, false, '//')
|
116
|
+
defassert(:relative?, false, '//a')
|
117
|
+
defassert(:relative?, false, '//a/')
|
118
|
+
defassert(:relative?, false, '//a/b')
|
119
|
+
defassert(:relative?, false, '//a/b/')
|
120
|
+
defassert(:relative?, false, '//a/b/c')
|
121
|
+
end
|
122
|
+
|
123
|
+
def relative_path_from(dest_directory, base_directory)
|
124
|
+
Pathname.new(dest_directory).relative_path_from(Pathname.new(base_directory)).to_s
|
125
|
+
end
|
126
|
+
|
127
|
+
defassert(:relative_path_from, "../a", "a", "b")
|
128
|
+
defassert(:relative_path_from, "../a", "a", "b/")
|
129
|
+
defassert(:relative_path_from, "../a", "a/", "b")
|
130
|
+
defassert(:relative_path_from, "../a", "a/", "b/")
|
131
|
+
defassert(:relative_path_from, "../a", "/a", "/b")
|
132
|
+
defassert(:relative_path_from, "../a", "/a", "/b/")
|
133
|
+
defassert(:relative_path_from, "../a", "/a/", "/b")
|
134
|
+
defassert(:relative_path_from, "../a", "/a/", "/b/")
|
135
|
+
|
136
|
+
defassert(:relative_path_from, "../b", "a/b", "a/c")
|
137
|
+
defassert(:relative_path_from, "../a", "../a", "../b")
|
138
|
+
|
139
|
+
defassert(:relative_path_from, "a", "a", ".")
|
140
|
+
defassert(:relative_path_from, "..", ".", "a")
|
141
|
+
|
142
|
+
defassert(:relative_path_from, ".", ".", ".")
|
143
|
+
defassert(:relative_path_from, ".", "..", "..")
|
144
|
+
defassert(:relative_path_from, "..", "..", ".")
|
145
|
+
|
146
|
+
defassert(:relative_path_from, "c/d", "/a/b/c/d", "/a/b")
|
147
|
+
defassert(:relative_path_from, "../..", "/a/b", "/a/b/c/d")
|
148
|
+
defassert(:relative_path_from, "../../../../e", "/e", "/a/b/c/d")
|
149
|
+
defassert(:relative_path_from, "../b/c", "a/b/c", "a/d")
|
150
|
+
|
151
|
+
defassert(:relative_path_from, "../a", "/../a", "/b")
|
152
|
+
defassert(:relative_path_from, "../../a", "../a", "b")
|
153
|
+
defassert(:relative_path_from, ".", "/a/../../b", "/b")
|
154
|
+
defassert(:relative_path_from, "..", "a/..", "a")
|
155
|
+
defassert(:relative_path_from, ".", "a/../b", "b")
|
156
|
+
|
157
|
+
defassert(:relative_path_from, "a", "a", "b/..")
|
158
|
+
defassert(:relative_path_from, "b/c", "b/c", "b/..")
|
159
|
+
|
160
|
+
def self.defassert_raise(name, exc, *args)
|
161
|
+
define_assertion(name) {
|
162
|
+
message = "#{name}(#{args.map {|a| a.inspect }.join(', ')})"
|
163
|
+
assert_raise(exc, message) { self.send(name, *args) }
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
defassert_raise(:relative_path_from, ArgumentError, "/", ".")
|
168
|
+
defassert_raise(:relative_path_from, ArgumentError, ".", "/")
|
169
|
+
defassert_raise(:relative_path_from, ArgumentError, "a", "..")
|
170
|
+
defassert_raise(:relative_path_from, ArgumentError, ".", "..")
|
171
|
+
|
172
|
+
def realpath(path)
|
173
|
+
Pathname.new(path).realpath.to_s
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_realpath
|
177
|
+
begin
|
178
|
+
File.symlink(nil, nil)
|
179
|
+
rescue NotImplementedError
|
180
|
+
return
|
181
|
+
rescue TypeError
|
182
|
+
end
|
183
|
+
dir = "#{Dir.tmpdir}/tst-pathname-#$$"
|
184
|
+
Dir.mkdir(dir)
|
185
|
+
begin
|
186
|
+
File.symlink("not-exist-target", "#{dir}/not-exist")
|
187
|
+
assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist") }
|
188
|
+
File.symlink("loop", "#{dir}/loop")
|
189
|
+
assert_raise(Errno::ELOOP) { realpath("#{dir}/loop") }
|
190
|
+
ensure
|
191
|
+
FileUtils.rmtree(dir)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def descend(path)
|
196
|
+
Pathname.new(path).enum_for(:descend).map {|v| v.to_s }
|
197
|
+
end
|
198
|
+
|
199
|
+
defassert(:descend, %w[/ /a /a/b /a/b/c], "/a/b/c")
|
200
|
+
defassert(:descend, %w[a a/b a/b/c], "a/b/c")
|
201
|
+
defassert(:descend, %w[. ./a ./a/b ./a/b/c], "./a/b/c")
|
202
|
+
defassert(:descend, %w[a], "a/")
|
203
|
+
|
204
|
+
def ascend(path)
|
205
|
+
Pathname.new(path).enum_for(:ascend).map {|v| v.to_s }
|
206
|
+
end
|
207
|
+
|
208
|
+
defassert(:ascend, %w[/a/b/c /a/b /a /], "/a/b/c")
|
209
|
+
defassert(:ascend, %w[a/b/c a/b a], "a/b/c")
|
210
|
+
defassert(:ascend, %w[./a/b/c ./a/b ./a .], "./a/b/c")
|
211
|
+
defassert(:ascend, %w[a], "a/")
|
212
|
+
|
213
|
+
def test_initialize
|
214
|
+
p1 = Pathname.new('a')
|
215
|
+
assert_equal('a', p1.to_s)
|
216
|
+
p2 = Pathname.new(p1)
|
217
|
+
assert_equal(p1, p2)
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_initialize_nul
|
221
|
+
assert_raise(ArgumentError) { Pathname.new("a\0") }
|
222
|
+
end
|
223
|
+
|
224
|
+
class AnotherStringLike # :nodoc:
|
225
|
+
def initialize(s) @s = s end
|
226
|
+
def to_str() @s end
|
227
|
+
def ==(other) @s == other end
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_equality
|
231
|
+
obj = Pathname.new("a")
|
232
|
+
str = "a"
|
233
|
+
sym = :a
|
234
|
+
ano = AnotherStringLike.new("a")
|
235
|
+
assert_equal(true, obj == str)
|
236
|
+
assert_equal(true, str == obj)
|
237
|
+
assert_equal(true, obj == ano)
|
238
|
+
assert_equal(true, ano == obj)
|
239
|
+
assert_equal(false, obj == sym)
|
240
|
+
assert_equal(false, sym == obj)
|
241
|
+
|
242
|
+
obj2 = Pathname.new("a")
|
243
|
+
assert_equal(true, obj == obj2)
|
244
|
+
assert_equal(true, obj === obj2)
|
245
|
+
assert_equal(true, obj.eql?(obj2))
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_hashkey
|
249
|
+
h = {}
|
250
|
+
h[Pathname.new("a")] = 1
|
251
|
+
h[Pathname.new("a")] = 2
|
252
|
+
assert_equal(1, h.size)
|
253
|
+
end
|
254
|
+
|
255
|
+
def assert_pathname_cmp(e, s1, s2)
|
256
|
+
p1 = Pathname.new(s1)
|
257
|
+
p2 = Pathname.new(s2)
|
258
|
+
r = p1 <=> p2
|
259
|
+
assert(e == r,
|
260
|
+
"#{p1.inspect} <=> #{p2.inspect}: <#{e}> expected but was <#{r}>")
|
261
|
+
end
|
262
|
+
def test_comparison
|
263
|
+
assert_pathname_cmp( 0, "a", "a")
|
264
|
+
assert_pathname_cmp( 1, "b", "a")
|
265
|
+
assert_pathname_cmp(-1, "a", "b")
|
266
|
+
ss = %w(
|
267
|
+
a
|
268
|
+
a/
|
269
|
+
a/b
|
270
|
+
a.
|
271
|
+
a0
|
272
|
+
)
|
273
|
+
s1 = ss.shift
|
274
|
+
ss.each {|s2|
|
275
|
+
assert_pathname_cmp(-1, s1, s2)
|
276
|
+
s1 = s2
|
277
|
+
}
|
278
|
+
end
|
279
|
+
|
280
|
+
def pathsub(path, pat, repl) Pathname.new(path).sub(pat, repl).to_s end
|
281
|
+
defassert(:pathsub, "a.o", "a.c", /\.c\z/, ".o")
|
282
|
+
|
283
|
+
def root?(path)
|
284
|
+
Pathname.new(path).root?
|
285
|
+
end
|
286
|
+
|
287
|
+
defassert(:root?, true, "/")
|
288
|
+
defassert(:root?, true, "//")
|
289
|
+
defassert(:root?, true, "///")
|
290
|
+
defassert(:root?, false, "")
|
291
|
+
defassert(:root?, false, "a")
|
292
|
+
|
293
|
+
def test_destructive_update
|
294
|
+
path = Pathname.new("a")
|
295
|
+
path.to_s.replace "b"
|
296
|
+
assert_equal(Pathname.new("a"), path)
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_null_character
|
300
|
+
assert_raise(ArgumentError) { Pathname.new("\0") }
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_taint
|
304
|
+
obj = Pathname.new("a"); assert_same(obj, obj.taint)
|
305
|
+
obj = Pathname.new("a"); assert_same(obj, obj.untaint)
|
306
|
+
|
307
|
+
assert_equal(false, Pathname.new("a" ) .tainted?)
|
308
|
+
assert_equal(false, Pathname.new("a" ) .to_s.tainted?)
|
309
|
+
assert_equal(true, Pathname.new("a" ).taint .tainted?)
|
310
|
+
assert_equal(true, Pathname.new("a" ).taint.to_s.tainted?)
|
311
|
+
assert_equal(true, Pathname.new("a".taint) .tainted?)
|
312
|
+
assert_equal(true, Pathname.new("a".taint) .to_s.tainted?)
|
313
|
+
assert_equal(true, Pathname.new("a".taint).taint .tainted?)
|
314
|
+
assert_equal(true, Pathname.new("a".taint).taint.to_s.tainted?)
|
315
|
+
|
316
|
+
str = "a"
|
317
|
+
path = Pathname.new(str)
|
318
|
+
str.taint
|
319
|
+
assert_equal(false, path .tainted?)
|
320
|
+
assert_equal(false, path.to_s.tainted?)
|
321
|
+
end
|
322
|
+
|
323
|
+
def test_untaint
|
324
|
+
obj = Pathname.new("a"); assert_same(obj, obj.untaint)
|
325
|
+
|
326
|
+
assert_equal(false, Pathname.new("a").taint.untaint .tainted?)
|
327
|
+
assert_equal(false, Pathname.new("a").taint.untaint.to_s.tainted?)
|
328
|
+
|
329
|
+
str = "a".taint
|
330
|
+
path = Pathname.new(str)
|
331
|
+
str.untaint
|
332
|
+
assert_equal(true, path .tainted?)
|
333
|
+
assert_equal(true, path.to_s.tainted?)
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_freeze
|
337
|
+
obj = Pathname.new("a"); assert_same(obj, obj.freeze)
|
338
|
+
|
339
|
+
assert_equal(false, Pathname.new("a" ) .frozen?)
|
340
|
+
assert_equal(false, Pathname.new("a".freeze) .frozen?)
|
341
|
+
assert_equal(true, Pathname.new("a" ).freeze .frozen?)
|
342
|
+
assert_equal(true, Pathname.new("a".freeze).freeze .frozen?)
|
343
|
+
assert_equal(false, Pathname.new("a" ) .to_s.frozen?)
|
344
|
+
assert_equal(false, Pathname.new("a".freeze) .to_s.frozen?)
|
345
|
+
assert_equal(false, Pathname.new("a" ).freeze.to_s.frozen?)
|
346
|
+
assert_equal(false, Pathname.new("a".freeze).freeze.to_s.frozen?)
|
347
|
+
end
|
348
|
+
|
349
|
+
def test_to_s
|
350
|
+
str = "a"
|
351
|
+
obj = Pathname.new(str)
|
352
|
+
assert_equal(str, obj.to_s)
|
353
|
+
assert_not_same(str, obj.to_s)
|
354
|
+
assert_not_same(obj.to_s, obj.to_s)
|
355
|
+
end
|
356
|
+
|
357
|
+
def test_kernel_open
|
358
|
+
count = 0
|
359
|
+
result = Kernel.open(Pathname.new(__FILE__)) {|f|
|
360
|
+
assert(File.identical?(__FILE__, f))
|
361
|
+
count += 1
|
362
|
+
2
|
363
|
+
}
|
364
|
+
assert_equal(1, count)
|
365
|
+
assert_equal(2, result)
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_each_filename
|
369
|
+
result = []
|
370
|
+
Pathname.new("/usr/bin/ruby").each_filename {|f| result << f }
|
371
|
+
assert_equal(%w[/ usr bin ruby], result)
|
372
|
+
end
|
373
|
+
|
374
|
+
def test_kernel_pathname
|
375
|
+
assert_equal(Pathname.new("a"), Pathname("a"))
|
376
|
+
end
|
377
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pathname3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen Touset
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-17 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Faster replacement for pathname and pathname2
|
17
|
+
email: stephen@touset.org
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- CHANGES
|
26
|
+
- README
|
27
|
+
- LICENSE
|
28
|
+
- pathname3.gemspec
|
29
|
+
- lib/pathname3.rb
|
30
|
+
- test/lib/test_pathname.rb
|
31
|
+
- test/lib/test_pathname3.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/stouset/pathname3/
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.5
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: pathname3 is a third attempt at rewriting the eminently useful Pathname library in Ruby. The first version (packaged with Ruby) is extremely slow for many operations, as is the second one (by Daniel J. Berger). This version attempts to combine the best parts of both predecessors, while also maintaining speed. Namely, we use Daniel's String-based approach, while dumping Facade and sending messages to FileTest, File, Dir, and FileUtils explicitly (for clarity and predictability). Windows support will be provided in a later release. Donations of code toward this end would be appreciated.
|
60
|
+
test_files: []
|
61
|
+
|