quality_extensions 1.1.4 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/lib/Xfind_bug_test.rb +28 -0
  2. data/lib/quality_extensions/array/all_same.rb +40 -0
  3. data/lib/quality_extensions/array/delete_if_bang.rb +145 -0
  4. data/lib/quality_extensions/array/expand_ranges.rb +3 -53
  5. data/lib/quality_extensions/array/include_any_of.rb +23 -0
  6. data/lib/quality_extensions/array/justify.rb +305 -0
  7. data/lib/quality_extensions/array/{average.rb → mean.rb} +1 -1
  8. data/lib/quality_extensions/array/select_if_bang.rb +0 -0
  9. data/lib/quality_extensions/array/sum.rb +30 -0
  10. data/lib/quality_extensions/enumerable/all_same.rb +43 -0
  11. data/lib/quality_extensions/enumerable/group_by_and_map.rb +110 -0
  12. data/lib/quality_extensions/enumerable/select_bang.rb +49 -0
  13. data/lib/quality_extensions/enumerable/select_while.rb +337 -52
  14. data/lib/quality_extensions/enumerable/select_with_index.rb +145 -0
  15. data/lib/quality_extensions/hash/hash_select.rb +5 -2
  16. data/lib/quality_extensions/hash/merge_if.rb +48 -0
  17. data/lib/quality_extensions/kernel/example_printer.rb +10 -3
  18. data/lib/quality_extensions/kernel/require_all.rb +24 -8
  19. data/lib/quality_extensions/kernel/sleep_loudly.rb +108 -0
  20. data/lib/quality_extensions/kernel/uninterruptable.rb +22 -0
  21. data/lib/quality_extensions/matrix/indexable.rb +68 -0
  22. data/lib/quality_extensions/matrix/linked_vectors.rb +137 -0
  23. data/lib/quality_extensions/module/class_methods.rb +2 -0
  24. data/lib/quality_extensions/object/non.rb +12 -0
  25. data/lib/quality_extensions/pathname.rb +435 -7
  26. data/lib/quality_extensions/range_list.rb +222 -0
  27. data/lib/quality_extensions/safe_nil.rb +5 -3
  28. data/lib/quality_extensions/string/each_char_with_index.rb +1 -2
  29. data/lib/quality_extensions/string/integer_eh.rb +3 -0
  30. data/lib/quality_extensions/string/numeric_eh.rb +74 -0
  31. data/lib/quality_extensions/string/safe_in_comment.rb +38 -0
  32. data/lib/quality_extensions/string/safe_numeric_conversion.rb +102 -0
  33. data/lib/quality_extensions/string/shell_escape.rb +4 -4
  34. data/lib/quality_extensions/string/with_knowledge_of_color.rb +8 -0
  35. data/lib/quality_extensions/table.rb +116 -0
  36. data/lib/quality_extensions/template.rb +4 -5
  37. data/lib/quality_extensions/template.rb_test_unit.rb +33 -0
  38. data/lib/quality_extensions/test/difference_highlighting-minitest.rb +321 -0
  39. data/lib/quality_extensions/test/difference_highlighting-test_unit.rb +325 -0
  40. data/lib/quality_extensions/test/difference_highlighting.rb +6 -314
  41. data/lib/quality_extensions/timeout/countdown_timer.rb +1 -0
  42. data/lib/quality_extensions/vector/enumerable.rb +51 -0
  43. metadata +35 -5
@@ -4,10 +4,20 @@
4
4
  # Copyright:: Copyright (c) 2009, Tyler Rick
5
5
  # License:: Ruby License
6
6
  # Submit to Facets?::
7
- # Developer notes:: Make a patch to actual pathname source.
8
- # Changes::
7
+ # Developer notes::
8
+ # * Make a patch to actual pathname source.
9
+ # * document all Pathname methods better, copying from docs for delegated class if necessary, but NOT just saying 'See FileTest.file?.' How useless that is to have to keep flipping back and forth referring to like 4 different classes!
10
+ # History::
11
+ # * Renamed parts to split_all to be the same as Facets' File.split_all
12
+ # To do:
13
+ # path.basename.capitalize doesn't work
14
+ # workaround:
15
+ # path = Pathname.new(path.basename.to_s.capitalize)
16
+ # better:
17
+ # path.basename.change_basename {|basename| basename.capitalize} ?
9
18
  #++
10
19
 
