bitclust-core 1.2.6 → 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 (160) 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 +49 -5
  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 +17 -17
  24. data/lib/bitclust/capi_converter.rb +20 -0
  25. data/lib/bitclust/classentry.rb +68 -17
  26. data/lib/bitclust/compat.rb +3 -2
  27. data/lib/bitclust/completion.rb +59 -27
  28. data/lib/bitclust/crossrubyutils.rb +9 -5
  29. data/lib/bitclust/database.rb +29 -8
  30. data/lib/bitclust/doc_converter.rb +63 -0
  31. data/lib/bitclust/docentry.rb +2 -1
  32. data/lib/bitclust/entity_splitter.rb +221 -0
  33. data/lib/bitclust/entry.rb +48 -7
  34. data/lib/bitclust/exception.rb +1 -0
  35. data/lib/bitclust/functiondatabase.rb +14 -1
  36. data/lib/bitclust/functionentry.rb +6 -1
  37. data/lib/bitclust/functionreferenceparser.rb +5 -4
  38. data/lib/bitclust/generators/epub.rb +11 -3
  39. data/lib/bitclust/htmlutils.rb +2 -1
  40. data/lib/bitclust/include_graph.rb +375 -0
  41. data/lib/bitclust/include_pruner.rb +144 -0
  42. data/lib/bitclust/interface.rb +2 -1
  43. data/lib/bitclust/libraryentry.rb +9 -7
  44. data/lib/bitclust/lineinput.rb +8 -5
  45. data/lib/bitclust/link_checker.rb +179 -0
  46. data/lib/bitclust/markdown_bridge.rb +186 -0
  47. data/lib/bitclust/markdown_orchestrator.rb +267 -0
  48. data/lib/bitclust/markdown_to_rrd.rb +824 -0
  49. data/lib/bitclust/markdown_tree.rb +217 -0
  50. data/lib/bitclust/mdcompiler.rb +883 -0
  51. data/lib/bitclust/mdparser.rb +347 -0
  52. data/lib/bitclust/messagecatalog.rb +4 -3
  53. data/lib/bitclust/method_since_calculator.rb +117 -0
  54. data/lib/bitclust/methoddatabase.rb +125 -14
  55. data/lib/bitclust/methodentry.rb +130 -7
  56. data/lib/bitclust/methodid.rb +13 -11
  57. data/lib/bitclust/methodsignature.rb +11 -4
  58. data/lib/bitclust/nameutils.rb +42 -22
  59. data/lib/bitclust/parseutils.rb +1 -0
  60. data/lib/bitclust/preprocessor.rb +70 -32
  61. data/lib/bitclust/progress_bar.rb +1 -0
  62. data/lib/bitclust/rdcompiler.rb +197 -96
  63. data/lib/bitclust/refsdatabase.rb +24 -8
  64. data/lib/bitclust/reloadable_request_handler.rb +72 -0
  65. data/lib/bitclust/requesthandler.rb +22 -16
  66. data/lib/bitclust/ridatabase.rb +11 -4
  67. data/lib/bitclust/rrd_to_markdown.rb +925 -0
  68. data/lib/bitclust/rrdparser.rb +197 -30
  69. data/lib/bitclust/runner.rb +18 -2
  70. data/lib/bitclust/screen.rb +81 -11
  71. data/lib/bitclust/search_index_generator.rb +288 -0
  72. data/lib/bitclust/searcher.rb +72 -22
  73. data/lib/bitclust/server.rb +6 -1
  74. data/lib/bitclust/silent_progress_bar.rb +1 -0
  75. data/lib/bitclust/simplesearcher.rb +25 -12
  76. data/lib/bitclust/subcommand.rb +8 -1
  77. data/lib/bitclust/subcommands/ancestors_command.rb +10 -2
  78. data/lib/bitclust/subcommands/checklink_command.rb +54 -0
  79. data/lib/bitclust/subcommands/chm_command.rb +16 -7
  80. data/lib/bitclust/subcommands/classes_command.rb +6 -0
  81. data/lib/bitclust/subcommands/epub_command.rb +1 -0
  82. data/lib/bitclust/subcommands/extract_command.rb +6 -0
  83. data/lib/bitclust/subcommands/htmlfile_command.rb +22 -7
  84. data/lib/bitclust/subcommands/init_command.rb +5 -1
  85. data/lib/bitclust/subcommands/list_command.rb +13 -4
  86. data/lib/bitclust/subcommands/lookup_command.rb +29 -9
  87. data/lib/bitclust/subcommands/methods_command.rb +11 -2
  88. data/lib/bitclust/subcommands/methodsince_command.rb +80 -0
  89. data/lib/bitclust/subcommands/preproc_command.rb +6 -0
  90. data/lib/bitclust/subcommands/property_command.rb +3 -1
  91. data/lib/bitclust/subcommands/query_command.rb +1 -0
  92. data/lib/bitclust/subcommands/searchpage_command.rb +102 -0
  93. data/lib/bitclust/subcommands/server_command.rb +16 -10
  94. data/lib/bitclust/subcommands/setup_command.rb +25 -10
  95. data/lib/bitclust/subcommands/statichtml_command.rb +132 -6
  96. data/lib/bitclust/subcommands/update_command.rb +111 -2
  97. data/lib/bitclust/syntax_highlighter.rb +52 -5
  98. data/lib/bitclust/textutils.rb +4 -3
  99. data/lib/bitclust/version.rb +2 -1
  100. data/lib/bitclust/version_badges.rb +90 -0
  101. data/lib/bitclust/whole_file_gate.rb +137 -0
  102. data/lib/bitclust.rb +1 -0
  103. data/test/test_app.rb +269 -0
  104. data/test/test_bitclust.rb +2 -0
  105. data/test/test_capi_converter.rb +91 -0
  106. data/test/test_class_screen.rb +413 -0
  107. data/test/test_copy_doc_md.rb +53 -0
  108. data/test/test_doc_converter.rb +78 -0
  109. data/test/test_entity_splitter.rb +231 -0
  110. data/test/test_entry.rb +207 -2
  111. data/test/test_eol_warning.rb +43 -0
  112. data/test/test_functionreferenceparser.rb +11 -0
  113. data/test/test_include_graph.rb +640 -0
  114. data/test/test_include_pruner.rb +133 -0
  115. data/test/test_link_checker.rb +114 -0
  116. data/test/test_lookup_command.rb +135 -0
  117. data/test/test_markdown_bridge.rb +217 -0
  118. data/test/test_markdown_orchestrator.rb +478 -0
  119. data/test/test_markdown_to_rrd.rb +757 -0
  120. data/test/test_markdown_tree.rb +369 -0
  121. data/test/test_mdcompiler.rb +1276 -0
  122. data/test/test_mdparser.rb +538 -0
  123. data/test/test_method_screen.rb +166 -0
  124. data/test/test_method_since_calculator.rb +290 -0
  125. data/test/test_methoddatabase.rb +16 -0
  126. data/test/test_methodentry.rb +328 -0
  127. data/test/test_methodsignature.rb +3 -1
  128. data/test/test_methodsince_command.rb +168 -0
  129. data/test/test_nameutils.rb +22 -0
  130. data/test/test_preprocessor.rb +215 -0
  131. data/test/test_rdcompiler.rb +429 -27
  132. data/test/test_refsdatabase.rb +32 -0
  133. data/test/test_rrd_to_markdown.rb +968 -0
  134. data/test/test_rrdparser.rb +295 -2
  135. data/test/test_run_ruby_wasm.rb +54 -0
  136. data/test/test_run_worker_prelude.rb +83 -0
  137. data/test/test_runner.rb +51 -0
  138. data/test/test_search_index_generator.rb +513 -0
  139. data/test/test_search_screen.rb +48 -0
  140. data/test/test_searcher.rb +153 -0
  141. data/test/test_searchpage_command.rb +167 -0
  142. data/test/test_simplesearcher.rb +28 -0
  143. data/test/test_statichtml_command.rb +204 -0
  144. data/test/test_syntax_highlighter.rb +60 -0
  145. data/test/test_whole_file_gate.rb +175 -0
  146. data/theme/default/js/NOTICE +42 -0
  147. data/theme/default/js/run-worker.js +111 -0
  148. data/theme/default/js/run.js +350 -0
  149. data/theme/default/js/search_controller.js +134 -0
  150. data/theme/default/js/search_init.js +176 -0
  151. data/theme/default/js/search_navigation.js +110 -0
  152. data/theme/default/js/search_page.js +202 -0
  153. data/theme/default/js/search_ranker.js +244 -0
  154. data/theme/default/script.js +91 -18
  155. data/theme/default/search.css +149 -0
  156. data/theme/default/style.css +193 -21
  157. data/theme/default/syntax-highlight.css +8 -0
  158. data/theme/lillia/style.css +45 -1
  159. metadata +178 -21
  160. 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,10 +461,51 @@ 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>
