nanoc 3.4.3 → 3.5.0b1

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.
Files changed (85) hide show
  1. data/CONTRIBUTING.md +25 -0
  2. data/Gemfile +3 -1
  3. data/Gemfile.lock +22 -13
  4. data/NEWS.md +27 -0
  5. data/README.md +3 -1
  6. data/lib/nanoc.rb +2 -2
  7. data/lib/nanoc/base/compilation/compiler_dsl.rb +19 -0
  8. data/lib/nanoc/base/core_ext/array.rb +18 -8
  9. data/lib/nanoc/base/core_ext/hash.rb +18 -8
  10. data/lib/nanoc/base/core_ext/pathname.rb +2 -8
  11. data/lib/nanoc/base/plugin_registry.rb +57 -19
  12. data/lib/nanoc/base/result_data/item_rep.rb +3 -15
  13. data/lib/nanoc/base/source_data/item.rb +1 -1
  14. data/lib/nanoc/base/source_data/layout.rb +1 -1
  15. data/lib/nanoc/base/source_data/site.rb +15 -19
  16. data/lib/nanoc/cli.rb +28 -23
  17. data/lib/nanoc/cli/command_runner.rb +4 -0
  18. data/lib/nanoc/cli/commands/autocompile.rb +15 -6
  19. data/lib/nanoc/cli/commands/check.rb +47 -0
  20. data/lib/nanoc/cli/commands/compile.rb +271 -195
  21. data/lib/nanoc/cli/commands/create-site.rb +5 -5
  22. data/lib/nanoc/cli/commands/deploy.rb +16 -4
  23. data/lib/nanoc/cli/commands/prune.rb +3 -3
  24. data/lib/nanoc/cli/commands/show-data.rb +73 -58
  25. data/lib/nanoc/cli/commands/show-rules.rb +1 -1
  26. data/lib/nanoc/cli/commands/validate-css.rb +2 -3
  27. data/lib/nanoc/cli/commands/validate-html.rb +2 -3
  28. data/lib/nanoc/cli/commands/validate-links.rb +5 -11
  29. data/lib/nanoc/cli/commands/view.rb +1 -1
  30. data/lib/nanoc/cli/commands/watch.rb +38 -20
  31. data/lib/nanoc/cli/error_handler.rb +122 -122
  32. data/lib/nanoc/data_sources.rb +2 -0
  33. data/lib/nanoc/data_sources/filesystem_unified.rb +1 -1
  34. data/lib/nanoc/data_sources/filesystem_verbose.rb +1 -1
  35. data/lib/nanoc/data_sources/static.rb +60 -0
  36. data/lib/nanoc/extra.rb +2 -0
  37. data/lib/nanoc/extra/checking.rb +16 -0
  38. data/lib/nanoc/extra/checking/check.rb +33 -0
  39. data/lib/nanoc/extra/checking/checks.rb +19 -0
  40. data/lib/nanoc/extra/checking/checks/css.rb +23 -0
  41. data/lib/nanoc/extra/checking/checks/external_links.rb +149 -0
  42. data/lib/nanoc/extra/checking/checks/html.rb +24 -0
  43. data/lib/nanoc/extra/checking/checks/internal_links.rb +57 -0
  44. data/lib/nanoc/extra/checking/checks/stale.rb +23 -0
  45. data/lib/nanoc/extra/checking/dsl.rb +31 -0
  46. data/lib/nanoc/extra/checking/issue.rb +19 -0
  47. data/lib/nanoc/extra/checking/runner.rb +130 -0
  48. data/lib/nanoc/extra/link_collector.rb +57 -0
  49. data/lib/nanoc/extra/pruner.rb +1 -1
  50. data/lib/nanoc/extra/validators/links.rb +5 -262
  51. data/lib/nanoc/extra/validators/w3c.rb +8 -76
  52. data/lib/nanoc/filters/colorize_syntax.rb +1 -1
  53. data/lib/nanoc/filters/handlebars.rb +2 -2
  54. data/lib/nanoc/filters/less.rb +1 -1
  55. data/lib/nanoc/filters/redcarpet.rb +1 -1
  56. data/lib/nanoc/filters/rubypants.rb +1 -1
  57. data/lib/nanoc/filters/slim.rb +1 -1
  58. data/lib/nanoc/helpers/blogging.rb +163 -104
  59. data/lib/nanoc/helpers/xml_sitemap.rb +9 -3
  60. data/tasks/doc.rake +2 -1
  61. data/test/base/core_ext/array_spec.rb +4 -4
  62. data/test/base/core_ext/hash_spec.rb +7 -7
  63. data/test/base/core_ext/pathname_spec.rb +12 -2
  64. data/test/base/test_compiler_dsl.rb +24 -0
  65. data/test/base/test_item_rep.rb +58 -26
  66. data/test/cli/commands/test_watch.rb +0 -8
  67. data/test/data_sources/test_static.rb +66 -0
  68. data/test/extra/checking/checks/test_css.rb +40 -0
  69. data/test/extra/checking/checks/test_external_links.rb +76 -0
  70. data/test/extra/checking/checks/test_html.rb +40 -0
  71. data/test/extra/checking/checks/test_internal_links.rb +46 -0
  72. data/test/extra/checking/checks/test_stale.rb +49 -0
  73. data/test/extra/checking/test_check.rb +16 -0
  74. data/test/extra/checking/test_dsl.rb +20 -0
  75. data/test/extra/checking/test_runner.rb +15 -0
  76. data/test/extra/test_link_collector.rb +93 -0
  77. data/test/extra/validators/test_links.rb +0 -64
  78. data/test/extra/validators/test_w3c.rb +20 -26
  79. data/test/filters/test_colorize_syntax.rb +15 -0
  80. data/test/filters/test_less.rb +14 -0
  81. data/test/filters/test_pandoc.rb +5 -1
  82. data/test/helpers/test_blogging.rb +52 -8
  83. data/test/helpers/test_xml_sitemap.rb +68 -0
  84. data/test/test_gem.rb +1 -1
  85. metadata +31 -6