20
+
11
21
  require 'pathname'
12
22
  require 'tempfile'
13
23
 
@@ -17,6 +27,39 @@ class Pathname
17
27
  Pathname.new(Tempfile.new('Pathname').path)
18
28
  end
19
29
 
30
+ # Pathname.new(Dir.getwd)
31
+ #
32
+ # Name ideas: cwd
33
+ def self.getwd
34
+ Pathname.new(Dir.getwd)
35
+ end
36
+
37
+ # Returns a Pathname object representing the absolute path equivalent to self.
38
+ #
39
+ # If self is already absolute, returns self. Otherwise, prepends Pathname.getwd (in other words, creates an absolute path relative to the current working directory.)
40
+ #
41
+ # Pathname.new('.').absolutize == Pathname.getwd # => true
42
+ #
43
+ def absolutize
44
+ if absolute?
45
+ self
46
+ else
47
+ (Pathname.getwd + self).cleanpath
48
+ end
49
+ end
50
+
51
+ # Same as FileUtils.touch
52
+ #
53
+ # Options: noop verbose
54
+ #
55
+ # Updates modification time (mtime) and access time (atime) of file(s) in list. Files are created if they don’t exist.
56
+ #
57
+ # FileUtils.touch 'timestamp'
58
+ # FileUtils.touch Dir.glob('*.c'); system 'make'
59
+ def touch
60
+ FileUtils.touch self.to_s
61
+ end
62
+
20
63
  # Moves self to +new_path+ using FileUtils.mv.
21
64
  #
22
65
  # See documentation for FileUtils.mv for a list of valid +options+.
@@ -29,18 +72,30 @@ class Pathname
29
72
  end
30
73
  alias_method :move, :mv
31
74
 
32
- # Copies self to +new_path+ using FileUtils.cp.
75
+ # Copies self to +dest+ using FileUtils.cp.
33
76
  #
34
77
  # See documentation for FileUtils.cp for a list of valid +options+.
35
78
  #
36
- # Returns Pathname object for +new_file+ file.
79
+ # Returns Pathname object for +dest+ file.
37
80
  #
38
- def cp(new_path, options = {})
39
- FileUtils.cp self.to_s, new_path.to_s, options
40
- Pathname.new(new_path)
81
+ def cp(dest, options = {})
82
+ FileUtils.cp self.to_s, dest.to_s, options
83
+ Pathname.new(dest)
41
84
  end
42
85
  alias_method :copy, :cp
43
86
 
87
+ # Copies self to +dest+ using FileUtils.cp_r. If self is a directory, this method copies all its contents recursively. If +dest+ is a directory, copies self to +dest/src+.
88
+ #
89
+ # See documentation for FileUtils.cp_r for a list of valid +options+.
90
+ #
91
+ # Returns Pathname object for +dest+ file.
92
+ #
93
+ def cp_r(dest, options = {})
94
+ FileUtils.cp_r self.to_s, dest.to_s, options
95
+ Pathname.new(dest)
96
+ end
97
+ alias_method :copy_recursive, :cp_r
98
+
44
99
 
45
100
  # Copies/install self to +dest+ using FileUtils.install.
46
101
  #
@@ -55,6 +110,146 @@ class Pathname
55
110
  FileUtils.install self.to_s, dest.to_s, options
56
111
  Pathname.new(dest)
57
112
  end
