bitclust-core 1.3.0 → 1.6.0

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 (152) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/README.md +65 -0
  4. data/Rakefile +32 -0
  5. data/data/bitclust/catalog/ja_JP.UTF-8 +19 -1
  6. data/data/bitclust/searchpage/index.html +90 -0
  7. data/data/bitclust/template/class +69 -8
  8. data/data/bitclust/template/function +2 -2
  9. data/data/bitclust/template/layout +11 -3
  10. data/data/bitclust/template/method +2 -2
  11. data/data/bitclust/template/search +1 -1
  12. data/data/bitclust/template.epub/class +22 -1
  13. data/data/bitclust/template.epub/function +2 -2
  14. data/data/bitclust/template.epub/layout +1 -3
  15. data/data/bitclust/template.epub/method +2 -2
  16. data/data/bitclust/template.lillia/class +26 -5
  17. data/data/bitclust/template.lillia/layout +1 -3
  18. data/data/bitclust/template.lillia/method +2 -2
  19. data/data/bitclust/template.offline/class +48 -4
  20. data/data/bitclust/template.offline/function +2 -2
  21. data/data/bitclust/template.offline/layout +27 -3
  22. data/data/bitclust/template.offline/method +2 -2
  23. data/lib/bitclust/app.rb +16 -17
  24. data/lib/bitclust/capi_converter.rb +20 -0
  25. data/lib/bitclust/classentry.rb +67 -17
  26. data/lib/bitclust/compat.rb +2 -2
  27. data/lib/bitclust/completion.rb +58 -27
  28. data/lib/bitclust/crossrubyutils.rb +8 -5
  29. data/lib/bitclust/database.rb +28 -8
  30. data/lib/bitclust/doc_converter.rb +63 -0
  31. data/lib/bitclust/docentry.rb +1 -1
  32. data/lib/bitclust/entity_splitter.rb +221 -0
  33. data/lib/bitclust/entry.rb +47 -7
  34. data/lib/bitclust/functiondatabase.rb +13 -1
  35. data/lib/bitclust/functionentry.rb +5 -1
  36. data/lib/bitclust/functionreferenceparser.rb +4 -4
  37. data/lib/bitclust/generators/epub.rb +10 -3
  38. data/lib/bitclust/htmlutils.rb +1 -1
  39. data/lib/bitclust/include_graph.rb +375 -0
  40. data/lib/bitclust/include_pruner.rb +144 -0
  41. data/lib/bitclust/interface.rb +1 -1
  42. data/lib/bitclust/libraryentry.rb +8 -7
  43. data/lib/bitclust/lineinput.rb +7 -5
  44. data/lib/bitclust/link_checker.rb +179 -0
  45. data/lib/bitclust/markdown_bridge.rb +186 -0
  46. data/lib/bitclust/markdown_orchestrator.rb +267 -0
  47. data/lib/bitclust/markdown_to_rrd.rb +824 -0
  48. data/lib/bitclust/markdown_tree.rb +217 -0
  49. data/lib/bitclust/mdcompiler.rb +883 -0
  50. data/lib/bitclust/mdparser.rb +347 -0
  51. data/lib/bitclust/messagecatalog.rb +3 -3
  52. data/lib/bitclust/method_since_calculator.rb +117 -0
  53. data/lib/bitclust/methoddatabase.rb +124 -14
  54. data/lib/bitclust/methodentry.rb +125 -7
  55. data/lib/bitclust/methodid.rb +12 -11
  56. data/lib/bitclust/methodsignature.rb +10 -4
  57. data/lib/bitclust/nameutils.rb +41 -22
  58. data/lib/bitclust/preprocessor.rb +66 -29
  59. data/lib/bitclust/rdcompiler.rb +195 -95
  60. data/lib/bitclust/refsdatabase.rb +23 -8
  61. data/lib/bitclust/reloadable_request_handler.rb +72 -0
  62. data/lib/bitclust/requesthandler.rb +21 -16
  63. data/lib/bitclust/ridatabase.rb +10 -4
  64. data/lib/bitclust/rrd_to_markdown.rb +925 -0
  65. data/lib/bitclust/rrdparser.rb +196 -30
  66. data/lib/bitclust/runner.rb +17 -2
  67. data/lib/bitclust/screen.rb +80 -11
  68. data/lib/bitclust/search_index_generator.rb +288 -0
  69. data/lib/bitclust/searcher.rb +69 -20
  70. data/lib/bitclust/simplesearcher.rb +24 -12
  71. data/lib/bitclust/subcommand.rb +7 -1
  72. data/lib/bitclust/subcommands/ancestors_command.rb +9 -2
  73. data/lib/bitclust/subcommands/checklink_command.rb +54 -0
  74. data/lib/bitclust/subcommands/chm_command.rb +15 -7
  75. data/lib/bitclust/subcommands/classes_command.rb +5 -0
  76. data/lib/bitclust/subcommands/extract_command.rb +5 -0
  77. data/lib/bitclust/subcommands/htmlfile_command.rb +21 -7
  78. data/lib/bitclust/subcommands/init_command.rb +4 -1
  79. data/lib/bitclust/subcommands/list_command.rb +12 -4
  80. data/lib/bitclust/subcommands/lookup_command.rb +28 -9
  81. data/lib/bitclust/subcommands/methods_command.rb +10 -2
  82. data/lib/bitclust/subcommands/methodsince_command.rb +80 -0
  83. data/lib/bitclust/subcommands/preproc_command.rb +5 -0
  84. data/lib/bitclust/subcommands/property_command.rb +2 -1
  85. data/lib/bitclust/subcommands/searchpage_command.rb +102 -0
  86. data/lib/bitclust/subcommands/server_command.rb +10 -8
  87. data/lib/bitclust/subcommands/setup_command.rb +24 -10
  88. data/lib/bitclust/subcommands/statichtml_command.rb +129 -6
  89. data/lib/bitclust/subcommands/update_command.rb +110 -2
  90. data/lib/bitclust/syntax_highlighter.rb +48 -4
  91. data/lib/bitclust/textutils.rb +3 -3
  92. data/lib/bitclust/version.rb +1 -1
  93. data/lib/bitclust/version_badges.rb +90 -0
  94. data/lib/bitclust/whole_file_gate.rb +137 -0
  95. data/test/test_app.rb +269 -0
  96. data/test/test_bitclust.rb +2 -0
  97. data/test/test_capi_converter.rb +91 -0
  98. data/test/test_class_screen.rb +413 -0
  99. data/test/test_copy_doc_md.rb +53 -0
  100. data/test/test_doc_converter.rb +78 -0
  101. data/test/test_entity_splitter.rb +231 -0
  102. data/test/test_entry.rb +207 -2
  103. data/test/test_eol_warning.rb +43 -0
  104. data/test/test_functionreferenceparser.rb +11 -0
  105. data/test/test_include_graph.rb +640 -0
  106. data/test/test_include_pruner.rb +133 -0
  107. data/test/test_link_checker.rb +114 -0
  108. data/test/test_lookup_command.rb +135 -0
  109. data/test/test_markdown_bridge.rb +217 -0
  110. data/test/test_markdown_orchestrator.rb +478 -0
  111. data/test/test_markdown_to_rrd.rb +757 -0
  112. data/test/test_markdown_tree.rb +369 -0
  113. data/test/test_mdcompiler.rb +1276 -0
  114. data/test/test_mdparser.rb +538 -0
  115. data/test/test_method_screen.rb +166 -0
  116. data/test/test_method_since_calculator.rb +290 -0
  117. data/test/test_methoddatabase.rb +16 -0
  118. data/test/test_methodentry.rb +328 -0
  119. data/test/test_methodsignature.rb +3 -1
  120. data/test/test_methodsince_command.rb +168 -0
  121. data/test/test_nameutils.rb +22 -0
  122. data/test/test_preprocessor.rb +215 -0
  123. data/test/test_rdcompiler.rb +401 -30
  124. data/test/test_refsdatabase.rb +32 -0
  125. data/test/test_rrd_to_markdown.rb +968 -0
  126. data/test/test_rrdparser.rb +295 -2
  127. data/test/test_run_ruby_wasm.rb +54 -0
  128. data/test/test_run_worker_prelude.rb +83 -0
  129. data/test/test_runner.rb +51 -0
  130. data/test/test_search_index_generator.rb +513 -0
  131. data/test/test_search_screen.rb +48 -0
  132. data/test/test_searcher.rb +132 -0
  133. data/test/test_searchpage_command.rb +167 -0
  134. data/test/test_simplesearcher.rb +28 -0
  135. data/test/test_statichtml_command.rb +204 -0
  136. data/test/test_syntax_highlighter.rb +60 -0
  137. data/test/test_whole_file_gate.rb +175 -0
  138. data/theme/default/js/NOTICE +42 -0
  139. data/theme/default/js/run-worker.js +111 -0
  140. data/theme/default/js/run.js +350 -0
  141. data/theme/default/js/search_controller.js +134 -0
  142. data/theme/default/js/search_init.js +176 -0
  143. data/theme/default/js/search_navigation.js +110 -0
  144. data/theme/default/js/search_page.js +202 -0
  145. data/theme/default/js/search_ranker.js +244 -0
  146. data/theme/default/script.js +91 -18
  147. data/theme/default/search.css +149 -0
  148. data/theme/default/style.css +193 -21
  149. data/theme/default/syntax-highlight.css +8 -0
  150. data/theme/lillia/style.css +45 -1
  151. metadata +161 -20
  152. data/README +0 -32