465
+ </code></pre>
466
+ </dd>
467
+ HERE
468
+ assert_compiled_method_source(expected, src)
469
+ end
470
+
471
+ def test_method_with_samplecode_singleton_class
472
+ src = <<'HERE'
473
+ --- singleton_method(name) -> Method
474
+ //emlist[][ruby]{
475
+ class <<obj
476
+ def foo
477
+ Object.new
478
+ end
479
+ end
480
+ class << Object.new
481
+ end
482
+ class << self
483
+ end
484
+ class << FOO::BAR::BAZ
485
+ end
486
+ p Foo.singleton_method(:foo)
487
+ //}
488
+ end
489
+ HERE
490
+ expected = <<'HERE'
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>
492
+ <dd class="method-description">
493
+ <pre class="highlight ruby"><code><span class="k">class</span> <span class="o">&lt;&lt;</span>obj
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>
496
+ <span class="k">end</span>
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>
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>
418
505
  </code></pre>
506
+ <p>
507
+ end
508
+ </p>
419
509
  </dd>
420
510
  HERE
421
511
  assert_compiled_method_source(expected, src)
@@ -442,6 +532,176 @@ HERE
442
532
  assert_compiled_method_source(expected, src)
443
533
  end
444
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
+
445
705
  def test_ulist_simple
