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
@@ -0,0 +1,231 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test/unit'
4
+
5
+ require 'bitclust/entity_splitter'
6
+ require 'bitclust/include_graph'
7
+
8
+ # EntitySplitter: マルチエンティティ RD をエンティティ単位に分割する(O3)。
9
+ # 2段階:
10
+ # 1. resolve_header_gates — スコープ定数(常に真/偽)の版ゲートのうち、最初の内容行が
11
+ # エンティティ H1 のブロックを解決する(活きている枝を残しゲートを外す)。
12
+ # 版で改名されたエンティティ(thread/Mutex, Net::HTTPURITooLong 等)の H1 ペアが
13
+ # スコープ内の単一 H1 に収束し、旧名は活き枝の alias 行として残る。
14
+ # 2. segments — 深さ0の H1(またはスコープ内ゲート付き H1 ブロック)を境界に分割。
15
+ # セグメント間の内容は直前のエンティティに帰属。連結すると入力に一致する。
16
+ #
17
+ # テストリスト:
18
+ # [x] resolve: 常真 since + #@else 改名ペア → 活き枝のみ(thread/Mutex パターン)
19
+ # [x] resolve: 常偽 until + #@else → else 枝のみ
20
+ # [x] resolve: 常真ゲートがエンティティ全体を包む(else なし)→ unwrap(EarlyHints パターン)
21
+ # [x] resolve: 常偽ゲートがエンティティ全体を包む(else なし)→ ブロックごと除去
22
+ # [x] resolve: スコープ内ゲート(since 3.2 等)→ 据え置き
23
+ # [x] resolve: 散文を包むゲート(最初の内容行が H1 でない)→ 据え置き
24
+ # [x] resolve: ブロック内にネストした #@ があっても対応を取る
25
+ # [x] resolve: 活き枝に複数エンティティがあってもそのまま残す(base64 パターン)
26
+ # [x] segments: 裸 H1 で分割、内容は直前エンティティへ、連結=入力
27
+ # [x] segments: スコープ内ゲート付き H1 ブロックは丸ごと1セグメント
28
+ # [x] segments: #@samplecode 内の「= class」風の行は境界にしない
29
+ # [x] segments: 先頭に H1 以外の内容がある場合は nil
30
+ # [x] entity_filename: :: → __、. は保持
31
+ class TestEntitySplitter < Test::Unit::TestCase
32
+ def scope
33
+ BitClust::IncludeGraph::Scope.new("3.0", "4.2")
34
+ end
35
+
36
+ def resolve(src)
37
+ BitClust::EntitySplitter.resolve_header_gates(src, scope)
38
+ end
39
+
40
+ def segments(src)
41
+ BitClust::EntitySplitter.segments(src)
42
+ end
43
+
44
+ # ---- resolve_header_gates ----
45
+
46
+ def test_resolve_renamed_entity_keeps_active_branch
47
+ # thread/Mutex: #@since 2.3.0(常真)で改名された H1 ペア
48
+ src = <<~RRD
49
+ \#@since 2.3.0
50
+ = class Thread::Mutex < Object
51
+ alias Mutex
52
+ \#@else
53
+ = class Mutex < Object
54
+ \#@end
55
+
56
+ 本文。
57
+ RRD
58
+ expected = <<~RRD
59
+ = class Thread::Mutex < Object
60
+ alias Mutex
61
+
62
+ 本文。
63
+ RRD
64
+ assert_equal expected, resolve(src)
65
+ end
66
+
67
+ def test_resolve_never_until_with_else_keeps_else_branch
68
+ src = "\#@until 2.3.0\n= class Old < Object\n\#@else\n= class New < Object\n\#@end\n本文。\n"
69
+ assert_equal "= class New < Object\n本文。\n", resolve(src)
70
+ end
71
+
72
+ def test_resolve_unwraps_wholly_gated_entity
73
+ # Net::HTTPEarlyHints: #@since 2.6.0(常真)がエンティティ全体を包む
74
+ src = "= class A < B\n\n\#@since 2.6.0\n= class C < D\n説明。\n\#@end\n\n= class E < F\n"
75
+ assert_equal "= class A < B\n\n= class C < D\n説明。\n\n= class E < F\n", resolve(src)
76
+ end
77
+
78
+ def test_resolve_drops_never_gated_entity
79
+ src = "= class A < B\n\n\#@until 2.4.0\n= class Dead < B\n説明。\n\#@end\n\n= class E < F\n"
80
+ assert_equal "= class A < B\n\n= class E < F\n", resolve(src)
81
+ end
82
+
83
+ def test_resolve_keeps_in_scope_gate
84
+ src = "\#@since 3.2\n= class New < Object\n説明。\n\#@end\n"
85
+ assert_equal src, resolve(src)
86
+ end
87
+
88
+ def test_resolve_keeps_prose_gates
89
+ src = "= class A < B\n\#@since 2.3.0\n新しい説明。\n\#@else\n古い説明。\n\#@end\n"
90
+ assert_equal src, resolve(src)
91
+ end
92
+
93
+ def test_resolve_provably_true_if_gate_with_entities
94
+ # digest.rd: #@if(version >= "1.8.6")(常真)がエンティティ構造ごと包む
95
+ src = "\#@if(version >= \"1.8.6\")\n= class A < Object\n\n= class B < A\ninclude I\n\#@else\n= class B < Object\n\#@end\n共通。\n"
96
+ assert_equal "= class A < Object\n\n= class B < A\ninclude I\n共通。\n", resolve(src)
97
+ end
98
+
99
+ def test_resolve_constant_gate_containing_h1_after_prose
100
+ # syslog.rd: 常真ゲートが散文の後にエンティティ H1 を含む
101
+ src = "= module C\n\n\#@since 2.0.0\n散文。\n= module D\nD。\n\#@end\n"
102
+ assert_equal "= module C\n\n散文。\n= module D\nD。\n", resolve(src)
103
+ end
104
+
105
+ def test_resolve_keeps_relation_only_constant_gate
106
+ # H1 を含まない定数ゲート(gated relations)は front matter の #@ 表現に任せる
107
+ src = "= module C\n\#@since 2.0.0\ninclude X\n\#@end\n"
108
+ assert_equal src, resolve(src)
109
+ end
110
+
111
+ def test_resolve_ignores_h1_like_lines_inside_samplecode
112
+ src = "\#@since 2.0.0\n散文。\n\#@samplecode\n= class Fake < Object\n\#@end\n\#@end\n"
113
+ assert_equal src, resolve(src)
114
+ end
115
+
116
+ def test_resolve_handles_quoted_version
117
+ # Preprocessor は #@since "1.8.5" のクォート形式も受理する(_builtin/Process に実在)
118
+ src = "\#@since \"1.8.5\"\n= class A < B\n本文。\n\#@end\n"
119
+ assert_equal "= class A < B\n本文。\n", resolve(src)
120
+ end
121
+
122
+ def test_resolve_handles_nested_blocks
123
+ src = <<~RRD
124
+ \#@since 1.9.1
125
+ = class A < B
126
+ \#@since 2.0.0
127
+ 版分岐の説明。
128
+ \#@end
129
+ \#@end
130
+ RRD
131
+ expected = <<~RRD
132
+ = class A < B
133
+ \#@since 2.0.0
134
+ 版分岐の説明。
135
+ \#@end
136
+ RRD
137
+ assert_equal expected, resolve(src)
138
+ end
139
+
140
+ def test_resolve_keeps_multi_entity_active_branch
141
+ # base64/Base64: 常真ゲートの枝に複数エンティティ
142
+ src = "\#@since 1.9.1\n= module Base64\n\n= reopen Kernel\n\#@else\n= module Base64\n\#@end\n"
143
+ assert_equal "= module Base64\n\n= reopen Kernel\n", resolve(src)
144
+ end
145
+
146
+ # ---- segments ----
147
+
148
+ def test_segments_split_at_bare_h1
149
+ src = "= class A < Object\ninclude Foo\n\nA の説明。\n\n= class B < Object\nB の説明。\n"
150
+ segs = segments(src)
151
+ assert_equal ["A", "B"], segs.map(&:first)
152
+ assert_equal "= class A < Object\ninclude Foo\n\nA の説明。\n\n", segs[0][1]
153
+ assert_equal "= class B < Object\nB の説明。\n", segs[1][1]
154
+ assert_equal src, segs.map(&:last).join
155
+ end
156
+
157
+ def test_segments_in_scope_gated_block_is_one_segment
158
+ src = "= class A < Object\n\n\#@since 3.2\n= class New < Object\n説明。\n\#@end\n"
159
+ segs = segments(src)
160
+ assert_equal ["A", "New"], segs.map(&:first)
161
+ assert_equal "\#@since 3.2\n= class New < Object\n説明。\n\#@end\n", segs[1][1]
162
+ end
163
+
164
+ def test_segments_partial_gate_around_h1_is_not_a_boundary
165
+ # syslog の旧構造: H1 と見出しだけがゲートされ、定数群はゲートの外にある。
166
+ # 単独ファイル化するとゲートが偽の版で自立パースできない
167
+ # (旧世界では直前エンティティに付く)ので分割境界にしない
168
+ src = "= class A < Object\n\n" \
169
+ "\#@since 2.0.0\n= module B\n説明。\n== Constants\n\#@end\n" \
170
+ "--- CONST -> Integer\n"
171
+ segs = segments(src)
172
+ assert_equal ["A"], segs.map(&:first)
173
+ assert_equal src, segs[0][1]
174
+ end
175
+
176
+ def test_segments_gated_boundary_allows_trailing_blanks
177
+ src = "= class A < Object\n\n" \
178
+ "\#@since 3.2\n= class New < Object\n説明。\n\#@end\n\n"
179
+ segs = segments(src)
180
+ assert_equal ["A", "New"], segs.map(&:first)
181
+ end
182
+
183
+ def test_segments_ignores_h1_like_lines_in_samplecode
184
+ src = "= class A < Object\n\#@samplecode\n= class B < Object\n\#@end\n"
185
+ segs = segments(src)
186
+ assert_equal ["A"], segs.map(&:first)
187
+ end
188
+
189
+ def test_segments_leading_content_becomes_base_segment
190
+ # ライブラリファイルのインライン・エンティティ: 先頭のライブラリ概要部は
191
+ # name=nil のベースセグメントになる
192
+ src = "category Cat\n\n概要。\n\n= class A < Object\nA の説明。\n"
193
+ segs = segments(src)
194
+ assert_equal [nil, "A"], segs.map(&:first)
195
+ assert_equal "category Cat\n\n概要。\n\n", segs[0][1]
196
+ assert_equal src, segs.map(&:last).join
197
+ end
198
+
199
+ def test_segments_single_entity
200
+ src = "= class A < Object\n説明。\n"
201
+ assert_equal [["A", src]], segments(src)
202
+ end
203
+
204
+ # ---- header_relations? ----
205
+
206
+ def test_header_relations_detects_relation_after_h1
207
+ assert_true BitClust::EntitySplitter.header_relations?(
208
+ "= class A < Object\ninclude Foo\n\n説明。\n")
209
+ assert_true BitClust::EntitySplitter.header_relations?(
210
+ "= class A < Object\n\n説明。\n\n= class B < Object\nalias C\n")
211
+ end
212
+
213
+ def test_header_relations_ignores_body_and_samplecode
214
+ # 本文到達後の include 風の行(コード例等)は数えない
215
+ assert_false BitClust::EntitySplitter.header_relations?(
216
+ "= module Math\n\n説明。\n\n\#@samplecode\ninclude Math\n\#@end\n")
217
+ end
218
+
219
+ def test_header_relations_counts_gated_relations
220
+ assert_true BitClust::EntitySplitter.header_relations?(
221
+ "= class A < Object\n\#@since 2.6.0\nalias B\n\#@end\n\n説明。\n")
222
+ end
223
+
224
+ # ---- entity_filename ----
225
+
226
+ def test_entity_filename
227
+ assert_equal "Net__HTTPOK", BitClust::EntitySplitter.entity_filename("Net::HTTPOK")
228
+ assert_equal "ARGF.class", BitClust::EntitySplitter.entity_filename("ARGF.class")
229
+ assert_equal "Time", BitClust::EntitySplitter.entity_filename("Time")
230
+ end
231
+ end
data/test/test_entry.rb CHANGED
@@ -11,11 +11,11 @@ alias HogeHogeHoge
11
11
  --- hoge