@@ -19,15 +19,27 @@ class TestRDCompiler < Test::Unit::TestCase
19
19
  assert_equal(expected, @c.compile(src))
20
20
  end
21
21
 
22
- def assert_compiled_method_source(expected, src)
22
+ def assert_compiled_method_source(expected, src, names: [], since_map: {}, until_map: {})
23
23
  method_entry = Object.new
24
24
  mock(method_entry).source{ src }
25
25
  mock(method_entry).index_id.any_times{ "dummy" }
26
26
  mock(method_entry).defined?.any_times{ true }
27
27
  mock(method_entry).id.any_times{ "String/i.index._builtin" }
28
+ mock(method_entry).names.any_times{ names }
29
+ mock(method_entry).since_map.any_times{ since_map }
30
+ mock(method_entry).until_map.any_times{ until_map }
28
31
  assert_equal(expected, @c.compile_method(method_entry))
29
32
  end
30
33
 
34
+ # badge のカタログ訳(「Ruby %s から」等)を検証するテストで使う、
35
+ # 日本語カタログを読み込んだ compiler を作る(setup の @c はカタログ無しの
36
+ # C ロケールなので、_() はキーそのまま(英語)を返してしまう)
37
+ def ja_catalog_compiler
38
+ prefix = File.expand_path('../data/bitclust/catalog', __dir__)
39
+ catalog = BitClust::MessageCatalog.load_with_locales(prefix, ['ja_JP.UTF-8'])
40
+ BitClust::RDCompiler.new(@u, 1, {:database => @db, :catalog => catalog})
41
+ end
42
+
31
43
  def test_dlist
