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
@@ -29,8 +29,7 @@ HERE
29
29
  = module Dummy
30
30
  == Instance Methods
31
31
  --- test_undef
32
-
33
- @undef
32
+ {: undef}
34
33
 
35
34
  このメソッドは利用できない
36
35
 
@@ -39,4 +38,298 @@ HERE
39
38
  test_undef_spec = BitClust::MethodSpec.parse('Dummy#test_undef')
40
39
  assert_equal(:undefined, methoddatabase.get_method(test_undef_spec).kind)
41
40
  end
41
+
42
+ def test_nomethod
43
+ result = BitClust::RRDParser.parse(<<HERE, 'dummy')
44
+ = module Dummy
45
+ == Instance Methods
46
+ --- test_nomethod
47
+ {: nomethod}
48
+
49
+ 説明のためここに記載しているメソッド
50
+
51
+ HERE
52
+ _library, methoddatabase = result
53
+ test_nomethod_spec = BitClust::MethodSpec.parse('Dummy#test_nomethod')
54
+ assert_equal(:nomethod, methoddatabase.get_method(test_nomethod_spec).kind)
55
+ end
56
+
57
+ def test_unknown_method_attribute
58
+ assert_raise(BitClust::ParseError) do
59
+ BitClust::RRDParser.parse(<<HERE, 'dummy')
60
+ = module Dummy
61
+ == Instance Methods
62
+ --- test_typo
63
+ {: nomthod}
64
+
65
+ typo したフラグはエラーになる
66
+
67
+ HERE
68
+ end
69
+ end
70
+
71
+ def test_since_attribute_sets_since_of_name
72
+ _library, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
73
+ = module Dummy
74
+ == Instance Methods
75
+ --- test_since
76
+ {: since="2.5"}
77
+
78
+ 説明
79
+
80
+ HERE
81
+ entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_since'))
82
+ assert_equal('2.5', entry.since_of('test_since'))
83
+ assert_nil(entry.until_of('test_since'))
84
+ end
85
+
86
+ # {: since=""}(空値)は「明示的に不明」の指定(bitclust#132)。メソッド自体は
87
+ # 昔からあるのにドキュメント追加が遅れ、ラダー算出が誤った版を出す場合に
88
+ # バッジを抑止する(空文字が記録され、算出値で上書きされず、表示もされない)
89
+ def test_empty_since_attribute_means_explicitly_unknown
90
+ _library, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
91
+ = module Dummy
92
+ == Instance Methods
93
+ --- test_unknown
94
+ {: since=""}
95
+
96
+ 説明
97
+
98
+ HERE
99
+ entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_unknown'))
100
+ assert_equal('', entry.since_of('test_unknown'))
101
+ assert_nil(entry.until_of('test_unknown'))
102
+ end
103
+
104
+ def test_empty_until_attribute_is_also_accepted
105
+ _library, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
106
+ = module Dummy
107
+ == Instance Methods
108
+ --- test_unknown_until
109
+ {: until=""}
110
+
111
+ 説明
112
+
113
+ HERE
114
+ entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_unknown_until'))
115
+ assert_equal('', entry.until_of('test_unknown_until'))
116
+ end
117
+
118
+ def test_until_attribute_sets_until_of_name
119
+ _library, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
120
+ = module Dummy
121
+ == Instance Methods
122
+ --- test_until
123
+ {: until="3.0"}
124
+
125
+ 説明
126
+
127
+ HERE
128
+ entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_until'))
129
+ assert_equal('3.0', entry.until_of('test_until'))
130
+ assert_nil(entry.since_of('test_until'))
131
+ end
132
+
133
+ # bitclust#132: 特殊変数のシグネチャ名は "$PROGRAM_NAME" のように $ 付き
134
+ # だが、エントリの names は $ を剥がした形で格納される。since_by_name の
135
+ # キーは names に合わせる(正規化しないと黙って参照されない値になる)
136
+ def test_since_attribute_on_special_variable_uses_entry_name
137
+ _library, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
138
+ = module Kernel
139
+ == Special Variables
140
+ --- $0
141
+ --- $PROGRAM_NAME
142
+ {: since="1.9.1"}
143
+
144
+ 説明
145
+
146
+ HERE
147
+ entry = db.get_class('Kernel').entries.first || raise
148
+ assert_equal(['0', 'PROGRAM_NAME'], entry.names.sort)
149
+ assert_equal('1.9.1', entry.since_of('PROGRAM_NAME'))
150
+ assert_nil(entry.since_of('0'))
151
+ end
152
+
153
+ def test_malformed_since_attribute_is_rejected
154
+ ['since=2.5', 'since="3,2"', 'since="abc"', 'foo="1"'].each do |token|
155
+ assert_raise(BitClust::ParseError, token) do
156
+ BitClust::RRDParser.parse(<<HERE, 'dummy')
157
+ = module Dummy
158
+ == Instance Methods
159
+ --- test_since
160
+ {: #{token}}
161
+
162
+ 説明
163
+
164
+ HERE
165
+ end
166
+ end
167
+ end
168
+
169
+ def test_duplicate_since_attribute_on_one_signature_is_rejected
170
+ assert_raise(BitClust::ParseError) do
171
+ BitClust::RRDParser.parse(<<HERE, 'dummy')
172
+ = module Dummy
173
+ == Instance Methods
174
+ --- test_since
175
+ {: since="1.0" since="2.0"}
176
+
177
+ 説明
178
+
179
+ HERE
180
+ end
181
+ end
182
+
183
+ def test_instance_methods
184
+ result = BitClust::RRDParser.parse(<<HERE, 'dummy')
185
+ = module Dummy
186
+
187
+ == Instance Methods
188
+ --- im
189
+
190
+ == Private Methods
191
+
192
+ --- pvi
193
+
194
+ == Protected Instance Methods
195
+
196
+ --- pti
197
+
198
+ HERE
199
+ _library, methoddatabase = result
200
+
201
+ test_undef_spec = BitClust::MethodSpec.parse('Dummy#im')
202
+ assert_equal(true, methoddatabase.get_method(test_undef_spec).public?)
203
+
204
+ test_undef_spec = BitClust::MethodSpec.parse('Dummy#pvi')
205
+ assert_equal(true, methoddatabase.get_method(test_undef_spec).private?)
206
+
207
+ test_undef_spec = BitClust::MethodSpec.parse('Dummy#pti')
208
+ assert_equal(true, methoddatabase.get_method(test_undef_spec).protected?)
209
+ end
210
+ end
211
+
212
+ class TestRRDParserMethodAttributeBinding < Test::Unit::TestCase
213
+ # {: ...} は直前のシグネチャ行のみに束縛される(kramdown の Block IAL と同じ)。
214
+ # kind はエントリ単位なので、別名エントリでは全シグネチャに同じ属性が必要
215
+ def test_attribute_on_every_alias_signature
216
+ result = BitClust::RRDParser.parse(<<HERE, 'dummy')
217
+ = module Dummy
218
+ == Instance Methods
219
+ --- test_foo
220
+ {: nomethod}
221
+ --- test_bar
222
+ {: nomethod}
223
+
224
+ 説明のためのエントリ
225
+
226
+ HERE
227
+ _library, db = result
228
+ foo = db.get_method(BitClust::MethodSpec.parse('Dummy#test_foo'))
229
+ assert_equal(:nomethod, foo.kind)
230
+ assert_equal(['test_bar', 'test_foo'], foo.names)
231
+ end
232
+
233
+ def test_attribute_missing_on_some_alias_signature_is_rejected
234
+ assert_raise(BitClust::ParseError) do
235
+ BitClust::RRDParser.parse(<<HERE, 'dummy')
236
+ = module Dummy
237
+ == Instance Methods
238
+ --- test_foo
239
+ {: nomethod}
240
+ --- test_bar
241
+
242
+ 説明のためのエントリ
243
+
244
+ HERE
245
+ end
246
+ end
247
+
248
+ def test_since_attribute_differs_per_alias_signature
249
+ # since=/until= はシグネチャ単位で束縛され、nomethod/undef と違って
250
+ # エイリアスごとに異なる値を持てる(全シグネチャ一致は要求しない)
251
+ result = BitClust::RRDParser.parse(<<HERE, 'dummy')
252
+ = module Dummy
253
+ == Instance Methods
254
+ --- test_foo
255
+ {: since="2.0.0"}
256
+ --- test_bar
257
+ {: since="3.0"}
258
+
259
+ 説明のためのエントリ
260
+
261
+ HERE
262
+ _library, db = result
263
+ entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_foo'))
264
+ assert_equal(['test_bar', 'test_foo'], entry.names)
265
+ assert_equal('2.0.0', entry.since_of('test_foo'))
266
+ assert_equal('3.0', entry.since_of('test_bar'))
267
+ end
268
+
269
+ def test_since_attribute_on_only_one_alias_signature_is_allowed
270
+ result = BitClust::RRDParser.parse(<<HERE, 'dummy')
271
+ = module Dummy
272
+ == Instance Methods
273
+ --- test_foo
274
+ {: since="2.0.0"}
275
+ --- test_bar
276
+
277
+ 説明のためのエントリ
278
+
279
+ HERE
280
+ _library, db = result
281
+ entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_foo'))
282
+ assert_equal('2.0.0', entry.since_of('test_foo'))
283
+ assert_nil(entry.since_of('test_bar'))
284
+ end
285
+
286
+ def test_undef_and_since_mixed_on_same_signature_line
287
+ result = BitClust::RRDParser.parse(<<HERE, 'dummy')
288
+ = module Dummy
289
+ == Instance Methods
290
+ --- test_foo
291
+ {: undef since="3.0"}
292
+
293
+ 説明のためのエントリ
294
+
295
+ HERE
296
+ _library, db = result
297
+ entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_foo'))
298
+ assert_equal(:undefined, entry.kind)
299
+ assert_equal('3.0', entry.since_of('test_foo'))
300
+ end
301
+
302
+ def test_bare_attribute_uniformity_still_enforced_when_since_present
303
+ # since= はシグネチャ単位で例外的に一致要求から外れるが、
304
+ # undef/nomethod のエントリ単位の一致要求はそのまま生きている
305
+ assert_raise(BitClust::ParseError) do
306
+ BitClust::RRDParser.parse(<<HERE, 'dummy')
307
+ = module Dummy
308
+ == Instance Methods
309
+ --- test_foo
310
+ {: undef since="3.0"}
311
+ --- test_bar
312
+ {: since="3.0"}
313
+
314
+ 説明のためのエントリ
315
+
316
+ HERE
317
+ end
318
+ end
319
+
320
+ def test_detached_attribute_line_is_not_a_method_attribute
321
+ # 空行を挟んだ {: ...} はシグネチャに束縛されない(ただの本文)
322
+ result = BitClust::RRDParser.parse(<<HERE, 'dummy')
323
+ = module Dummy
324
+ == Instance Methods
325
+ --- test_foo
326
+
327
+ {: nomethod}
328
+
329
+ 説明
330
+
331
+ HERE
332
+ _library, db = result
333
+ assert_equal(:defined, db.get_method(BitClust::MethodSpec.parse('Dummy#test_foo')).kind)
334
+ end
42
335
  end
@@ -0,0 +1,54 @@
1
+ require 'test/unit'
2
+ require 'bitclust'
3
+ require 'bitclust/screen'
4
+
5
+ class TestRunRubyWasm < Test::Unit::TestCase
6
+ SRC = <<'HERE'
7
+ = class Hoge
8
+ hoge class
9
+ == Instance Methods
10
+ --- foo
11
+ foo method
12
+ HERE
13
+
14
+ WASM_URL = 'https://cdn.jsdelivr.net/npm/@ruby/3.4-wasm-wasi@2.9.3-2.9.4/dist/ruby+stdlib.wasm'
15
+ META_TAG = %Q(<meta name="rurema-run-ruby-wasm" content="#{WASM_URL}">)
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.4'
27
+ }.merge(manager_options))
28
+ db = BitClust::MethodDatabase.dummy('version' => '3.4')
29
+ manager.class_screen(lib.fetch_class('Hoge'), :database => db).body
30
+ end
31
+
32
+ def test_run_script_is_loaded_when_enabled
33
+ html = render(:run_ruby_wasm => WASM_URL)
34
+ assert_include(html, META_TAG)
35
+ assert_include(html, 'js/run.js')
36
+ end
37
+
38
+ def test_run_script_is_not_loaded_by_default
39
+ html = render({})
40
+ assert_not_include(html, 'rurema-run-ruby-wasm')
41
+ assert_not_include(html, 'run.js')
42
+ end
43
+
44
+ def test_wasm_url_is_html_escaped
45
+ html = render(:run_ruby_wasm => 'https://example.com/ruby.wasm?a=1&b="x"')
46
+ assert_include(html, 'content="https://example.com/ruby.wasm?a=1&amp;b=&quot;x&quot;"')
47
+ end
48
+
49
+ def test_coexists_with_eol_warning
50
+ html = render(:run_ruby_wasm => WASM_URL, :eol_warning => true)
51
+ assert_include(html, META_TAG)
52
+ assert_include(html, 'class="eol-warning"')
53
+ end
54
+ end
@@ -0,0 +1,83 @@
1
+ require 'test/unit'
2
+
3
+ # theme/default/js/run-worker.js の PRELUDE(Ruby コード)の検証。
4
+ # Kernel#puts/print/p は $stdout が IO でないとき #write 経由で書き込むが、
5
+ # マニュアルのサンプルは $stderr.puts や $stdout.putc のように IO のメソッドを
6
+ # 直接呼ぶこともある(旧実装の StringIO はそれらを備えていた)。JS ブリッジを
7
+ # スタブした実 Ruby で PRELUDE を eval し、両方の経路の出力を確認する。
8
+ class TestRunWorkerPrelude < Test::Unit::TestCase
9
+ WORKER_JS = File.expand_path('../theme/default/js/run-worker.js', __dir__)
10
+
11
+ module JSStub
12
+ OUTPUT = []
13
+ def self.global
14
+ self
15
+ end
16
+
17
+ def self.call(name, text)
18
+ raise ArgumentError, "unexpected JS call: #{name}" unless name == :postOutput
19
+ OUTPUT << text.to_s
20
+ end
21
+ end
22
+
23
+ def setup
24
+ src = File.read(WORKER_JS)
25
+ prelude = src[/export const PRELUDE = `\n(.*?)\n`/m, 1]
26
+ assert_not_nil(prelude, 'PRELUDE not found in run-worker.js')
27
+ # ruby.wasm 上でだけ存在する js gem をスタブに差し替える
28
+ @prelude = prelude.sub(/\Arequire "js"\n/, '')
29
+ JSStub::OUTPUT.clear
30
+ Object.const_set(:JS, JSStub)
31
+ end
32
+
33
+ def teardown
34
+ Object.send(:remove_const, :JS) if Object.const_defined?(:JS)
35
+ Object.send(:remove_const, :JSStreamIO) if Object.const_defined?(:JSStreamIO)
36
+ end
37
+
38
+ def run_with_prelude
39
+ orig_stdout = $stdout
40
+ orig_stderr = $stderr
41
+ begin
42
+ eval(@prelude, TOPLEVEL_BINDING)
43
+ yield
44
+ ensure
45
+ $stdout = orig_stdout
46
+ $stderr = orig_stderr
47
+ end
48
+ JSStub::OUTPUT.join
49
+ end
50
+
51
+ def test_kernel_methods_stream_through_post_output
52
+ out = run_with_prelude do
53
+ puts 'hello'
54
+ print 'a', 'b'
55
+ p 123
56
+ end
57
+ assert_equal("hello\nab123\n", out)
58
+ end
59
+
60
+ def test_direct_io_methods_match_old_stringio_behavior
61
+ out = run_with_prelude do
62
+ $stdout.puts 'direct'
63
+ $stderr.puts 'err'
64
+ $stdout.putc 'XY'
65
+ $stdout.print 'pr'
66
+ $stdout.printf('%05d', 42)
67
+ $stdout << 'chained' << '!'
68
+ $stdout.flush
69
+ $stdout.puts ['a', ['b']]
70
+ $stdout.puts
71
+ end
72
+ assert_equal("direct\nerr\nXpr00042chained!a\nb\n\n", out)
73
+ end
74
+
75
+ def test_stream_reports_not_a_tty_and_accepts_sync
76
+ run_with_prelude do
77
+ assert_false($stdout.tty?)
78
+ assert_false($stderr.isatty)
79
+ assert_true($stdout.sync)
80
+ $stdout.sync = true
81
+ end
82
+ end
83
+ end
data/test/test_runner.rb CHANGED
@@ -94,4 +94,55 @@ class TestRunner < Test::Unit::TestCase
94
94
  command.exec(["--list"], {:prefix=>@prefix, :capi => false})
