stouset-pathname3 1.2.3

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