32
44
  src = <<'HERE'
33
45
  : t1
@@ -202,6 +214,47 @@ HERE
202
214
  assert_compiled_method_source(expected, src)
203
215
  end
204
216
 
217
+ # bitclust#250: template.lillia/library だけが compile_method(m, true) で
218
+ # 第2引数(@opt)を渡し、見出し先頭に「クラス名+typemark」を付ける。4.0
219
+ # 以降のドキュメントではこの prefix も "?." 表示に切り替わる(識別子である
220
+ # typemark ではなく、表示専用の display_typemark を経由する)
221
+ def test_method_with_opt_prefixes_class_name_and_display_typemark
222
+ klass = Object.new
223
+ mock(klass).name { 'Kernel' }
224
+
225
+ method_entry = Object.new
226
+ mock(method_entry).source { "--- mf\n\nfoo\n" }
227
+ mock(method_entry).index_id.any_times { 'dummy' }
228
+ mock(method_entry).defined?.any_times { true }
229
+ mock(method_entry).id.any_times { 'Kernel/m.mf._builtin' }
230
+ mock(method_entry).names.any_times { ['mf'] }
231
+ mock(method_entry).since_map.any_times { {} }
232
+ mock(method_entry).until_map.any_times { {} }
233
+ mock(method_entry).klass.any_times { klass }
234
+ mock(method_entry).display_typemark.any_times { '?.' }
235
+
236
+ html = @c.compile_method(method_entry, true)
237
+ assert_include(html, '<code>Kernel?.mf</code>')
238
+ end
239
+
240
+ # opt を渡さない通常経路(class/method/function 各テンプレート)は
241
+ # klass/display_typemark に一切触れず、prefix なしのまま(回帰防止:
242
+ # klass/display_typemark をスタブしていないので、誤って参照すると
243
+ # 未定義呼び出しとして失敗する)
244
+ def test_method_without_opt_omits_the_class_and_typemark_prefix
245
+ method_entry = Object.new
246
+ mock(method_entry).source { "--- mf\n\nfoo\n" }
247
+ mock(method_entry).index_id.any_times { 'dummy' }
248
+ mock(method_entry).defined?.any_times { true }
249
+ mock(method_entry).id.any_times { 'Kernel/m.mf._builtin' }
250
+ mock(method_entry).names.any_times { ['mf'] }
251
+ mock(method_entry).since_map.any_times { {} }
252
+ mock(method_entry).until_map.any_times { {} }
253
+
254
+ html = @c.compile_method(method_entry)
255
+ assert_include(html, '<code>mf</code>')
256
+ end
257
+
205
258
  def test_method_with_emlist
206
259
  src = <<'HERE'
207
260
  --- <=>
@@ -359,10 +412,8 @@ HERE
359
412
  <dt class='method-param'>[PARAM] arg:</dt>
360
413
  <dd>
361
414
  dsc1
362
- <pre class="highlight ruby">
363
415
  <span class="caption">This is caption</span>
364
- <code>
365
- dsc2
416
+ <pre class="highlight ruby"><code>dsc2
366
417
  dsc3
367
418
  </code></pre>
368
419
  </dd>
@@ -387,10 +438,8 @@ HERE
387
438
  <p>
388
439
  abs
389
440
  </p>
390
- <pre class="highlight ruby">
391
441
  <span class="caption">description</span>
392
- <code>
393
- <span class="nb">puts</span> <span class="s2">"</span><span class="s2">text</span><span class="s2">"</span>
442
+ <pre class="highlight ruby"><code><span class="nb">puts</span> <span class="s2">"</span><span class="s2">text</span><span class="s2">"</span>
394
443
  </code></pre>
395
444
  </dd>
396
445
  HERE
@@ -412,9 +461,7 @@ HERE
412
461
  <p>
413
462
  abs
414
463
  </p>
415
- <pre class="highlight ruby">
416
- <code>
417
- <span class="nb">puts</span> <span class="s2">"</span><span class="s2">text</span><span class="s2">"</span>
464
+ <pre class="highlight ruby"><code><span class="nb">puts</span> <span class="s2">"</span><span class="s2">text</span><span class="s2">"</span>
418
465
  </code></pre>
419
466
  </dd>
420
467
  HERE
@@ -427,8 +474,15 @@ HERE
427
474
  //emlist[][ruby]{
428
475
  class <<obj
429
476
  def foo
477
+ Object.new
430
478
  end
431
479
  end
480
+ class << Object.new
481
+ end
482
+ class << self
483
+ end
484
+ class << FOO::BAR::BAZ
485
+ end
432
486
  p Foo.singleton_method(:foo)
433
487
  //}
434
488
  end
@@ -436,12 +490,17 @@ HERE
436
490
  expected = <<'HERE'
437
491
  <dt class="method-heading" id="dummy"><code>singleton_method(name) -&gt; Method</code><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
438
492
  <dd class="method-description">
439
- <pre class="highlight ruby">
440
- <code>
441
- <span class="k">class</span> <span class="o">&lt;&lt;</span><span class="nn"></span><span class="o"></span><span class="nc">obj</span>
493
+ <pre class="highlight ruby"><code><span class="k">class</span> <span class="o">&lt;&lt;</span>obj
442
494
  <span class="k">def</span> <span class="nf">foo</span>
495
+ <span class="no">Object</span><span class="p">.</span><span class="nf">new</span>
443
496
  <span class="k">end</span>