@@ -35,12 +35,16 @@ module Nanoc::Helpers
35
35
  #
36
36
  # @option params [Array] :items A list of items to include in the sitemap
37
37
  #
38
+ # @option params [Proc] :rep_select A proc to filter reps through. If the
39
+ # proc returns true, the rep will be included; otherwise, it will not.
40
+ #
38
41
  # @return [String] The XML sitemap
39
42
  def xml_sitemap(params={})
40
43
  require 'builder'
41
44
 
42
45
  # Extract parameters
43
- items = params.fetch(:items) { @items.reject { |i| i[:is_hidden] } }
46
+ items = params.fetch(:items) { @items.reject { |i| i[:is_hidden] } }
47
+ select_proc = params.fetch(:rep_select, nil)
44
48
 
45
49
  # Create builder
46
50
  buffer = ''
@@ -55,8 +59,10 @@ module Nanoc::Helpers
55
59
  xml.instruct!
56
60
  xml.urlset(:xmlns => 'http://www.sitemaps.org/schemas/sitemap/0.9') do
57
61
  # Add item
58
- items.each do |item|
59
- item.reps.reject { |r| r.raw_path.nil? }.each do |rep|
62
+ items.sort_by { |i| i.identifier }.each do |item|
63
+ reps = item.reps.reject { |r| r.raw_path.nil? }
64
+ reps.reject! { |r| !select_proc[r] } if select_proc
65
+ reps.sort_by { |r| r.name.to_s }.each do |rep|
60
66
  xml.url do
61
67
  xml.loc @site.config[:base_url] + rep.path
62
68
  xml.lastmod item[:mtime].to_iso8601_date unless item[:mtime].nil?
@@ -11,6 +11,7 @@ YARD::Rake::YardocTask.new(:doc) do |yard|
11
11
  '--readme', 'README.md',
12
12
  '--files', 'NEWS.md,LICENSE',
13
13
  '--output-dir', 'doc/yardoc',
14
- '--template-path', 'doc/yardoc_templates'
14
+ '--template-path', 'doc/yardoc_templates',
15
+ '--load', 'doc/yardoc_handlers/identifier.rb'
15
16
  ]
16
17
  end
@@ -1,21 +1,21 @@
1
1
  # encoding: utf-8
2
2
 
3
- describe 'Array#symbolize_keys' do
3
+ describe 'Array#symbolize_keys_recursively' do
4
4
 
5
5
  it 'should convert keys to symbols' do
6
6
  array_old = [ :abc, 'xyz', { 'foo' => 'bar', :baz => :qux } ]