12
12
  hoge
13
13
  --- fuga
14
- @undef
14
+ {: undef}
15
15
  fuga
16
16
  == Instance Methods
17
17
  --- fugafuga
18
- @undef
18
+ {: undef}
19
19
  fugafuga
20
20
  = class Bar < Hoge
21
21
  == Class Methods
@@ -62,5 +62,210 @@ HERE
62
62
  assert('Exception', @lib.fetch_class("Err").superclass.name)
63
63
  assert('Exception', @lib.fetch_class("ErrErr").superclass.name)
64
64
  end
65
+
66
+ def test_instance_method?
67
+ bar = @lib.fetch_class("Bar")
68
+ assert(bar.instance_method?('fugafuga'))
69
+ assert(!bar.instance_method?('fugafuga', false))
70
+ hoge = @lib.fetch_class("Hoge")
71
+ assert(hoge.instance_method?('fugafuga'))
72
+ assert(hoge.instance_method?('fugafuga', false))
73
+ end
74
+ end
75
+
76
+ class TestEntryDescription < Test::Unit::TestCase
77
+ def parse_class(class_source)
78
+ lib, = BitClust::RRDParser.parse(class_source, 'hoge')
79
+ lib.fetch_class('Hoge')
80
+ end
81
+
82
+ def test_description_truncates_newline_between_non_ascii
83
+ klass = parse_class(<<HERE)
84
+ = class Hoge
85
+ これは1行目で
86
+ あとに続きます。
87
+
88
+ 以降の段落は含まれません。
89
+ HERE
90
+ assert_equal('これは1行目であとに続きます。', klass.description)
91
+ end
92
+
93
+ def test_description_truncates_consecutive_newlines_between_non_ascii
94
+ klass = parse_class(<<HERE)
95
+ = class Hoge
96
+ あい
97
+ うえ
98
+ おか。
99
+ HERE
100
+ assert_equal('あいうえおか。', klass.description)
101
+ end
102
+
103
+ def test_description_converts_newline_to_space_around_ascii
104
+ klass = parse_class(<<HERE)
105
+ = class Hoge
106
+ first line
107
+ second line
108
+ HERE
109
+ assert_equal('first line second line', klass.description)
110
+ end
111
+
112
+ def test_description_replaces_bracket_link_with_plain_text
113
+ klass = parse_class(<<HERE)
114
+ = class Hoge
115
+ 自身の hostname を文字列で返します。また、[[m:URI::Generic#host]] が設
116
+ 定されていない場合は [[c:Array]] を返します。
117
+ HERE
118
+ assert_equal('自身の hostname を文字列で返します。また、URI::Generic#host が設定されていない場合は Array を返します。',
119
+ klass.description)
120
+ end
121
+
122
+ def test_description_replaces_indexer_bracket_link
123
+ klass = parse_class(<<HERE)
124
+ = class Hoge
125
+ [[m:String#[] ]] を参照。
126
+ HERE
127
+ assert_equal('String#[] を参照。', klass.description)
128
+ end
129
+
130
+ def test_method_description_is_plain_text
131
+ klass = parse_class(<<HERE)
132
+ = class Hoge
133
+ == Instance Methods
134
+ --- fuga
135
+
136
+ [[c:Array]] を日本語で
137
+ 返します。
138
+
139
+ 次の段落。
140
+ HERE
141
+ method = klass.entries.detect {|m| m.name == 'fuga' }
142
+ assert_equal('Array を日本語で返します。', method.description)
143
+ end
65
144
  end
66
145
 
146
+ class TestEntryNomethod < Test::Unit::TestCase
147
+ def parse_class(class_source)
148
+ lib, = BitClust::RRDParser.parse(class_source, 'hoge')
149
+ lib.fetch_class('Hoge')
150
+ end
151
+
152
+ def test_nomethod_is_partitioned_separately
153
+ klass = parse_class(<<HERE)
154
+ = class Hoge
155
+ == Instance Methods
156
+ --- fuga
157
+ {: nomethod}
158
+
159
+ 説明のためのエントリです。
160
+ HERE
161
+ parts = klass.partitioned_entries
162
+ assert_equal(['fuga'], parts.nomethod.map(&:name))
163
+ assert_equal([], parts.instance_methods.map(&:name))
164
+ end
165
+
166
+ def test_redefined_is_partitioned_separately
167
+ klass = parse_class(<<HERE)
168
+ = class Hoge
169
+ == Instance Methods
170
+ --- bar
171
+
172
+ 説明です。
173
+
174
+ = redefine Hoge
175
+ == Instance Methods
176
+ --- baz
177
+
178
+ 再定義の説明です。
179
+ HERE
180
+ parts = klass.partitioned_entries
181
+ assert_equal(['baz'], parts.redefined.map(&:name))
182
+ assert_equal(['bar'], parts.instance_methods.map(&:name))
183
+ end
184
+
185
+ def test_description_skips_leading_metadata_paragraph
186
+ klass = parse_class(<<HERE)
187
+ = class Hoge
188
+ == Instance Methods
189
+ --- fuga
190
+ {: nomethod}
191
+
192
+ 説明のためのエントリです。
193
+ HERE
194
+ method = klass.entries.detect {|m| m.name == 'fuga' }
195
+ assert_equal('説明のためのエントリです。', method.description)
196
+ end
197
+
198
+ def test_description_is_empty_when_only_metadata
199
+ klass = parse_class(<<HERE)
200
+ = class Hoge
201
+ == Instance Methods
202
+ --- fuga
203
+ {: undef}
204
+ HERE
205
+ method = klass.entries.detect {|m| m.name == 'fuga' }
206
+ assert_equal('', method.description)
207
+ end
208
+ end
209
+
210
+ class TestClassEntryDynamicallyIncludedEntries < Test::Unit::TestCase
211
+ SRC = <<'HERE'
212
+ = module DynMod
213
+ dyn module
214
+ == Instance Methods
215
+ --- dyn_method
216
+ dyn method
217
+ == Private Instance Methods
218
+ --- hidden_dyn_method
219
+ hidden dyn method
220
+ = class Host < Object
221
+ host class
222
+ == Instance Methods
223
+ --- host_method
224
+ host method
225
+ = reopen Host
226
+ include DynMod
227
+ HERE
228
+
229
+ def setup
230
+ @lib, = BitClust::RRDParser.parse(SRC, 'dynlib')
231
+ @host = @lib.fetch_class('Host')
232
+ end
233
+
234
+ def test_returns_public_instance_methods_of_dynamically_included_modules
235
+ assert_equal(['dyn_method'], @host.dynamically_included_entries.map(&:name))
236
+ end
237
+
238
+ def test_excludes_private_instance_methods_of_the_dynamically_included_module
239
+ names = @host.dynamically_included_entries.map(&:name)
240
+ assert_not_include(names, 'hidden_dyn_method')
241
+ end
242
+
243
+ def test_entries_keep_their_originating_module_and_library
244
+ entry = @host.dynamically_included_entries.first
245
+ assert_equal('DynMod', entry.klass.name)
246
+ assert_equal('dynlib', entry.library.name)
247
+ end
248
+
249
+ def test_does_not_affect_ancestors
250
+ # dynamic include must not change the MRO/ancestors chain.
251
+ assert_equal(['Host', 'Object'], @host.ancestors.map(&:name))
252
+ end
253
+
254
+ def test_does_not_affect_entries_or_partitioned_entries
255
+ assert_not_include(@host.entries.map(&:name), 'dyn_method')
256
+ parts = @host.partitioned_entries
257
+ assert_not_include(parts.instance_methods.map(&:name), 'dyn_method')
258
+ assert_not_include(parts.added.map(&:name), 'dyn_method')
259
+ end
260
+
261
+ def test_is_empty_when_class_has_no_dynamic_include
262
+ plain, = BitClust::RRDParser.parse(<<'PLAIN', 'dynlib')
263
+ = class Plain < Object
264
+ plain class
265
+ == Instance Methods
266
+ --- plain_method
267
+ plain method
268
+ PLAIN
269
+ assert_equal([], plain.fetch_class('Plain').dynamically_included_entries)
270
+ end
271
+ end
@@ -0,0 +1,43 @@
1
+ require 'test/unit'
2
+ require 'bitclust'
3
+ require 'bitclust/screen'
4
+
5
+ class TestEOLWarning < Test::Unit::TestCase
6
+ SRC = <<'HERE'
7
+ = class Hoge
8
+ hoge class
9
+ == Instance Methods
10
+ --- foo
11
+ foo method
12
+ HERE
13
+
14
+ BANNER_TEXT = 'このマニュアルは既にメンテナンスが終了したバージョンの Ruby を対象としています。'
15
+ LATEST_URL = 'https://docs.ruby-lang.org/ja/latest/'
16
+
17
+ def render(manager_options)
18
+ lib, = BitClust::RRDParser.parse(SRC, 'testlib')
19
+ datadir = File.expand_path('../data/bitclust', __dir__)
20
+ manager = BitClust::ScreenManager.new({
21
+ :templatedir => "#{datadir}/template.offline",
22
+ :catalogdir => "#{datadir}/catalog",
23
+ :encoding => 'utf-8',
24
+ :default_encoding => 'utf-8',
25
+ :base_url => '',
26
+ :target_version => '3.0'
27
+ }.merge(manager_options))
28
+ db = BitClust::MethodDatabase.dummy('version' => '3.0')
29
+ manager.class_screen(lib.fetch_class('Hoge'), :database => db).body
30
+ end
31
+
32
+ def test_eol_warning_banner_is_shown_when_enabled
33
+ html = render(:eol_warning => true)
34
+ assert_include(html, BANNER_TEXT)
35
+ assert_include(html, LATEST_URL)
36
+ end
37
+
38
+ def test_eol_warning_banner_is_hidden_by_default
39
+ html = render({})
40
+ assert_not_include(html, BANNER_TEXT)
41
+ assert_not_include(html, LATEST_URL)
42
+ end
43
+ end
@@ -48,4 +48,15 @@ HERE
48
48
  assert_equal data[:expected], result.collect(&:source)
49
49
  }
50
50
  end
51
+
52
+ # source_location points at the file only; the line number is no longer
53
+ # recorded (it would only churn the generated diffs).
54
+ def test_source_location_has_no_line_number
55
+ @db.transaction {
56
+ result = @parser.parse_file(@path, "test.c", {"version" => "2.6.0"})
57
+ location = result.first.source_location
58
+ assert_equal @path, location.file
59
+ assert_nil location.line
60
+ }
61
+ end
51
62
  end