444
497
  <span class="k">end</span>
498
+ <span class="k">class</span> <span class="o">&lt;&lt;</span> <span class="no">Object</span><span class="p">.</span><span class="nf">new</span>
499
+ <span class="k">end</span>
500
+ <span class="k">class</span> <span class="o">&lt;&lt;</span> <span class="nc">self</span>
501
+ <span class="k">end</span>
502
+ <span class="k">class</span> <span class="o">&lt;&lt;</span> <span class="no">FOO</span><span class="o">::</span><span class="no">BAR</span><span class="o">::</span><span class="no">BAZ</span>
503
+ <span class="k">end</span>
445
504
  <span class="nb">p</span> <span class="no">Foo</span><span class="p">.</span><span class="nf">singleton_method</span><span class="p">(</span><span class="ss">:foo</span><span class="p">)</span>
446
505
  </code></pre>
447
506
  <p>
@@ -473,6 +532,176 @@ HERE
473
532
  assert_compiled_method_source(expected, src)
474
533
  end
475
534
 
535
+ # bitclust#132 P3: since/until バージョンバッジ。名前ごとの since_map/
536
+ # until_map が空なら(既存の全テストがそう)何も出ない = 従来どおりの
537
+ # 出力(このケースは assert_compiled_method_source のデフォルト引数で
538
+ # 既存テストとして担保済み)。以下は非空の場合の描画を確認する
539
+
540
+ def test_method_signature_since_badge_uniform_single_name
541
+ @c = ja_catalog_compiler
542
+ src = <<'HERE'
543
+ --- hoge
544
+ foo
545
+ HERE
546
+ expected = <<'HERE'
547
+ <dt class="method-heading" id="dummy"><code>hoge</code><span class="method-since-badge">Ruby 2.0.0 から</span><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
548
+ <dd class="method-description">
549
+ <p>
550
+ foo
551
+ </p>
552
+ </dd>
553
+ HERE
554
+ assert_compiled_method_source(expected, src,
555
+ names: ['hoge'], since_map: {'hoge' => '2.0.0'})
556
+ end
557
+
558
+ # 別名(alias)の全名が同じバージョンを持つ「一様」なケースでは、
559
+ # バッジは最初の dt にだけ出す(2つ目以降の dt では繰り返さない)
560
+ def test_method_signature_since_badge_uniform_alias
561
+ @c = ja_catalog_compiler
562
+ src = <<'HERE'
563
+ --- hoge1
564
+ --- hoge2
565
+ bar
566
+ HERE
567
+ expected = <<'HERE'
568
+ <dt class="method-heading" id="dummy"><code>hoge1</code><span class="method-since-badge">Ruby 2.0.0 から</span><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
569
+ <dt class="method-heading"><code>hoge2</code></dt>
570
+ <dd class="method-description">
571
+ <p>
572
+ bar
573
+ </p>
574
+ </dd>
575
+ HERE
576
+ assert_compiled_method_source(expected, src,
577
+ names: ['hoge1', 'hoge2'], since_map: {'hoge1' => '2.0.0', 'hoge2' => '2.0.0'})
578
+ end
579
+
580
+ # 別名の一部にしか値が無い「混在」なケースでは、一様とはみなさず名前ごとに
581
+ # 判定する。ここでは最初の名前(hoge1)ではなく2番目(hoge2)にだけ値がある
582
+ # ケースで、バッジが正しく hoge2 の dt にだけ付くことを確認する(2番目
583
+ # だから、ではなく「最初の dt だから」で誤って出ていないことの確認)
584
+ def test_method_signature_since_badge_mixed_alias
585
+ @c = ja_catalog_compiler
586
+ src = <<'HERE'
587
+ --- hoge1
588
+ --- hoge2
589
+ bar
590
+ HERE
591
+ expected = <<'HERE'
592
+ <dt class="method-heading" id="dummy"><code>hoge1</code><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
593
+ <dt class="method-heading"><code>hoge2</code><span class="method-since-badge">Ruby 2.0.0 から</span></dt>
594
+ <dd class="method-description">
595
+ <p>
596
+ bar
597
+ </p>
598
+ </dd>
599
+ HERE
600
+ assert_compiled_method_source(expected, src,
601
+ names: ['hoge1', 'hoge2'], since_map: {'hoge2' => '2.0.0'})
602
+ end
603
+
604
+ def test_method_signature_until_badge
605
+ @c = ja_catalog_compiler
606
+ src = <<'HERE'
607
+ --- hoge
608
+ foo
609
+ HERE
610
+ expected = <<'HERE'
611
+ <dt class="method-heading" id="dummy"><code>hoge</code><span class="method-until-badge">Ruby 4.0 で削除</span><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
612
+ <dd class="method-description">
613
+ <p>
614
+ foo
615
+ </p>
616
+ </dd>
617
+ HERE
618
+ assert_compiled_method_source(expected, src,
619
+ names: ['hoge'], until_map: {'hoge' => '4.0'})
620
+ end
621
+
622
+ # 同じ dt に since と until の両方が付く場合、since→until の順で
623
+ # 半角スペース1つ区切りで並ぶ
624
+ def test_method_signature_since_and_until_badges_on_same_dt
625
+ @c = ja_catalog_compiler
626
+ src = <<'HERE'
627
+ --- hoge
628
+ foo
629
+ HERE
630
+ expected = <<'HERE'
631
+ <dt class="method-heading" id="dummy"><code>hoge</code><span class="method-since-badge">Ruby 2.0.0 から</span> <span class="method-until-badge">Ruby 4.0 で削除</span><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
632
+ <dd class="method-description">
633
+ <p>
634
+ foo
635
+ </p>
636
+ </dd>
637
+ HERE
638
+ assert_compiled_method_source(expected, src,
639
+ names: ['hoge'], since_map: {'hoge' => '2.0.0'}, until_map: {'hoge' => '4.0'})
640
+ end
641
+
642
+ # bitclust#132: 特殊変数のシグネチャ名($ 付き)はエントリの names
643
+ # ($ なし)へ正規化して since_map を引く。正規化が無いと mixed 経路で
644
+ # 該当 dt にバッジが出ない
645
+ def test_method_signature_since_badge_special_variable_alias
646
+ @c = ja_catalog_compiler
647
+ src = <<'HERE'
648
+ --- $0
649
+ --- $PROGRAM_NAME
650
+ bar
651
+ HERE
652
+ expected = <<'HERE'
653
+ <dt class="method-heading" id="dummy"><code>$0</code><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
654
+ <dt class="method-heading"><code>$PROGRAM_NAME</code><span class="method-since-badge">Ruby 1.9.1 から</span></dt>
655
+ <dd class="method-description">
656
+ <p>
657
+ bar
658
+ </p>
659
+ </dd>
660
+ HERE
661
+ assert_compiled_method_source(expected, src,
662
+ names: ['0', 'PROGRAM_NAME'], since_map: {'PROGRAM_NAME' => '1.9.1'})
663
+ end
664
+
665
+ # since_map の空文字値は「明示的に不明」(著者が {: since=""} で指定)。
666
+ # バッジは表示しない(bitclust#132: ドキュメント追加が遅れて算出が誤る場合の抑止)
667
+ def test_method_signature_empty_since_suppresses_badge
668
+ @c = ja_catalog_compiler
669
+ src = <<'HERE'
670
+ --- hoge
671
+ foo
672
+ HERE
673
+ expected = <<'HERE'
674
+ <dt class="method-heading" id="dummy"><code>hoge</code><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
675
+ <dd class="method-description">
676
+ <p>
677
+ foo
678
+ </p>
679
+ </dd>
680
+ HERE
681
+ assert_compiled_method_source(expected, src,
682
+ names: ['hoge'], since_map: {'hoge' => ''})
683
+ end
684
+
685
+ def test_method_signature_empty_since_mixed_alias
686
+ @c = ja_catalog_compiler
687
+ src = <<'HERE'
688
+ --- hoge1
689
+ --- hoge2
690
+ bar
691
+ HERE
692
+ expected = <<'HERE'
693
+ <dt class="method-heading" id="dummy"><code>hoge1</code><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
694
+ <dt class="method-heading"><code>hoge2</code><span class="method-since-badge">Ruby 2.0.0 から</span></dt>
695
+ <dd class="method-description">
696
+ <p>
697
+ bar
698
+ </p>
699
+ </dd>
700
+ HERE
701
+ assert_compiled_method_source(expected, src,
702
+ names: ['hoge1', 'hoge2'], since_map: {'hoge1' => '', 'hoge2' => '2.0.0'})
703
+ end
704
+
476
705
  def test_ulist_simple