446
706
  src = <<'HERE'
447
707
  * hoge1
@@ -494,13 +754,15 @@ HERE
494
754
  src = <<HERE
495
755
  * hoge1
496
756
  * fuga1
757
+ bar
497
758
  * hoge2
498
759
  * fuga2
499
760
  HERE
500
761
  expected = <<HERE
501
762
  <ul>
502
763
  <li>hoge1<ul>
503
- <li>fuga1</li>
764
+ <li>fuga1
765
+ bar</li>
504
766
  </ul>
505
767
  </li>
506
768
  <li>hoge2<ul>
@@ -508,7 +770,6 @@ HERE
508
770
  </ul>
509
771
  </li>
510
772
  </ul>
511
-
512
773
  HERE
513
774
  assert_compiled_source(expected, src)
514
775
  end
@@ -547,7 +808,6 @@ HERE
547
808
  </ol>
548
809
  </li>
549
810
  </ol>
550
-
551
811
  HERE
552
812
  assert_compiled_source(expected, src)
553
813
  end
@@ -574,7 +834,6 @@ HERE
574
834
  </ol>
575
835
  </li>
576
836
  </ul>
577
-
578
837
  HERE
579
838
  assert_compiled_source(expected, src)
580
839
  end
@@ -595,6 +854,8 @@ HERE
595
854
  <li>boo1</li>
596
855
  </ol>
597
856
  </li>
857
+ </ol>
858
+ </li>
598
859
  <li>hoge2<ol>
599
860
  <li>fuga2<ol>
600
861
  <li>boo2</li>
@@ -603,9 +864,6 @@ HERE
603
864
  </ol>
604
865
  </li>
605
866
  </ol>
606
- </li>
607
- </ol>
608
-
609
867
  HERE