95
95
  @runner.run(["property", "--list"])
96
96
  end
97
+
98
+ def test_run_search_without_database
99
+ # search (Searcher) は自前で DB を探すので、--database も config も
100
+ # なしで実行できる
101
+ command = mock(Object.new)
102
+ mock(::BitClust::Searcher).new.returns(command)
103
+ mock(@runner).load_config.returns(nil)
104
+ command.parse(["String#gsub"])
105
+ command.exec(["String#gsub"], {:prefix => nil, :capi => false})
106
+ @runner.run(["search", "String#gsub"])
107
+ end
108
+
109
+ def test_run_database_command_without_database
110
+ # DB 必須のサブコマンドは、裸の raise ではなく案内付きのエラーで中断する
111
+ command = mock(Object.new)
112
+ mock(::BitClust::Subcommands::InitCommand).new.returns(command)
113
+ mock(@runner).load_config.returns(nil)
114
+ command.parse([])
115
+ command.needs_database?.returns(true)
116
+ original_stderr = $stderr
117
+ $stderr = StringIO.new
118
+ assert_raise(SystemExit) { @runner.run(["init"]) }
119
+ assert_include($stderr.string, "--database")
120
+ ensure
121
+ $stderr = original_stderr
122
+ end
123
+
124
+ def test_needs_database
125
+ # グローバル --database が不要なサブコマンド
126
+ # (DB を使わない・自前の -d を持つ・DB が任意)
127
+ [
128
+ BitClust::Subcommands::SetupCommand,
129
+ BitClust::Subcommands::PreprocCommand,
130
+ BitClust::Subcommands::ExtractCommand,
131
+ BitClust::Subcommands::ClassesCommand,
132
+ BitClust::Subcommands::MethodsCommand,
133
+ BitClust::Subcommands::AncestorsCommand,
134
+ BitClust::Subcommands::HtmlfileCommand,
135
+ BitClust::Subcommands::SearchpageCommand,
136
+ ].each do |klass|
137
+ assert_false(klass.new.needs_database?, klass.name)
138
+ end
139
+ # グローバル --database が必須のサブコマンド
140
+ [
141
+ BitClust::Subcommands::InitCommand,
142
+ BitClust::Subcommands::UpdateCommand,
143
+ BitClust::Subcommands::ListCommand,
144
+ ].each do |klass|
145
+ assert_true(klass.new.needs_database?, klass.name)
146
+ end
147
+ end
97
148
  end