477
706
  src = <<'HERE'
478
707
  * hoge1
@@ -525,13 +754,15 @@ HERE
525
754
  src = <<HERE
526
755
  * hoge1
527
756
  * fuga1
757
+ bar
528
758
  * hoge2
529
759
  * fuga2
530
760
  HERE
531
761
  expected = <<HERE
532
762
  <ul>
533
763
  <li>hoge1<ul>
534
- <li>fuga1</li>
764
+ <li>fuga1
765
+ bar</li>
535
766
  </ul>
536
767
  </li>
537
768
  <li>hoge2<ul>
@@ -539,7 +770,6 @@ HERE
539
770
  </ul>
540
771
  </li>
541
772
  </ul>
542
-
543
773
  HERE
544
774
  assert_compiled_source(expected, src)
545
775
  end
@@ -578,7 +808,6 @@ HERE
578
808
  </ol>
579
809
  </li>
580
810
  </ol>
581
-
582
811
  HERE
583
812
  assert_compiled_source(expected, src)
584
813
  end
@@ -605,7 +834,6 @@ HERE
605
834
  </ol>
606
835
  </li>
607
836
  </ul>
608
-
609
837
  HERE
610
838
  assert_compiled_source(expected, src)
611
839
  end
@@ -626,6 +854,8 @@ HERE
626
854
  <li>boo1</li>
627
855
  </ol>
628
856
  </li>
857
+ </ol>
858
+ </li>
629
859
  <li>hoge2<ol>
630
860
  <li>fuga2<ol>
631
861
  <li>boo2</li>
@@ -634,9 +864,6 @@ HERE
634
864
  </ol>
635
865
  </li>
636
866
  </ol>
637
- </li>
638
- </ol>
639
-
640
867
  HERE
641
868
  assert_compiled_source(expected, src)
642
869
  end
@@ -684,20 +911,25 @@ HERE
684
911
  "instance method" => ['[[m:String#dump]]', '<a href="dummy/method/String/i/dump">String#dump</a>'],
685
912
  "indexer" => ['[[m:String#[] ]]', '<a href="dummy/method/String/i/=5b=5d">String#[]</a>'],
686
913
  "C API" => ['[[f:rb_ary_new3]]', '<a href="dummy/function/rb_ary_new3">rb_ary_new3</a>'],