113
+
114
+
115
+ # This is needed since <#Pathname> + <#String> treats both self and the string as a *directory* to be joined instead of simply treating them as parts of a basename/filename to join together.
116
+ #
117
+ # Pathname.new('/tmp/some_file') + '.suffix'
118
+ # => Pathname.new('/tmp/some_file/.suffix')
119
+ #
120
+ # Pathname.new('/tmp/some_file').add_suffix('.suffix')
121
+ # => Pathname.new('/tmp/some_file.suffix')
122
+ #
123
+ # Pathname.new('/tmp/some_file/').add_suffix('.suffix')
124
+ # => Pathname.new('/tmp/some_file.suffix')
125
+ #
126
+ def add_suffix(s)
127
+ Pathname.new(cleanpath.to_s + s)
128
+ end
129
+
130
+ def add_prefix(s)
131
+ Pathname.new((dirname + s).to_s + basename.to_s)
132
+ end
133
+
134
+ # Better name? Would 'dirs' be better? 'parents'?
135
+ #
136
+ # Similar to split, but instead of only returning two parts ([dirname, basename]), returns an element for *each* directory/basename represented in the path.
137
+ #
138
+ # Similar to PHP's pathinfo()['parts']?
139
+ #
140
+ def split_all
141
+ # Boundary condition for paths like '/usr' (['/', 'usr'] will be the result)
142
+ if self.to_s == '/'
143
+ [self]
144
+ # Boundary condition for paths like 'usr' (we only want ['usr'], not ['.', 'usr'])
145
+ elsif self.to_s == '.'
146
+ []
147
+ else
148
+ parent.split_all + [self]
149
+ end
150
+ end
151
+
152
+ # Returns all path parts except the last (the last part being the basename).
153
+ #
154
+ # When there is only one part (as is the case, f.e., with Pathname('/') or Pathname('file')), it returns an empty array (rather than Pathname('/') or Pathname('.')).
155
+ #
156
+ # Similar to split, but instead of only returning two parts ([dirname, basename]), returns an element for *each* directory represented in the path.
157
+ #
158
+ def split_all_without_basename
159
+ parents = split_all.dup
160
+ parents.pop
161
+ parents
162
+ end
163
+
164
+ # Returns an array of all path parts that are directories. (If +self.directory?+, self is included too, unless +include_self+ is false.)
165
+ #
166
+ # This is similar to parts_without_basename except unlike parts_without_basename, which removes the last path ('basename') part no matter what, parent_dirs actually checks if the last path part is a *directory* and only removes it if it is not.
167
+ #
168
+ # absolutize is called to force it to be an absolute path; so this method will not behave as advertized if the path is invalid or if the current working directory isn't correct when the path is absolutized...
169
+ #
170
+ # parent_dirs is not useful when used with fictional paths. It actually calls #directory? on the last path part, so the path must actually exist for this method to work as advertised.
171
+ # (You would might be advised to check #exist? before calling this method.)
172
+ # If you are confident that self is a directory, then you might want to use parts_without_basename.
173
+ #
174
+ # Name ideas: parents, ancestors (but since it also includes self by default, I thought emphasizing *dirs* would be less misleading.)
175
+ #
176
+ def parent_dirs(include_self = true)
177
+ parents = absolutize.split_all.dup
178
+ parents.pop if parents.any? && !(parents.last.directory? && include_self)
179
+ parents
180
+ end
181
+
182
+ # Better name? Would 'dirs' be better?
183
+ #
184
+ # Similar to split, but instead of only returning two parts ([dirname, basename]), returns an element for *each* directory represented in the path.
185
+ #
186
+ # Pathname.new('dir1/dir2/base').parts_s
187
+ # # => ['dir1', 'dir2', 'base']
188
+ #
189
+ # Pathname.new('dir1/dir2/base').parts_s.first
190
+ # # => 'dir1'
191
+ #
192
+ # Pathname.new('/dir1/dir2/base').parts_s
193
+ # # => ['/', 'dir1', 'dir2', 'base']
194
+ #
195
+ # Unlike split_all, this returns an array of *strings* rather than an array of Pathnames.
196
+ #
197
+ # Similar to PHP's pathinfo()['parts']?
198
+ #
199
+ def split_all_s
200
+ a, b = split
201
+ a, b = a, b.to_s
202
+
203
+ # Boundary condition for paths like '/usr' (['/', 'usr'] will be the result)
204
+ if b == '/'
205
+ [b]
206
+ # Boundary condition for paths like 'usr' (we only want ['usr'], not ['.', 'usr'])
207
+ elsif b == '.'
208
+ []
209
+ else
210
+ a.split_all_s + [b]
211
+ end
212
+ end
213
+
214
+ # Traverses up the file system until a match is found that is described by +block+ (that is, until +block+ yields a true value).
215
+ #
216
+ # Yields each parent *directory* (including self if self.directory?) as a Pathname object, one at a time, until we get to root of the file system (absolutize is called to force it to be an absolute path) or the block indicates that it has found what it's looking for.
217
+ #
218
+ # find_ancestor will return as its return value the block's return value as soon as the block's return value evaluates to true (not nil or false). If no match is found, find_ancestor will return nil.
219
+ #
220
+ # Example:
221
+ # git_dir = Pathname.getwd.find_ancestor {|dir| path = dir + '.git'; path if path.exist? }
222
+ #
223
+ # Note that this is quite unlike Pathname#find which has access to prune, etc.
224
+ #
225
+ # Other name ideas: reverse_find, upfind, find_up_tree, find_first_ancestor
226
+ #
227
+ # def find_parent
228
+ # absolutize.parent_dirs.each do |part|
229
+ # ret = yield part
230
+ # return ret if ret
231
+ # end
232
+ # nil
233
+ # end
234
+
235
+ # Traverses up the file system until a match is found that is described by +block+ (that is, until +block+ yields a true value).
236
+ #
237
+ # Yields each parent *directory* (including self if self.directory?) as a Pathname object, one at a time, until we get to root of the file system (absolutize is called to force it to be an absolute path) or the block indicates that it has found what it's looking for.
238
+ #
239
+ # find_ancestor will return as its return value the block's return value as soon as the block's return value evaluates to true (not nil or false). If no match is found, find_ancestor will return nil.
240
+ #
241
+ # Examples:
242
+ # git_dir = Pathname.getwd.each_parent_dir {|dir| path = dir + '.git'; break path if path.exist? }
243
+ # git_dirs = []; Pathname.getwd.each_parent_dir {|dir| path = dir + '.git'; git_dirs << path if path.exist? }
244
+ #
245
+ # To do: deprecate, merge docs with parent_dirs?
246
+ def each_parent_dir
247
+ parent_dirs.reverse.each do |part|
248
+ ret = yield part
249
+ end
250
+ nil
251
+ end
252
+
58
253
  end