7
7
  array_new = [ :abc, 'xyz', { :foo => 'bar', :baz => :qux } ]
8
- array_old.symbolize_keys.must_equal array_new
8
+ array_old.symbolize_keys_recursively.must_equal array_new
9
9
  end
10
10
 
11
11
  end
12
12
 
13
- describe 'Array#stringify_keys' do
13
+ describe 'Array#stringify_keys_recursively' do
14
14
 
15
15
  it 'should convert keys to strings' do
16
16
  array_old = [ :abc, 'xyz', { :foo => 'bar', 'baz' => :qux } ]
17
17
  array_new = [ :abc, 'xyz', { 'foo' => 'bar', 'baz' => :qux } ]
18
- array_old.stringify_keys.must_equal array_new
18
+ array_old.stringify_keys_recursively.must_equal array_new
19
19
  end
20
20
 
21
21
  end
@@ -1,39 +1,39 @@
1
1
  # encoding: utf-8
2
2
 
3
- describe 'Hash#symbolize_keys' do
3
+ describe 'Hash#symbolize_keys_recursively' do
4
4
 
5
5
  it 'should convert keys to symbols' do
6
6
  hash_old = { 'foo' => 'bar' }
7
7
  hash_new = { :foo => 'bar' }
8
- hash_old.symbolize_keys.must_equal hash_new
8
+ hash_old.symbolize_keys_recursively.must_equal hash_new
9
9
  end
10
10
 
11
11
  end
12
12
 
13
- describe 'Hash#stringify_keys' do
13
+ describe 'Hash#stringify_keys_recursively' do
14
14
 
15
15
  it 'should leave strings as strings' do
16
16
  hash_old = { 'foo' => 'bar' }
17
17
  hash_new = { 'foo' => 'bar' }
18
- hash_old.stringify_keys.must_equal hash_new
18
+ hash_old.stringify_keys_recursively.must_equal hash_new
19
19
  end
20
20
 
21
21
  it 'should convert symbols to strings' do
22
22
  hash_old = { :foo => 'bar' }
23
23
  hash_new = { 'foo' => 'bar' }
24
- hash_old.stringify_keys.must_equal hash_new
24
+ hash_old.stringify_keys_recursively.must_equal hash_new
25
25
  end
26
26
 
27
27
  it 'should convert integers to strings' do
28
28
  hash_old = { 123 => 'bar' }
29
29
  hash_new = { '123' => 'bar' }
30
- hash_old.stringify_keys.must_equal hash_new
30
+ hash_old.stringify_keys_recursively.must_equal hash_new
31
31
  end
32
32
 
33
33
  it 'should convert nil to an empty string' do
34
34
  hash_old = { nil => 'bar' }
35
35
  hash_new = { '' => 'bar' }
36
- hash_old.stringify_keys.must_equal hash_new
36
+ hash_old.stringify_keys_recursively.must_equal hash_new
37
37
  end
38
38
 
39
39
  end
@@ -4,10 +4,15 @@ describe 'Pathname#checksum' do
4
4
 
5
5
  it 'should work on empty files' do
6
6
  begin
7
+ # Create file
7
8
  FileUtils.mkdir_p('tmp')
8
9
  File.open('tmp/myfile', 'w') { |io| io.write('') }
10
+ now = Time.now
11
+ File.utime(now, now, 'tmp/myfile')
12
+
13
+ # Create checksum
9
14
  pathname = Pathname.new('tmp/myfile')
10
- pathname.checksum.must_equal 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
15
+ pathname.checksum.must_equal '0-' + now.to_s
11
16
  ensure
12
17
  FileUtils.rm_rf('tmp')
13
18
  end
@@ -15,10 +20,15 @@ describe 'Pathname#checksum' do
15
20
 
16
21
  it 'should work on all files' do
17
22
  begin
23
+ # Create file
18
24
  FileUtils.mkdir_p('tmp')
19
25
  File.open('tmp/myfile', 'w') { |io| io.write('abc') }
26
+ now = Time.now
27
+ File.utime(now, now, 'tmp/myfile')
28
+
29
+ # Create checksum
20
30
  pathname = Pathname.new('tmp/myfile')
21
- pathname.checksum.must_equal 'a9993e364706816aba3e25717850c26c9cd0d89d'
31
+ pathname.checksum.must_equal '3-' + now.to_s
22
32
  ensure