687
- "C API root" => ['[[f:/]]', '<a href="dummy/function/">All C API</a>'],
688
- "C API index" => ['[[f:_index]]', '<a href="dummy/function/">All C API</a>'],
914
+ "C API root" => ['[[f:/]]', '<a href="dummy/function/">Function Index</a>'],
915
+ "C API index" => ['[[f:_index]]', '<a href="dummy/function/">Function Index</a>'],
689
916
  "standard library" => ['[[lib:jcode]]', '<a href="dummy/library/jcode">jcode</a>'],
917
+ "library root" => ['[[lib:/]]', '<a href="dummy/library/">Library Index</a>'],
918
+ "library index" => ['[[lib:_index]]', '<a href="dummy/library/_index">Library Index</a>'],
919
+ "builtin library" => ['[[lib:_builtin]]', '<a href="dummy/library/_builtin">Builtin Library</a>'],
690
920
  "man command" => ['[[man:tr(1)]]', '<a class="external" href="http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html">tr(1)</a>'],
691
921
  "man header" => ['[[man:sys/socket.h(header)]]', '<a class="external" href="http://www.opengroup.org/onlinepubs/009695399/basedefs/sys/socket.h.html">sys/socket.h(header)</a>'],
692
922
  "man system call" => ['[[man:fopen(3linux)]]', '<a class="external" href="http://man7.org/linux/man-pages/man3/fopen.3.html">fopen(3linux)</a>'],
693
923
  "RFC" => ['[[RFC:2822]]', '<a class="external" href="https://tools.ietf.org/html/rfc2822">[RFC2822]</a>'],
924
+ "ISO standard" => ['[[ISO:8601]]', 'ISO 8601'],
925
+ "JIS standard" => ['[[JIS:X 0301]]', 'JIS X 0301'],
694
926
  "special var $~" => ['[[m:$~]]', '<a href="dummy/method/Kernel/v/=7e">$~</a>'],
695
927
  "special var $," => ['[[m:$,]]', '<a href="dummy/method/Kernel/v/=2c">$,</a>'],
696
928
  "extra close bracket" => ['[[c:String]]]', '<a href="dummy/class/String">String</a>]'],
697
929
  "continuity" => ['[[c:String]][[c:String]]', '<a href="dummy/class/String">String</a><a href="dummy/class/String">String</a>'],
698
930
  "constant" => ['[[m:File::SEPARATOR]]', '<a href="dummy/method/File/c/SEPARATOR">File::SEPARATOR</a>'],
699
931
  "url" => ['[[url:http://i.loveruby.net]]', '<a class="external" href="http://i.loveruby.net">http://i.loveruby.net</a>'],
700
- "ruby-list" => ['[[ruby-list:12345]]', '<a class="external" href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/12345">[ruby-list:12345]</a>'],
932
+ "ruby-list" => ['[[ruby-list:12345]]', '<a class="external" href="https://blade.ruby-lang.org/ruby-list/12345">[ruby-list:12345]</a>'],
701
933
  "bugs.r-l.o feature" => ['[[feature:12345]]', '<a class="external" href="https://bugs.ruby-lang.org/issues/12345">[feature#12345]</a>'],
702
934
  "bugs.r-l.o bug" => ['[[bug:12345]]', '<a class="external" href="https://bugs.ruby-lang.org/issues/12345">[bug#12345]</a>'],
703
935
  "bugs.r-l.o misc" => ['[[misc:12345]]', '<a class="external" href="https://bugs.ruby-lang.org/issues/12345">[misc#12345]</a>'])
@@ -706,18 +938,147 @@ HERE
706
938
  assert_equal(expected, @c.send(:compile_text, target), target)
707
939
  end
708
940
 