59
254
 
60
255
 
@@ -81,6 +276,23 @@ class TheTest < Test::Unit::TestCase
81
276
  new_file.unlink rescue nil
82
277
  end
83
278
 
279
+ def test_cwd
280
+ assert_equal Dir.getwd, Pathname.getwd.to_s
281
+ end
282
+
283
+ def test_absolutize
284
+ assert_equal Pathname.new('/some/already/absolute/path'), Pathname.new('/some/already/absolute/path').absolutize
285
+ assert_equal Pathname.getwd, Pathname.new('.').absolutize
286
+ end
287
+
288
+ def test_touch
289
+ new_file = Pathname.new('/tmp/sought')
290
+ new_file.unlink rescue nil
291
+ assert !new_file.exist?
292
+ new_file.touch
293
+ assert new_file.exist?
294
+ end
295
+
84
296
  def test_tempfile_actually_creates_file
85
297
  assert @object.exist?
86
298
  end
@@ -117,12 +329,228 @@ class TheTest < Test::Unit::TestCase
117
329
  assert_match %r(/tmp/Pathname), new_object.to_s
118
330
  end
119
331
 
332
+ def test_cp_r_actually_copies_file
333
+ new_object = @object.cp_r('/tmp/Pathname_new_file')
334
+ assert @object.exist?
335
+ assert new_object.exist?
336
+ assert_match %r(/tmp/Pathname), new_object.to_s
337
+ end
338
+
120
339
  def test_install_actually_copies_file
121
340
  new_object = @object.install('/tmp/Pathname_new_file')
122
341
  assert @object.exist?
123
342
  assert new_object.exist?
124
343
  assert_match %r(/tmp/Pathname), new_object.to_s
125
344
  end