23
33
  FileUtils.rm_rf('tmp')
24
34
  end
@@ -16,6 +16,30 @@ class Nanoc::CompilerDSLTest < MiniTest::Unit::TestCase
16
16
  # TODO implement
17
17
  end
18
18
 
19
+ def test_include_rules
20
+ # Create site
21
+ Nanoc::CLI.run %w( create_site with_bonus_rules )
22
+ FileUtils.cd('with_bonus_rules') do
23
+ # Create rep
24
+ item = Nanoc::Item.new('foo', { :extension => 'bar' }, '/foo/')
25
+ rep = Nanoc::ItemRep.new(item, :default)
26
+
27
+ # Create a bonus rules file
28
+ File.open('more_rules.rb', 'w') { |io| io.write "passthrough '/foo/'" }
29
+
30
+ # Create other necessary stuff
31
+ site = Nanoc::Site.new('.')
32
+ site.items << item
33
+ dsl = site.compiler.rules_collection.dsl
34
+
35
+ # Include rules
36
+ dsl.include_rules 'more_rules'
37
+
38
+ # Check that the rule made it into the collection
39
+ refute_nil site.compiler.rules_collection.routing_rule_for(rep)
40
+ end
41
+ end
42
+
19
43
  def test_passthrough
20
44
  with_site do
21
45
  # Create rules
@@ -221,32 +221,6 @@ class Nanoc::ItemRepTest < MiniTest::Unit::TestCase
221
221
  assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
222
222
  end
223
223
 
224
- def test_write_should_not_touch_identical_binary_files
225
- # Create temporary source file
226
- File.open('blahblah', 'w') { |io| io.write("Blah blah…") }
227
- full_file_path = File.expand_path('blahblah')
228
-
229
- # Mock item
230
- item = Nanoc::Item.new(
231
- full_file_path, {}, '/',
232
- :binary => true
233
- )
234
-
235
- # Create rep
236
- item_rep = Nanoc::ItemRep.new(item, :foo)
237
- item_rep.raw_path = 'foo/bar/baz/quux'
238
-
239
- # Write once
240
- item_rep.write
241
- a_long_time_ago = Time.now-1_000_000
242
- File.utime(a_long_time_ago, a_long_time_ago, item_rep.raw_path)
243
-
244
- # Write again
245
- assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
246
- item_rep.write
247
- assert_equal a_long_time_ago.to_s, File.mtime(item_rep.raw_path).to_s
248
- end
249
-
250
224
  def test_write
251
225
  # Mock item