709
- data("doc" => ['[[d:hoge/bar]]', '<a href="dummy/hoge/bar">.*</a>'],
710
- "ref doc" => ['[[ref:d:hoge/bar#frag]]', '<a href="dummy/hoge/bar#frag">.*</a>'],
711
- "ref class" => ['[[ref:c:Hoge#frag]]', '<a href="dummy/class/Hoge#frag">.*</a>'],
712
- "ref special var" => ['[[ref:m:$~#frag]]', '<a href="dummy/method/Kernel/v/=7e#frag">.*</a>'],
713
- "ref library" => ['[[ref:lib:jcode#frag]]', '<a href="dummy/library/jcode#frag">.*</a>'],
714
- "ref class error" => ['[[ref:c:Hoge]]', 'compileerror'],
715
- "ref ref" => ['[[ref:ref:hoge/bar#frag]]', 'compileerror'],)
941
+ # bitclust#282: 参照のデフォルトラベル(記載どおりの spec 文字列)も
942
+ # 表示専用なので、module function ".#" は DB バージョンが 4.0 以降
943
+ # なら "?." で表示する(#250/#277 の display_typemark と同じ選択規則)。
944
+ # URL・アンカー(識別子)は変えない。
945
+ data("pre-4.0 keeps .#" => ['3.4', 'Kernel.#at_exit'],
946
+ "4.0 shows ?." => ['4.0', 'Kernel?.at_exit'],
947
+ "4.1 shows ?." => ['4.1', 'Kernel?.at_exit'])
948
+ def test_bracket_link_module_function_display(data)
949
+ version, label = data
950
+ db = BitClust::MethodDatabase.dummy("version" => version)
951
+ c = BitClust::RDCompiler.new(@u, 1, {:database => db})
952
+ assert_equal(%Q(<a href="dummy/method/Kernel/m/at_exit">#{label}</a>),
953
+ c.send(:compile_text, '[[m:Kernel.#at_exit]]'))
954
+ end
955
+
956
+ def test_reference_link_module_function_title_display
957
+ # refs テーブルに見出しがある場合の「spec/見出し」ラベルの spec 側も
958
+ # 4.0 以降は "?." 表示にする(doctree に現時点で用例は無い理論エッジ
959
+ # だが、デフォルトラベルと同じ選択規則で一貫させる)
960
+ refs = Object.new
961
+ def refs.[](type, id, frag) = '深掘り'
962
+ db = BitClust::MethodDatabase.dummy("version" => "4.0")
963
+ stub(db).refs { refs }
964
+ c = BitClust::RDCompiler.new(@u, 1, {:database => db})
965
+ assert_equal(%Q(<a href="dummy/method/Kernel/m/at_exit#frag">Kernel?.at_exit/深掘り</a>),
966
+ c.send(:compile_text, '[[ref:m:Kernel.#at_exit#frag]]'))
967
+ end
968
+
969
+ def test_bracket_link_other_typemarks_unchanged_at_4_0
970
+ db = BitClust::MethodDatabase.dummy("version" => "4.0")
971
+ c = BitClust::RDCompiler.new(@u, 1, {:database => db})
972
+ assert_equal('<a href="dummy/method/String/s/new">String.new</a>',
973
+ c.send(:compile_text, '[[m:String.new]]'))
974
+ assert_equal('<a href="dummy/method/String/i/dump">String#dump</a>',
975
+ c.send(:compile_text, '[[m:String#dump]]'))
976
+ assert_equal('<a href="dummy/method/Kernel/v/=7e">$~</a>',
977
+ c.send(:compile_text, '[[m:$~]]'))
978
+ end
979
+
980
+ data("library root" => ['[[lib:/]]', '<a href="dummy/library/">ライブラリ一覧</a>'],
981
+ "builtin library" => ['[[lib:_builtin]]', '<a href="dummy/library/_builtin">組み込みライブラリ</a>'],
982
+ "C API root" => ['[[f:/]]', '<a href="dummy/function/">関数一覧</a>'])
983
+ def test_bracket_link_with_catalog(data)
984
+ target, expected = data
985
+ prefix = File.expand_path('../data/bitclust/catalog', __dir__)
986
+ catalog = BitClust::MessageCatalog.load_with_locales(prefix, ['ja_JP.UTF-8'])
987
+ compiler = BitClust::RDCompiler.new(@u, 1, {:database => @db, :catalog => catalog})
988
+ assert_equal(expected, compiler.send(:compile_text, target), target)
989
+ end
990
+
991
+ data("doc" => ['[[d:hoge/bar]]', '<a href="dummy/hoge/bar">.*</a>'],
992
+ "ref doc" => ['[[ref:d:hoge/bar#frag]]', '<a href="dummy/hoge/bar#frag">.*</a>'],
993
+ "ref doc hyphen frag" => ['[[ref:d:hoge/bar#thread-safe]]', '<a href="dummy/hoge/bar#thread-safe">.*</a>'],
994
+ "ref class" => ['[[ref:c:Hoge#frag]]', '<a href="dummy/class/Hoge#frag">.*</a>'],
995
+ "ref special var" => ['[[ref:m:$~#frag]]', '<a href="dummy/method/Kernel/v/=7e#frag">.*</a>'],
996
+ "ref library" => ['[[ref:lib:jcode#frag]]', '<a href="dummy/library/jcode#frag">.*</a>'],
997
+ "ref class error" => ['[[ref:c:Hoge]]', 'compileerror'],
998
+ "ref ref" => ['[[ref:ref:hoge/bar#frag]]', 'compileerror'],)
716
999
  def test_bracket_link_doc(data)
717
1000
  target, expected = data
718
1001
  assert_match(/#{expected}/, @c.send(:compile_text, target), target)
719
1002
  end
720
1003
 
1004
+ def test_reference_link_same_page_hyphen_fragment
1005
+ # [ref:frag](type:name 無し)は同一ページ内アンカーへのリンク。
1006
+ # ハイフン入りフラグメント(doctree/manual の {#id} アンカーに合わせる)
1007
+ entry = BitClust::DocEntry.new(@db, 'glossary')
1008
+ entry.source = "### スレッドセーフ {#thread-safe}\n\n本文。\n"
1009
+ refs = BitClust::RefsDatabase.new
1010
+ refs.extract(entry)
1011
+ stub(@db).refs { refs }
1012
+ compiler = BitClust::RDCompiler.new(@u, 1, {:database => @db, :entry => entry})
1013
+ assert_equal('<a href="#thread-safe">スレッドセーフ</a>',
1014
+ compiler.send(:reference_link, 'thread-safe'))
1015
+ end
1016
+
1017
+ def test_nomethod_is_not_rendered
1018
+ src = <<'HERE'
1019
+ --- to_a -> Array
1020
+ {: nomethod}
1021
+
1022
+ 説明のためここに記載しています。
1023
+ HERE
1024
+ method_entry = Object.new
1025
+ mock(method_entry).source { src }
1026
+ mock(method_entry).index_id.any_times { "dummy" }
1027
+ mock(method_entry).defined?.any_times { true }
1028
+ mock(method_entry).id.any_times { "String/i.index._builtin" }
1029
+ mock(method_entry).names.any_times { [] }
1030
+ mock(method_entry).since_map.any_times { {} }
1031
+ mock(method_entry).until_map.any_times { {} }
1032
+ html = @c.compile_method(method_entry)
1033
+ assert_not_include(html, 'UNKNOWN_META_INFO')
1034
+ assert_not_include(html, '{:')
1035
+ assert_include(html, '説明のためここに記載しています。')
1036
+ end
1037
+
1038
+ def test_attribute_lines_between_alias_signatures_are_not_rendered
1039
+ src = <<'HERE'
1040
+ --- to_a -> Array
1041
+ {: nomethod}
1042
+ --- to_a2 -> Array
1043
+ {: nomethod}
1044
+
1045
+ 説明のためここに記載しています。
1046
+ HERE
1047
+ method_entry = Object.new
1048
+ mock(method_entry).source { src }
1049
+ mock(method_entry).index_id.any_times { "dummy" }
1050
+ mock(method_entry).defined?.any_times { true }
1051
+ mock(method_entry).id.any_times { "String/i.index._builtin" }
1052
+ mock(method_entry).names.any_times { [] }
1053
+ mock(method_entry).since_map.any_times { {} }
1054
+ mock(method_entry).until_map.any_times { {} }
1055
+ html = @c.compile_method(method_entry)
1056
+ assert_not_include(html, '{:')
1057
+ assert_include(html, 'to_a2')
1058
+ assert_include(html, '説明のためここに記載しています。')
1059
+ # 別名はひとつのエントリとして描画される(dt 2つ + dd 1つ)
1060
+ assert_equal(1, html.scan(/<dd class="method-description">/).size)
1061
+ assert_equal(2, html.scan(/<dt class="method-heading"/).size)
1062
+ end
1063
+
1064
+ def test_undef_attribute_renders_message
1065
+ src = <<'HERE'
1066
+ --- <=>(other) -> -1 | 0 | 1 | nil
1067
+ {: undef}
1068
+ HERE
1069
+ method_entry = Object.new
1070
+ mock(method_entry).source { src }
1071
+ mock(method_entry).index_id.any_times { "dummy" }
1072
+ mock(method_entry).defined?.any_times { true }
1073
+ mock(method_entry).id.any_times { "String/i.index._builtin" }
1074
+ mock(method_entry).names.any_times { [] }
1075
+ mock(method_entry).since_map.any_times { {} }
1076
+ mock(method_entry).until_map.any_times { {} }
1077
+ html = @c.compile_method(method_entry)
1078
+ assert_not_include(html, '{:')
1079
+ assert_include(html, 'このメソッドは定義されていません。')
1080
+ end
1081
+
721
1082
  def test_array_join
722
1083
  src = <<'HERE'
723
1084
  --- join(sep = $,) -> String
@@ -853,6 +1214,16 @@ HERE
853
1214
  :method_id => "ARGF.class/i.binmode.argf._builtin",
854
1215
  :version => "2.0.0",
855
1216
  :expected => "https://docs.ruby-lang.org/en/2.0.0/ARGF.html#method-i-binmode"
1217
+ },
1218
+ "Kernel.#trace_var" => {
1219
+ :method_id => "Kernel/m.trace_var._builtin",
1220
+ :version => "2.0.0",
1221
+ :expected => "https://docs.ruby-lang.org/en/2.0.0/Kernel.html#method-i-trace_var"
1222
+ },
1223
+ "Math.#sqrt" => {
1224
+ :method_id => "Math/m.sqrt._builtin",
1225
+ :version => "2.0.0",
1226
+ :expected => "https://docs.ruby-lang.org/en/2.0.0/Math.html#method-c-sqrt"
856
1227
  })