345
+
346
+ def test_add_suffix
347
+ file = Pathname.new('/tmp/Pathname_new_file')
348
+ assert_equal Pathname.new('/tmp/Pathname_new_file/.suffix'), file + '.suffix'.to_s
349
+ assert_equal Pathname.new('/tmp/Pathname_new_file.suffix'), file.add_suffix('.suffix')
350
+
351
+ file = Pathname.new('/tmp/Pathname_new_file/')
352
+ assert_equal Pathname.new('/tmp/Pathname_new_file.suffix'), file.add_suffix('.suffix')
353
+ end
354
+
355
+ def test_add_prefix
356
+ file = Pathname.new('/tmp/Pathname_new_file')
357
+ assert_equal 'prefix-/tmp/Pathname_new_file', 'prefix-' + file.to_s
358
+ assert_equal Pathname.new('/tmp/prefix-Pathname_new_file'), file.add_prefix('prefix-')
359
+
360
+ file = Pathname.new('/tmp/Pathname_new_file/')
361
+ assert_equal Pathname.new('/tmp/prefix-Pathname_new_file'), file.add_prefix('prefix-')
362
+ end
363
+
364
+ def test_split_all
365
+ file = Pathname.new('/')
366
+ assert_equal [Pathname.new('/')], file.split_all
367
+
368
+ file = Pathname.new('dir1')
369
+ assert_equal [Pathname.new('dir1')], file.split_all
370
+
371
+ file = Pathname.new('/dir1')
372
+ assert_equal [Pathname.new('/'), Pathname.new('/dir1')], file.split_all
373
+
374
+ file = Pathname.new('dir1/dir2/base')
375
+ assert_equal [Pathname.new('dir1'), Pathname.new('dir1/dir2'), Pathname.new('dir1/dir2/base')], file.split_all
376
+
377
+ file = Pathname.new('/dir1/dir2/base')
378
+ assert_equal [Pathname.new('/'), Pathname.new('/dir1'), Pathname.new('/dir1/dir2'), Pathname.new('/dir1/dir2/base')], file.split_all
379
+ end
380
+
381
+ def test_split_all_without_basename
382
+ file = Pathname.new('/')
383
+ assert_equal [], file.split_all_without_basename
384
+
385
+ file = Pathname.new('dir1')
386
+ assert_equal [], file.split_all_without_basename
387
+
388
+ file = Pathname.new('/dir1')
389
+ assert_equal [Pathname.new('/')], file.split_all_without_basename
390
+
391
+ file = Pathname.new('dir1/dir2/base')
392
+ assert_equal [Pathname.new('dir1'), Pathname.new('dir1/dir2')], file.split_all_without_basename
393
+
394
+ file = Pathname.new('/dir1/dir2/base')
395
+ assert_equal [Pathname.new('/'), Pathname.new('/dir1'), Pathname.new('/dir1/dir2')], file.split_all_without_basename
396
+ end
397
+
398
+ def test_parent_dirs
399
+ file = Pathname.new('/')
400
+ assert_equal [Pathname.new('/')], file.parent_dirs
401
+
402
+ # Before I had absolutize in parent_dirs
403
+ # file = Pathname.new('dir1')
404
+ # assert_equal false, file.directory? # Even though 'dir1' sounds like a directory to us humans, #directory? has no way of knowing that and so returns false.
405
+ # # parent_dirs is not useful when used with fictional paths; because it actually calls #directory?, the path must actually exist for it to work as advertised.
406
+ # assert_equal [], file.parent_dirs
407
+
408
+ # Before I had absolutize in parent_dirs
409
+ # Dir.chdir('/tmp') do
410
+ # Pathname.new('dir1').mkpath
411
+ # file = Pathname.new('dir1')
412
+ # # dir1 is not fictional in this test; parent_dirs will work as expected
413
+ # assert_equal true, file.directory?
414
+ # assert_equal [Pathname.new('dir1')], file.parent_dirs
415
+ # assert_equal [], file.parent_dirs(false) # don't include self
416
+ # end
417
+
418
+ Dir.chdir('/tmp') do
419
+ Pathname.new('dir1').mkpath
420
+ file = Pathname.new('dir1')
421
+ assert_equal true, file.directory?
422
+ assert_equal [Pathname.new('/'), Pathname.new('/tmp'), Pathname.new('/tmp/dir1')], file.parent_dirs
423
+ end
424
+
425
+
426
+ # Before I had absolutize in parent_dirs
427
+ # # Again, passed a fictional dir, so #directory? will return false (even though technically it is unknown/undefined) and basename will be dropped
428
+ begin
429
+ file = Pathname.new('/dir1')
430
+ assert_equal [Pathname.new('/')], file.parent_dirs
431
+
432
+ file = Pathname.new('/dir1/dir2/base')
433
+ assert_equal [Pathname.new('/'), Pathname.new('/dir1'), Pathname.new('/dir1/dir2')], file.parent_dirs
434
+ end
435
+
436
+ # dir1 should be real (should exist) this time, and self/basename is included by default if self is a directory.
437
+ file = Pathname.new('/tmp/dir1')
438
+ assert_equal [Pathname.new('/'), Pathname.new('/tmp'), Pathname.new('/tmp/dir1')], file.parent_dirs
439
+ assert_equal [Pathname.new('/'), Pathname.new('/tmp') ], file.parent_dirs(false)
440
+ end
441
+
442
+ def test_split_all_s
443
+ file = Pathname.new('/')
444
+ assert_equal ['/'], file.split_all_s
445
+
446
+ file = Pathname.new('dir1')
447
+ assert_equal ['dir1'], file.split_all_s
448
+
449
+ file = Pathname.new('/dir1')
450
+ assert_equal ['/', 'dir1'], file.split_all_s
451
+
452
+ file = Pathname.new('dir1/dir2/base')
453
+ assert_equal ['dir1', 'dir2', 'base'], file.split_all_s
454
+
455
+ file = Pathname.new('/dir1/dir2/base')
456
+ assert_equal ['/', 'dir1', 'dir2', 'base'], file.split_all_s
457
+ end
458
+
459
+ # original:
460
+ # def test_each_parent_dir
461
+ # sought_file = Pathname.new('/tmp/sought')
462
+ # sought_file.touch
463
+ # assert sought_file.exist?
464
+ # assert !sought_file.directory?
465
+ #
466
+ # inner_dir = Pathname.new('/tmp/a/b')
467
+ # inner_dir.mkpath
468
+ # assert inner_dir.exist?
469
+ # assert inner_dir.directory?
470
+ #
471
+ # i = 0
472
+ # found = inner_dir.each_parent_dir do |dir|
473
+ # i += 1
474
+ # candidate = dir + 'sought'
475
+ # candidate if candidate.exist?
476
+ # end
477
+ #
478
+ # assert_equal '/tmp/sought', found.to_s
479
+ # assert_equal sought_file, found
480
+ # assert_equal 2, i
481
+ #
482
+ # # But if we start from our getwd, we probably shouldn't find sought
483
+ # i = 0
484
+ # found = Pathname.getwd.each_parent_dir do |dir|
485
+ # i += 1
486
+ # candidate = dir + 'sought'
487
+ # candidate if candidate.exist?
488
+ # end
489
+ # assert_equal nil, found
490
+ # assert i >= 2
491
+ #
492
+ # # It should call cleanpath to convert relative to absolute paths
493
+ # # If we didn't do that, the block would not get called at all in this case.
494
+ # i = 0
495
+ # found = Pathname.new('.').each_parent_dir do |dir|
496
+ # i += 1
497
+ # candidate = dir + 'sought'
498
+ # candidate if candidate.exist?
499
+ # end
500
+ # assert_equal nil, found
501
+ # assert i >= 1, "Did not ascend at least 1 directory higher than '.'"
502
+ # end
503
+
504
+ def test_each_parent_dir
505
+ sought_file = Pathname.new('/tmp/sought')
506
+ sought_file.touch
507
+ assert sought_file.exist?
508
+ assert !sought_file.directory?
509
+
510
+ inner_dir = Pathname.new('/tmp/a/b')
511
+ inner_dir.mkpath
512
+ assert inner_dir.exist?
513
+ assert inner_dir.directory?
514
+
515
+ visited = []
516
+ inner_dir.each_parent_dir do |dir|
517
+ visited << dir
518
+ end
519
+ assert_equal [Pathname.new('/tmp/a/b'), Pathname.new('/tmp/a'), Pathname.new('/tmp'), Pathname.new('/')], visited
520
+
521
+ visited = []
522
+ found = inner_dir.each_parent_dir do |dir|
523
+ visited << dir
524
+ candidate = dir + 'sought'
525
+ break candidate if candidate.exist?
526
+ end
527
+
528
+ assert_equal '/tmp/sought', found.to_s
529
+ assert_equal sought_file, found
530
+ assert_equal [Pathname.new('/tmp/a/b'), Pathname.new('/tmp/a'), Pathname.new('/tmp')], visited
531
+
532
+ # But if we start from our getwd, we probably shouldn't find sought
533
+ i = 0
534
+ found = Pathname.getwd.each_parent_dir do |dir|
535
+ i += 1
536
+ candidate = dir + 'sought'
537
+ break candidate if candidate.exist?
538
+ end
539
+ assert_equal nil, found
540
+ assert i >= 2
541
+
542
+ # It should call cleanpath to convert relative to absolute paths
543
+ # If we didn't do that, the block would not get called at all in this case.
544
+ i = 0
545
+ found = Pathname.new('.').each_parent_dir do |dir|
546
+ i += 1
547
+ candidate = dir + 'sought'
548
+ break candidate if candidate.exist?
549
+ end
550
+ assert_equal nil, found
551
+ assert i >= 1, "Did not ascend at least 1 directory higher than '.'"
552
+ end
553
+
126
554
  end
127
555
  =end
128
556