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,413 @@
1
+ require 'test/unit'
2
+ require 'bitclust'
3
+ require 'bitclust/screen'
4
+ require 'tmpdir'
5
+ require 'fileutils'
6
+
7
+ class TestClassScreen < Test::Unit::TestCase
8
+ SRC = <<'HERE'
9
+ = class Base < Object
10
+ base class
11
+ == Class Methods
12
+ --- base_class_method
13
+ base class method
14
+ --- shared_name
15
+ shared name
16
+ --- hidden_class_method
17
+ hidden class method
18
+ == Instance Methods
19
+ --- base_instance_method
20
+ base instance method
21
+ = module Mixin
22
+ mixin module
23
+ == Class Methods
24
+ --- mixin_class_method
25
+ mixin class method
26
+ == Instance Methods
27
+ --- mixin_instance_method
28
+ mixin instance method
29
+ = class Sub < Base
30
+ include Mixin
31
+ sub class
32
+ == Class Methods
33
+ --- sub_class_method
34
+ sub class method
35
+ --- hidden_class_method
36
+ {: undef}
37
+ == Instance Methods
38
+ --- shared_name
39
+ {: undef}
40
+
41
+ --- explanatory_method
42
+ {: nomethod}
43
+ 説明のために記載しているメソッドです。
44
+
45
+ = redefine Sub
46
+ == Instance Methods
47
+ --- redefined_instance_method
48
+ redefined instance method
49
+ HERE
50
+
51
+ def setup
52
+ @lib, = BitClust::RRDParser.parse(SRC, 'testlib')
53
+ datadir = File.expand_path('../data/bitclust', __dir__)
54
+ manager = BitClust::ScreenManager.new(
55
+ :templatedir => "#{datadir}/template.offline",
56
+ :catalogdir => "#{datadir}/catalog",
57
+ :encoding => 'utf-8',
58
+ :default_encoding => 'utf-8',
59
+ :base_url => '',
60
+ :target_version => '3.4'
61
+ )
62
+ db = BitClust::MethodDatabase.dummy('version' => '3.4')
63
+ @html = manager.class_screen(@lib.fetch_class('Sub'), :database => db).body
64
+ end
65
+
66
+ def test_ancestor_singleton_methods_are_displayed
67
+ assert_include(@html, 'Baseから継承している特異メソッド')
68
+ assert_include(@html, 'base_class_method')
69
+ end
70
+
71
+ def test_module_singleton_methods_are_not_inherited
72
+ # A class does not inherit singleton methods from included modules.
73
+ assert_not_include(@html, 'Mixinから継承している特異メソッド')
74
+ assert_not_include(@html, 'mixin_class_method')
75
+ end
76
+
77
+ def test_undefined_singleton_method_is_hidden
78
+ assert_not_include(@html, 'hidden_class_method')
79
+ end
80
+
81
+ def test_nomethod_method_is_listed_in_its_own_section
82
+ assert_include(@html, '説明のための未定義メソッド')
83
+ assert_include(@html, 'explanatory_method')
84
+ end
85
+
86
+ def test_nomethod_metadata_is_not_rendered_as_unknown
87
+ assert_not_include(@html, 'UNKNOWN_META_INFO')
88
+ assert_not_include(@html, '{:')
89
+ end
90
+
91
+ def test_undefined_instance_method_does_not_hide_singleton_method
92
+ # Sub undefs the *instance* method shared_name; the inherited singleton
93
+ # method of the same name must still be listed.
94
+ assert_include(@html, 'shared_name')
95
+ end
96
+
97
+ def test_ancestor_instance_methods_include_modules
98
+ assert_include(@html, 'Baseから継承しているメソッド')
99
+ assert_include(@html, 'base_instance_method')
100
+ assert_include(@html, 'Mixinから継承しているメソッド')
101
+ assert_include(@html, 'mixin_instance_method')
102
+ end
103
+
104
+ def test_redefined_method_is_listed_in_its_own_section
105
+ assert_include(@html, '再定義されたメソッド')
106
+ assert_include(@html, 'redefined_instance_method')
107
+ end
108
+
109
+ def test_class_without_dynamic_include_does_not_show_dynamic_include_section
110
+ # Regression guard: classes that never use dynamic include must render
111
+ # exactly as before (no new headline, no leftover markers).
112
+ assert_not_include(@html, '動的includeで追加されるメソッド')
113
+ end
114
+ end
115
+
116
+ class TestClassScreenDynamicInclude < Test::Unit::TestCase
117
+ SRC = <<'HERE'
118
+ = module JsonMixin
119
+ json mixin module
120
+ == Instance Methods
121
+ --- to_json
122
+ to json
123
+ == Private Instance Methods
124
+ --- hidden_json_helper
125
+ hidden json helper
126
+ = class Host < Object
127
+ host class
128
+ == Instance Methods
129
+ --- host_method
130
+ host method
131
+ = reopen Host
132
+ include JsonMixin
133
+ HERE
134
+
135
+ def setup
136
+ @lib, = BitClust::RRDParser.parse(SRC, 'jsonlib')
137
+ datadir = File.expand_path('../data/bitclust', __dir__)
138
+ manager = BitClust::ScreenManager.new(
139
+ :templatedir => "#{datadir}/template.offline",
140
+ :catalogdir => "#{datadir}/catalog",
141
+ :encoding => 'utf-8',
142
+ :default_encoding => 'utf-8',
143
+ :base_url => '',
144
+ :target_version => '3.4'
145
+ )
146
+ db = BitClust::MethodDatabase.dummy('version' => '3.4')
147
+ @html = manager.class_screen(@lib.fetch_class('Host'), :database => db).body
148
+ end
149
+
150
+ def test_dynamically_included_method_is_listed_with_attribution
151
+ assert_include(@html, '動的includeで追加されるメソッド')
152
+ assert_include(@html, 'to_json')
153
+ assert_include(@html, 'JsonMixin')
154
+ assert_include(@html, '(by jsonlib)')
155
+ end
156
+
157
+ def test_ancestors_are_not_affected_by_dynamic_include
158
+ assert_not_include(@lib.fetch_class('Host').ancestors.map(&:name), 'JsonMixin')
159
+ end
160
+
161
+ def test_private_instance_method_of_dynamically_included_module_is_hidden
162
+ assert_not_include(@html, 'hidden_json_helper')
163
+ end
164
+ end
165
+
166
+ class TestClassScreenAddedMethods < Test::Unit::TestCase
167
+ SRC = <<'HERE'
168
+ = class Target < Object
169
+ target class
170
+ == Instance Methods
171
+ --- own_method
172
+ own method
173
+ = reopen Target
174
+ == Instance Methods
175
+ --- added_by_reopen
176
+ added by reopen
177
+ HERE
178
+
179
+ def setup
180
+ @lib, = BitClust::RRDParser.parse(SRC, 'extlib')
181
+ datadir = File.expand_path('../data/bitclust', __dir__)
182
+ @manager = BitClust::ScreenManager.new(
183
+ :templatedir => "#{datadir}/template.offline",
184
+ :catalogdir => "#{datadir}/catalog",
185
+ :encoding => 'utf-8',
186
+ :default_encoding => 'utf-8',
187
+ :base_url => '',
188
+ :target_version => '3.4'
189
+ )
190
+ db = BitClust::MethodDatabase.dummy('version' => '3.4')
191
+ @html = @manager.class_screen(@lib.fetch_class('Target'), :database => db).body
192
+ end
193
+
194
+ # reopen 本文に直接定義されたメソッド(kind = :added)が
195
+ # statichtml 用テンプレートの目次に出ること
196
+ def test_added_methods_are_listed_in_offline_index
197
+ assert_include(@html, '追加されるメソッド')
198
+ assert_include(@html, 'added_by_reopen')
199
+ end
200
+
201
+ def test_class_without_added_methods_has_no_added_heading
202
+ plain, = BitClust::RRDParser.parse(<<'PLAIN', 'extlib')
203
+ = class Plain < Object
204
+ plain class
205
+ == Instance Methods
206
+ --- plain_method
207
+ plain method
208
+ PLAIN
209
+ db = BitClust::MethodDatabase.dummy('version' => '3.4')
210
+ html = @manager.class_screen(plain.fetch_class('Plain'), :database => db).body
211
+ assert_not_include(html, '追加されるメソッド')
212
+ end
213
+ end
214
+
215
+ # bitclust#132 P3: since/until バージョンバッジが class ページ(template.offline、
216
+ # 各メソッドをインライン(compile_method 経由)で描画する側)にも出ることの確認
217
+ class TestClassScreenVersionBadges < Test::Unit::TestCase
218
+ SRC = <<'HERE'
219
+ = class Target < Object
220
+ target class
221
+ == Instance Methods
222
+ --- own_method
223
+ own method
224
+ HERE
225
+
226
+ def setup
227
+ @lib, = BitClust::RRDParser.parse(SRC, 'extlib')
228
+ datadir = File.expand_path('../data/bitclust', __dir__)
229
+ @manager = BitClust::ScreenManager.new(
230
+ :templatedir => "#{datadir}/template.offline",
231
+ :catalogdir => "#{datadir}/catalog",
232
+ :encoding => 'utf-8',
233
+ :default_encoding => 'utf-8',
234
+ :base_url => '',
235
+ :target_version => '3.4'
236
+ )
237
+ @db = BitClust::MethodDatabase.dummy('version' => '3.4')
238
+ end
239
+
240
+ def test_since_badge_is_rendered_in_inlined_entry
241
+ entry = @lib.fetch_class('Target').fetch_method(BitClust::MethodSpec.parse('Target#own_method'))
242
+ entry.fill_since('own_method', '3.2')
243
+ html = @manager.class_screen(@lib.fetch_class('Target'), :database => @db).body
244
+ assert_include(html, '<span class="method-since-badge">Ruby 3.2 から</span>')
245
+ end
246
+ end
247
+
248
+ # bitclust#132 P3: default(サーバー動的配信用)テンプレートは compiler を経由せず
249
+ # 独自に署名行を描画するので、別名(alias)ごとの署名行にそれぞれ対応する
250
+ # バッジが付く(一様化はしない)ことを個別に確認する。
251
+ #
252
+ # この template/class は @entry.inherited_method_specs を呼び、これは
253
+ # ClassEntry#_index 経由でディスク上の永続化された索引ファイルを読む。
254
+ # 他のテストのような RRDParser.parse + MethodDatabase.dummy のインメモリ
255
+ # 組では索引が存在せず ENOENT になるので、ここだけは init/update で実際に
256
+ # ディスクへコミットした本物の MethodDatabase を使う
257
+ class TestClassScreenDefaultTemplateVersionBadges < Test::Unit::TestCase
258
+ SRC = <<'HERE'
259
+ = class Target < Object
260
+ target class
261
+ == Instance Methods
262
+ --- alias_one
263
+ --- alias_two
264
+ shared body
265
+ HERE
266
+
267
+ def setup
268
+ @datadir = File.expand_path('../data/bitclust', __dir__)
269
+ @dbdir = Dir.mktmpdir('bitclust-version-badges-db')
270
+ srcdir = Dir.mktmpdir('bitclust-version-badges-src')
271
+ src_path = File.join(srcdir, 'testlib.rd')
272
+ File.write(src_path, SRC)
273
+
274
+ @db = BitClust::MethodDatabase.new(@dbdir)
275
+ @db.init
276
+ @db.transaction do
277
+ @db.propset('version', '3.4')
278
+ @db.propset('encoding', 'utf-8')
279
+ end
280
+ @db.transaction do
281
+ @db.update_by_file(src_path, 'testlib')
282
+ end
283
+ FileUtils.rm_r(srcdir, :force => true)
284
+ end
285
+
286
+ def teardown
287
+ FileUtils.rm_r(@dbdir, :force => true)
288
+ end
289
+
290
+ def test_per_signature_badges_attach_to_their_own_alias_line
291
+ entry = @db.get_method(BitClust::MethodSpec.parse('Target#alias_one'))
292
+ entry.fill_since('alias_one', '3.0')
293
+ entry.fill_until('alias_two', '4.0')
294
+
295
+ manager = BitClust::ScreenManager.new(
296
+ :templatedir => "#{@datadir}/template",
297
+ :catalogdir => "#{@datadir}/catalog",
298
+ :encoding => 'utf-8',
299
+ :default_encoding => 'utf-8',
300
+ :base_url => '',
301
+ :target_version => '3.4'
302
+ )
303
+ # Screen#run_template は互換 ERB を self.class にキャッシュするので、同一
304
+ # プロセス内の他のテスト(template.offline を使う ClassScreen)と
305
+ # templatedir が混線しないよう、この検証専用のサブクラスを介して描画する
306
+ # (テストファイル上部のコメント、および test_method_screen.rb の同種の
307
+ # 注記を参照。ClassScreen 本体には触れない)
308
+ screen_class = Class.new(BitClust::ClassScreen)
309
+ html = manager.send(:new_screen, screen_class, @db.get_class('Target'), :database => @db).body
310
+
311
+ since_badge = '<span class="method-since-badge">Ruby 3.0 から</span>'
312
+ until_badge = '<span class="method-until-badge">Ruby 4.0 で削除</span>'
313
+ assert_include(html, since_badge)
314
+ assert_include(html, until_badge)
315
+
316
+ alias_one_pos = html.index('<code>alias_one</code>')
317
+ alias_two_pos = html.index('<code>alias_two</code>')
318
+ since_pos = html.index(since_badge)
319
+ until_pos = html.index(until_badge)
320
+ assert(alias_one_pos && alias_two_pos && since_pos && until_pos,
321
+ 'expected both signature lines and both badges to be present')
322
+ # since は alias_one の行に付き、alias_two の行より前に来る
323
+ assert(alias_one_pos < since_pos && since_pos < alias_two_pos,
324
+ 'the since badge must attach right after alias_one, not alias_two')
325
+ # until は alias_two の行に付き、alias_two より後に来る
326
+ assert(alias_two_pos < until_pos,
327
+ 'the until badge must attach after alias_two')
328
+ end
329
+ end
330
+
331
+ # bitclust#250: Ruby 4.0 以降のドキュメントでは module function の表記を
332
+ # 独自の「.#」から「?.」に変える(表示のみ、識別子は変えない)。
333
+ #
334
+ # data/bitclust/template/class の「継承しているメソッド」一覧は
335
+ # @entry.inherited_method_specs(MethodSpec、@db を持たない値オブジェクト)を
336
+ # 直接文字列化する数少ない箇所なので、上の TestClassScreenDefaultTemplateVersionBadges
337
+ # と同じ理由で実ディスク DB を使う
338
+ class TestClassScreenModuleFunctionDisplay < Test::Unit::TestCase
339
+ SRC = <<'HERE'
340
+ = module Mixin
341
+ mixin module
342
+ == Module Functions
343
+ --- mf
344
+ mixin module function
345
+ = class Host < Object
346
+ include Mixin
347
+ host class
348
+ == Instance Methods
349
+ --- own_method
350
+ own method
351
+ HERE
352
+
353
+ def render(version)
354
+ datadir = File.expand_path('../data/bitclust', __dir__)
355
+ dbdir = Dir.mktmpdir('bitclust-module-function-display-db')
356
+ srcdir = Dir.mktmpdir('bitclust-module-function-display-src')
357
+ begin
358
+ src_path = File.join(srcdir, 'testlib.rd')
359
+ File.write(src_path, SRC)
360
+
361
+ db = BitClust::MethodDatabase.new(dbdir)
362
+ db.init
363
+ db.transaction do
364
+ db.propset('version', version)
365
+ db.propset('encoding', 'utf-8')
366
+ end
367
+ db.transaction do
368
+ db.update_by_file(src_path, 'testlib')
369
+ end
370
+
371
+ manager = BitClust::ScreenManager.new(
372
+ :templatedir => "#{datadir}/template",
373
+ :catalogdir => "#{datadir}/catalog",
374
+ :encoding => 'utf-8',
375
+ :default_encoding => 'utf-8',
376
+ :base_url => '',
377
+ :target_version => version
378
+ )
379
+ # See TestClassScreenDefaultTemplateVersionBadges above for the general
380
+ # background: Screen#run_template caches the compiled ERB body on the
381
+ # *class*, keyed only by method name. A plain anonymous subclass is not
382
+ # sufficient isolation here, though: if BitClust::ClassScreen itself
383
+ # was already compiled for a different templatedir (offline) by some
384
+ # other test earlier in this same process -- order-dependent, since
385
+ # TestClassScreen above uses BitClust::ClassScreen directly, with no
386
+ # subclass -- then `respond_to?(:class_template)` is already true via
387
+ # *inheritance*, and the subclass would silently reuse that stale
388
+ # compiled method instead of compiling its own. So compile directly
389
+ # onto screen_class ourselves, before Screen#run_template ever gets a
390
+ # chance to check: our own method then always wins by normal Ruby
391
+ # method resolution, regardless of what BitClust::ClassScreen has.
392
+ screen_class = Class.new(BitClust::ClassScreen)
393
+ repo = BitClust::TemplateRepository.new("#{datadir}/template")
394
+ ERB.new(repo.load('class')).def_method(screen_class, 'class_template', 'class.erb')
395
+ manager.send(:new_screen, screen_class, db.get_class('Host'), :database => db).body
396
+ ensure
397
+ FileUtils.rm_r(srcdir, :force => true)
398
+ FileUtils.rm_r(dbdir, :force => true)
399
+ end
400
+ end
401
+
402
+ def test_inherited_module_function_shows_dot_hash_before_4_0
403
+ html = render('3.4')
404
+ assert_include(html, '.#mf')
405
+ assert_not_include(html, '?.mf')
406
+ end
407
+
408
+ def test_inherited_module_function_switches_to_question_dot_at_4_0
409
+ html = render('4.0')
410
+ assert_include(html, '?.mf')
411
+ assert_not_include(html, '.#mf')
412
+ end
413
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test/unit'
4
+ require 'tmpdir'
5
+ require 'fileutils'
6
+ require 'bitclust'
7
+ require 'bitclust/methoddatabase'
8
+
9
+ # copy_doc_md: manual/doc 配下の md をファイル存在で doc ページとして登録する。
10
+ # front matter の since/until でページ自体をバージョンで出し分けられることを
11
+ # 確認する(ライブラリ側と同じ意味論)。
12
+ class TestCopyDocMd < Test::Unit::TestCase
13
+ def docs_for(version)
14
+ Dir.mktmpdir do |dir|
15
+ FileUtils.mkdir_p(File.join(dir, 'manual', 'api'))
16
+ FileUtils.mkdir_p(File.join(dir, 'manual', 'doc', 'spec'))
17
+ File.write(File.join(dir, 'manual', 'doc', 'spec', 'gated.md'),
18
+ "---\nuntil: \"3.2\"\n---\n# ゲート付きページ\n\n本文。\n")
19
+ File.write(File.join(dir, 'manual', 'doc', 'spec', 'since.md'),
20
+ "---\nsince: \"3.3\"\n---\n# 新機能ページ\n\n本文。\n")
21
+ File.write(File.join(dir, 'manual', 'doc', 'spec', 'normal.md'),
22
+ "# 通常ページ\n\n本文。\n")
23
+
24
+ prefix = File.join(dir, 'db')
25
+ db = BitClust::MethodDatabase.new(prefix)
26
+ db.init
27
+ db.transaction do
28
+ db.propset('version', version)
29
+ db.propset('encoding', 'utf-8')
30
+ end
31
+ db.transaction do
32
+ db.instance_variable_set(:@md_root, File.join(dir, 'manual', 'api'))
33
+ db.__send__(:copy_doc_md)
34
+ end
35
+ db2 = BitClust::MethodDatabase.new(prefix)
36
+ return db2.docs.each_with_object({}) { |d, h| h[d.id] = d.title }
37
+ end
38
+ end
39
+
40
+ def test_until_gate_before_threshold
41
+ docs = docs_for('3.0')
42
+ assert_equal 'ゲート付きページ', docs['spec.gated'] # until: 3.2 → 3.0 は表示
43
+ assert_nil docs['spec.since'] # since: 3.3 → 3.0 は非表示
44
+ assert_equal '通常ページ', docs['spec.normal']
45
+ end
46
+
47
+ def test_until_gate_after_threshold
48
+ docs = docs_for('3.4')
49
+ assert_nil docs['spec.gated'] # until: 3.2 → 3.4 は非表示
50
+ assert_equal '新機能ページ', docs['spec.since'] # since: 3.3 → 3.4 は表示
51
+ assert_equal '通常ページ', docs['spec.normal']
52
+ end
53
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test/unit'
4
+
5
+ require 'bitclust/doc_converter'
6
+ require 'bitclust/markdown_to_rrd'
7
+
8
+ # DocConverter: refm/doc(散文ページ)の md 変換。
9
+ # クロスファイル情報が無いので reduce(正規化)+ 単一ファイル変換のみ。
10
+ #
11
+ # reduce の正規化(意味を変えない表記ゆれを md→rd 再生成形に合わせる):
12
+ # [x] ラベル無し #@samplecode の末尾スペース除去(spec/variables.rd)
13
+ # [x] //} の末尾スペース除去(spec/pattern_matching.rd)
14
+ # [x] 定義リスト term の「: 」二重スペース → 「: 」(spec/safelevel.rd, symref.rd)
15
+ # [x] 行頭タブ → スペース(news/2_7_0.rd の散文1行のみ。コード例にタブは無い)
16
+ # [x] クロスツリー include を manual レイアウトへ(../api/src/X → ../api/X)
17
+ # [x] convert(rrd) は reduce 後の変換で、md→rd が reduce 結果を復元する
18
+ class TestDocConverter < Test::Unit::TestCase
19
+ def reduce(rrd)
20
+ BitClust::DocConverter.reduce(rrd)
21
+ end
22
+
23
+ def test_samplecode_trailing_space
24
+ assert_equal "\#@samplecode\ncode\n\#@end\n", reduce("\#@samplecode \ncode\n\#@end\n")
25
+ # ラベル付きは触らない
26
+ assert_equal "\#@samplecode 例\n", reduce("\#@samplecode 例\n")
27
+ end
28
+
29
+ def test_emlist_close_trailing_space
30
+ assert_equal "//emlist{\ncode\n//}\n", reduce("//emlist{\ncode\n//} \n")
31
+ end
32
+
33
+ def test_dlist_term_double_space
34
+ assert_equal ": Object#taint\n", reduce(": Object#taint\n")
35
+ assert_equal ": !true\n", reduce(": !true\n")
36
+ end
37
+
38
+ def test_anchored_heading_double_space
39
+ # spec/regexp.rd: ===[a:str] 特別な... (アンカー後の二重スペース)
40
+ assert_equal "===[a:str] 特別な文字列に対するマッチ\n",
41
+ reduce("===[a:str] 特別な文字列に対するマッチ\n")
42
+ end
43
+
44
+ def test_leading_tab_to_space
45
+ assert_equal " x\n lazy になりました。\n", reduce(" x\n\tlazy になりました。\n")
46
+ end
47
+
48
+ def test_cross_tree_include_rewritten_to_manual_layout
49
+ assert_equal "\#@include(../api/_builtin/pack-template)\n",
50
+ reduce("\#@include(../api/src/_builtin/pack-template)\n")
51
+ assert_equal "\#@include(../../api/_builtin/thread.inc)\n",
52
+ reduce("\#@include(../../api/src/_builtin/thread.inc)\n")
53
+ end
54
+
55
+ def test_convert_roundtrips_to_reduced
56
+ rrd = "= タイトル\n\n本文。\n\n: term\n 説明。\n"
57
+ md = BitClust::DocConverter.convert(rrd)
58
+ assert_equal reduce(rrd), BitClust::MarkdownToRRD.convert(md)
59
+ end
60
+
61
+ def test_files_selects_pages_and_referenced_fragments
62
+ # 旧パイプライン(copy_doc)は **/*.rd だけをページとして読む。
63
+ # .rd 以外は include 参照される断片(spec/regexp19)のみ変換し、
64
+ # 参照されない死にファイル(news/1.8.0.rd-2)は凍結側に残す
65
+ require 'tmpdir'
66
+ require 'fileutils'
67
+ Dir.mktmpdir do |dir|
68
+ FileUtils.mkdir_p(File.join(dir, "spec"))
69
+ FileUtils.mkdir_p(File.join(dir, "news"))
70
+ File.write(File.join(dir, "spec/regexp.rd"), "= 正規表現\n\#@include(regexp19)\n")
71
+ File.write(File.join(dir, "spec/regexp19"), "断片。\n")
72
+ File.write(File.join(dir, "news/1.8.0.rd"), "= news\n")
73
+ File.write(File.join(dir, "news/1.8.0.rd-2"), "= 続き(孤児)\n")
74
+ assert_equal ["news/1.8.0.rd", "spec/regexp.rd", "spec/regexp19"],
75
+ BitClust::DocConverter.files(dir)
76
+ end
77
+ end
78
+ end