252
226
  item = Nanoc::Item.new(
@@ -536,6 +510,64 @@ class Nanoc::ItemRepTest < MiniTest::Unit::TestCase
536
510
  end
537
511
  end
538
512
 
513
+ def test_write_should_calculate_is_modified_correctly_for_binary_items_new
514
+ # Mock item
515
+ FileUtils.mkdir_p('content')
516
+ File.open('content/meow.dat', 'w') { |io| io.write('asdf') }
517
+ item = Nanoc::Item.new(
518
+ "content/meow.dat", {}, '/',
519
+ :binary => true
520
+ )
521
+
522
+ # Create rep
523
+ item_rep = Nanoc::ItemRep.new(item, :foo)
524
+ FileUtils.mkdir_p('tmp')
525
+ File.open('tmp/woof.dat', 'w') { |io| io.write('fdsa') }
526
+ item_rep.instance_eval { @temporary_filenames[:last] = 'tmp/woof.dat' }
527
+ item_rep.raw_path = 'output/woof.dat'
528
+
529
+ # Write
530
+ notified = false
531
+ Nanoc::NotificationCenter.on(:rep_written, self) do |rep, raw_path, is_created, is_modified|
532
+ notified = true
533
+ assert is_created
534
+ assert is_modified
535
+ end
536
+ item_rep.write
537
+ assert notified
538
+ Nanoc::NotificationCenter.remove(:rep_written, self)
539
+ end
540
+
541
+ def test_write_should_calculate_is_modified_correctly_for_binary_items_existing
542
+ # Mock item
543
+ FileUtils.mkdir_p('content')
544
+ File.open('content/meow.dat', 'w') { |io| io.write('asdf') }
545
+ item = Nanoc::Item.new(
546
+ "content/meow.dat", {}, '/',
547
+ :binary => true
548
+ )
549
+
550
+ # Create rep
551
+ item_rep = Nanoc::ItemRep.new(item, :foo)
552
+ FileUtils.mkdir_p('tmp')
553
+ File.open('tmp/woof.dat', 'w') { |io| io.write('fdsa') }
554
+ FileUtils.mkdir_p('output')
555
+ File.open('output/woof.dat', 'w') { |io| io.write('fdsa but different') }
556
+ item_rep.instance_eval { @temporary_filenames[:last] = 'tmp/woof.dat' }
557
+ item_rep.raw_path = 'output/woof.dat'
558
+
559
+ # Write
560
+ notified = false
561
+ Nanoc::NotificationCenter.on(:rep_written, self) do |rep, raw_path, is_created, is_modified|
562
+ notified = true
563
+ refute is_created
564
+ assert is_modified
565
+ end
566
+ item_rep.write
567
+ assert notified
568
+ Nanoc::NotificationCenter.remove(:rep_written, self)
569
+ end
570
+
539
571
  private
540
572
 
541
573
  def create_binary_item
@@ -4,14 +4,6 @@ class Nanoc::CLI::Commands::WatchTest < MiniTest::Unit::TestCase
4
4
 
5
5
  include Nanoc::TestHelpers
6
6
 
7
- def setup
8
- super
9
- @@warned ||= begin
10
- STDERR.puts "\n(fssm deprecation warning can be ignored; master branch uses guard/listen)"
11
- true
12
- end
13
- end
14
-
15
7
  def test_run
16
8
  with_site do |s|
17
9
  watch_thread = Thread.new do
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ class Nanoc::DataSources::StaticTest < MiniTest::Unit::TestCase
4
+
5
+ include Nanoc::TestHelpers
6
+
7
+ def new_data_source(params=nil)
8
+ # Mock site
9
+ site = Nanoc::Site.new({})
10
+
11
+ # Create data source
12
+ data_source = Nanoc::DataSources::Static.new(site, nil, nil, params)
13
+
14
+ # Done
15
+ data_source
16
+ end
17
+
18
+ def test_items
19
+ # Create data source
20
+ data_source = new_data_source(:prefix => 'foo')
21
+
22
+ # Create sample files
23
+ FileUtils.mkdir_p('foo')
24
+ FileUtils.mkdir_p('foo/a/b')
25
+ File.open('foo/bar.png', 'w') { |io| io.write("random binary data") }
26
+ File.open('foo/b.c.css', 'w') { |io| io.write("more binary data") }
27
+ File.open('foo/a/b/c.gif', 'w') { |io| io.write("yet more binary data") }
28
+
29
+ # Get expected and actual output
30
+ expected_out = [
31
+ Nanoc::Item.new(
32
+ 'foo/bar.png',
33
+ { :extension => 'png', :filename => 'foo/bar.png' },
34
+ '/bar.png/',
35
+ :binary => true,
36
+ :mtime => File.mtime('foo/bar.png'),
37
+ :checksum => Pathname.new('foo/bar.png').checksum
38
+ ),
39
+ Nanoc::Item.new(
40
+ 'foo/b.c.css',
41
+ { :extension => 'css', :filename => 'foo/b.c.css' },
42
+ '/b.c.css/',
43
+ :binary => true,
44
+ :mtime => File.mtime('foo/b.c.css'),
45
+ :checksum => Pathname.new('foo/b.c.css').checksum
46
+ ),
47
+ Nanoc::Item.new(
48
+ 'foo/a/b/c.gif',
49
+ { :extension => 'gif', :filename => 'foo/a/b/c.gif' },
50
+ '/a/b/c.gif/',
51
+ :binary => true,
52
+ :mtime => File.mtime('foo/a/b/c.gif'),
53
+ :checksum => Pathname.new('foo/a/b/c.gif').checksum
54
+ )
55
+ ].sort_by { |i| i.identifier }
56
+
57
+ actual_out = data_source.send(:items).sort_by { |i| i.identifier }
58
+
59
+ (0..expected_out.size-1).each do |i|
60
+ assert_equal expected_out[i].raw_content, actual_out[i].raw_content, 'content must match'
61
+ assert_equal expected_out[i].identifier, actual_out[i].identifier, 'identifier must match'
62
+ assert_equal expected_out[i].mtime, actual_out[i].mtime, 'mtime must match'
63
+ assert_equal expected_out[i].raw_filename, actual_out[i].raw_filename, 'file paths must match'
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ class Nanoc::Extra::Checking::Checks::CSSTest < MiniTest::Unit::TestCase
4
+
5
+ include Nanoc::TestHelpers
6
+
7
+ def test_run_ok
8
+ with_site do |site|
9
+ # Create files
10
+ FileUtils.mkdir_p('output')
11
+ File.open('output/blah.html', 'w') { |io| io.write('<h1>Hi!</h1>') }
12
+ File.open('output/style.css', 'w') { |io| io.write('h1 { color: red; }') }
13
+
14
+ # Run check
15
+ check = Nanoc::Extra::Checking::Checks::CSS.new(site)
16
+ check.run
17
+
18
+ # Check
19
+ assert check.issues.empty?
20
+ end
21
+ end
22
+
23
+ def test_run_error
24
+ with_site do |site|
25
+ # Create files
26
+ FileUtils.mkdir_p('output')
27
+ File.open('output/blah.html', 'w') { |io| io.write('<h1>Hi!</h1>') }
28
+ File.open('output/style.css', 'w') { |io| io.write('h1 { coxlor: rxed; }') }
29
+
30
+ # Run check
31
+ check = Nanoc::Extra::Checking::Checks::CSS.new(site)
32
+ check.run
33
+
34
+ # Check
35
+ refute check.issues.empty?
36
+ end
37
+ end
38
+
39
+ end
40
+
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+
3
+ class Nanoc::Extra::Checking::Checks::ExternalLinksTest < MiniTest::Unit::TestCase
4
+
5
+ include Nanoc::TestHelpers
6
+
7
+ def setup
8
+ super
9
+ require 'timeout'
10
+ end
11
+
12
+ def test_run
13
+ with_site do |site|
14
+ # Create files
15
+ FileUtils.mkdir_p('output')
16
+ FileUtils.mkdir_p('output/stuff')
17
+ File.open('output/foo.txt', 'w') { |io| io.write('<a href="http://example.com/404">broken</a>') }
18
+ File.open('output/bar.html', 'w') { |io| io.write('<a href="http://example.com/">not broken</a>') }
19
+
20
+ # Create check
21
+ check = Nanoc::Extra::Checking::Checks::InternalLinks.new(site)
22
+ check.run
23
+
24
+ # Test
25
+ assert check.issues.empty?
26
+ end
27
+ end
28
+
29
+ def test_valid?
30
+ with_site do |site|
31
+ # Create files
32
+ FileUtils.mkdir_p('output')
33
+ FileUtils.mkdir_p('output/stuff')
34
+ File.open('output/origin', 'w') { |io| io.write('hi') }
35
+ File.open('output/foo', 'w') { |io| io.write('hi') }
36
+ File.open('output/stuff/blah', 'w') { |io| io.write('hi') }
37
+
38
+ # Create check
39
+ check = Nanoc::Extra::Checking::Checks::ExternalLinks.new(site)
40
+
41
+ # Test
42
+ self.run_server_while do
43
+ assert ok?(check, 'http://127.0.0.1:9204/200')
44
+ assert ok?(check, 'foo://example.com/')
45
+ refute ok?(check, 'http://127.0.0.1:9204">')
46
+ end
47
+ end
48
+ end
49
+
50
+ def ok?(check, url)
51
+ Timeout.timeout(3) do
52
+ check.validate(url).nil?
53
+ end
54
+ end
55
+
56
+ def run_server_while
57
+ @app = lambda { |env| [ env['REQUEST_PATH'][1..-1].to_i, {}, [ '... Useless body ...' ] ] }
58
+ @server = nil
59
+
60
+ @thread = Thread.new do
61
+ Rack::Handler::WEBrick.run(@app, :Host => @host='127.0.0.1', :Port => @port=9204) do |server|
62
+ @server = server
63
+ end
64
+ end
65
+
66
+ Timeout::timeout(5) do
67
+ Thread.pass until @server
68
+ end
69
+
70
+ yield
71
+
72
+ @server.stop
73
+ @thread.kill
74
+ end
75
+
76
+ end