610
868
  assert_compiled_source(expected, src)
611
869
  end
@@ -653,20 +911,25 @@ HERE
653
911
  "instance method" => ['[[m:String#dump]]', '<a href="dummy/method/String/i/dump">String#dump</a>'],
654
912
  "indexer" => ['[[m:String#[] ]]', '<a href="dummy/method/String/i/=5b=5d">String#[]</a>'],
655
913
  "C API" => ['[[f:rb_ary_new3]]', '<a href="dummy/function/rb_ary_new3">rb_ary_new3</a>'],
656
- "C API root" => ['[[f:/]]', '<a href="dummy/function/">All C API</a>'],
657
- "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>'],
658
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>'],
659
920
  "man command" => ['[[man:tr(1)]]', '<a class="external" href="http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html">tr(1)</a>'],
660
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>'],
661
922
  "man system call" => ['[[man:fopen(3linux)]]', '<a class="external" href="http://man7.org/linux/man-pages/man3/fopen.3.html">fopen(3linux)</a>'],
662
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'],
663
926
  "special var $~" => ['[[m:$~]]', '<a href="dummy/method/Kernel/v/=7e">$~</a>'],
664
927
  "special var $," => ['[[m:$,]]', '<a href="dummy/method/Kernel/v/=2c">$,</a>'],
665
928
  "extra close bracket" => ['[[c:String]]]', '<a href="dummy/class/String">String</a>]'],
666
929
  "continuity" => ['[[c:String]][[c:String]]', '<a href="dummy/class/String">String</a><a href="dummy/class/String">String</a>'],
667
930
  "constant" => ['[[m:File::SEPARATOR]]', '<a href="dummy/method/File/c/SEPARATOR">File::SEPARATOR</a>'],
668
931
  "url" => ['[[url:http://i.loveruby.net]]', '<a class="external" href="http://i.loveruby.net">http://i.loveruby.net</a>'],
669
- "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>'],
670
933
  "bugs.r-l.o feature" => ['[[feature:12345]]', '<a class="external" href="https://bugs.ruby-lang.org/issues/12345">[feature#12345]</a>'],
671
934
  "bugs.r-l.o bug" => ['[[bug:12345]]', '<a class="external" href="https://bugs.ruby-lang.org/issues/12345">[bug#12345]</a>'],
672
935
  "bugs.r-l.o misc" => ['[[misc:12345]]', '<a class="external" href="https://bugs.ruby-lang.org/issues/12345">[misc#12345]</a>'])
@@ -675,18 +938,147 @@ HERE
675
938
  assert_equal(expected, @c.send(:compile_text, target), target)
676
939
  end
677
940
 
678
- data("doc" => ['[[d:hoge/bar]]', '<a href="dummy/hoge/bar">.*</a>'],
679
- "ref doc" => ['[[ref:d:hoge/bar#frag]]', '<a href="dummy/hoge/bar#frag">.*</a>'],
680
- "ref class" => ['[[ref:c:Hoge#frag]]', '<a href="dummy/class/Hoge#frag">.*</a>'],
681
- "ref special var" => ['[[ref:m:$~#frag]]', '<a href="dummy/method/Kernel/v/=7e#frag">.*</a>'],
682
- "ref library" => ['[[ref:lib:jcode#frag]]', '<a href="dummy/library/jcode#frag">.*</a>'],
683
- "ref class error" => ['[[ref:c:Hoge]]', 'compileerror'],
684
- "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'],)
685
999
  def test_bracket_link_doc(data)
686
1000
  target, expected = data
687
1001
  assert_match(/#{expected}/, @c.send(:compile_text, target), target)
688
1002
  end
689
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
+
690
1082
  def test_array_join
691
1083
  src = <<'HERE'
692
1084
  --- join(sep = $,) -> String
@@ -822,6 +1214,16 @@ HERE
822
1214
  :method_id => "ARGF.class/i.binmode.argf._builtin",
823
1215
  :version => "2.0.0",
824
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"
825
1227
  })
826
1228
  def test_rdoc_url(data)
827
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