857
1228
  def test_rdoc_url(data)
858
1229
  assert_equal(data[:expected], @c.rdoc_url(data[:method_id], data[:version]))
@@ -81,4 +81,36 @@ HERE
81
81
  assert_equal(s.upcase, db.refs['class', 'ARGF', s])
82
82
  end
83
83
  end
84
+
85
+ # rd 形式の [a:xxx] アンカーもハイフンを含められる(doctree/bitclust#(このPR))
86
+ S3 = <<HERE
87
+ ===[a:with-hyphen] With Hyphen
88
+ HERE
89
+
90
+ def test_make_refs_rd_anchor_with_hyphen
91
+ _, db = BitClust::RRDParser.parse(S3, 'dummy')
92
+ db.make_refs
93
+ assert_equal('With Hyphen', db.refs['library', 'dummy', 'with-hyphen'])
94
+ end
95
+
96
+ # md ソースの見出しアンカー {#xxx} 収集はハイフンを許容する
97
+ # (doctree/manual の glossary.md 等、用語アンカーはハイフン区切り)
98
+ def test_extract_markdown_heading_anchor_with_hyphen
99
+ db = BitClust::MethodDatabase.dummy("version" => "3.4.0")
100
+ entry = BitClust::DocEntry.new(db, 'glossary')
101
+ entry.source = "### スレッドセーフ {#thread-safe}\n\n本文。\n"
102
+ refs = BitClust::RefsDatabase.new
103
+ refs.extract(entry)
104
+ assert_equal('スレッドセーフ', refs['doc', 'glossary', 'thread-safe'])
105
+ end
106
+
107
+ # 従来のアンダースコア・単語アンカーの回帰が無いことも確認する
108
+ def test_extract_markdown_heading_anchor_with_underscore
109
+ db = BitClust::MethodDatabase.dummy("version" => "3.4.0")
110
+ entry = BitClust::DocEntry.new(db, 'glossary')
111
+ entry.source = "### 見出し {#my_anchor}\n\n本文。\n"
112
+ refs = BitClust::RefsDatabase.new
113
+ refs.extract(entry)
114
+ assert_equal('見出し', refs['doc', 'glossary', 'my_anchor'])
115
+ end
84
116
  end