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.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/README.md +65 -0
- data/Rakefile +32 -0
- data/data/bitclust/catalog/ja_JP.UTF-8 +19 -1
- data/data/bitclust/searchpage/index.html +90 -0
- data/data/bitclust/template/class +69 -8
- data/data/bitclust/template/function +2 -2
- data/data/bitclust/template/layout +11 -3
- data/data/bitclust/template/method +2 -2
- data/data/bitclust/template/search +1 -1
- data/data/bitclust/template.epub/class +22 -1
- data/data/bitclust/template.epub/function +2 -2
- data/data/bitclust/template.epub/layout +1 -3
- data/data/bitclust/template.epub/method +2 -2
- data/data/bitclust/template.lillia/class +26 -5
- data/data/bitclust/template.lillia/layout +1 -3
- data/data/bitclust/template.lillia/method +2 -2
- data/data/bitclust/template.offline/class +48 -4
- data/data/bitclust/template.offline/function +2 -2
- data/data/bitclust/template.offline/layout +27 -3
- data/data/bitclust/template.offline/method +2 -2
- data/lib/bitclust/app.rb +16 -17
- data/lib/bitclust/capi_converter.rb +20 -0
- data/lib/bitclust/classentry.rb +67 -17
- data/lib/bitclust/compat.rb +2 -2
- data/lib/bitclust/completion.rb +58 -27
- data/lib/bitclust/crossrubyutils.rb +8 -5
- data/lib/bitclust/database.rb +28 -8
- data/lib/bitclust/doc_converter.rb +63 -0
- data/lib/bitclust/docentry.rb +1 -1
- data/lib/bitclust/entity_splitter.rb +221 -0
- data/lib/bitclust/entry.rb +47 -7
- data/lib/bitclust/functiondatabase.rb +13 -1
- data/lib/bitclust/functionentry.rb +5 -1
- data/lib/bitclust/functionreferenceparser.rb +4 -4
- data/lib/bitclust/generators/epub.rb +10 -3
- data/lib/bitclust/htmlutils.rb +1 -1
- data/lib/bitclust/include_graph.rb +375 -0
- data/lib/bitclust/include_pruner.rb +144 -0
- data/lib/bitclust/interface.rb +1 -1
- data/lib/bitclust/libraryentry.rb +8 -7
- data/lib/bitclust/lineinput.rb +7 -5
- data/lib/bitclust/link_checker.rb +179 -0
- data/lib/bitclust/markdown_bridge.rb +186 -0
- data/lib/bitclust/markdown_orchestrator.rb +267 -0
- data/lib/bitclust/markdown_to_rrd.rb +824 -0
- data/lib/bitclust/markdown_tree.rb +217 -0
- data/lib/bitclust/mdcompiler.rb +883 -0
- data/lib/bitclust/mdparser.rb +347 -0
- data/lib/bitclust/messagecatalog.rb +3 -3
- data/lib/bitclust/method_since_calculator.rb +117 -0
- data/lib/bitclust/methoddatabase.rb +124 -14
- data/lib/bitclust/methodentry.rb +125 -7
- data/lib/bitclust/methodid.rb +12 -11
- data/lib/bitclust/methodsignature.rb +10 -4
- data/lib/bitclust/nameutils.rb +41 -22
- data/lib/bitclust/preprocessor.rb +66 -29
- data/lib/bitclust/rdcompiler.rb +195 -95
- data/lib/bitclust/refsdatabase.rb +23 -8
- data/lib/bitclust/reloadable_request_handler.rb +72 -0
- data/lib/bitclust/requesthandler.rb +21 -16
- data/lib/bitclust/ridatabase.rb +10 -4
- data/lib/bitclust/rrd_to_markdown.rb +925 -0
- data/lib/bitclust/rrdparser.rb +196 -30
- data/lib/bitclust/runner.rb +17 -2
- data/lib/bitclust/screen.rb +80 -11
- data/lib/bitclust/search_index_generator.rb +288 -0
- data/lib/bitclust/searcher.rb +69 -20
- data/lib/bitclust/simplesearcher.rb +24 -12
- data/lib/bitclust/subcommand.rb +7 -1
- data/lib/bitclust/subcommands/ancestors_command.rb +9 -2
- data/lib/bitclust/subcommands/checklink_command.rb +54 -0
- data/lib/bitclust/subcommands/chm_command.rb +15 -7
- data/lib/bitclust/subcommands/classes_command.rb +5 -0
- data/lib/bitclust/subcommands/extract_command.rb +5 -0
- data/lib/bitclust/subcommands/htmlfile_command.rb +21 -7
- data/lib/bitclust/subcommands/init_command.rb +4 -1
- data/lib/bitclust/subcommands/list_command.rb +12 -4
- data/lib/bitclust/subcommands/lookup_command.rb +28 -9
- data/lib/bitclust/subcommands/methods_command.rb +10 -2
- data/lib/bitclust/subcommands/methodsince_command.rb +80 -0
- data/lib/bitclust/subcommands/preproc_command.rb +5 -0
- data/lib/bitclust/subcommands/property_command.rb +2 -1
- data/lib/bitclust/subcommands/searchpage_command.rb +102 -0
- data/lib/bitclust/subcommands/server_command.rb +10 -8
- data/lib/bitclust/subcommands/setup_command.rb +24 -10
- data/lib/bitclust/subcommands/statichtml_command.rb +129 -6
- data/lib/bitclust/subcommands/update_command.rb +110 -2
- data/lib/bitclust/syntax_highlighter.rb +48 -4
- data/lib/bitclust/textutils.rb +3 -3
- data/lib/bitclust/version.rb +1 -1
- data/lib/bitclust/version_badges.rb +90 -0
- data/lib/bitclust/whole_file_gate.rb +137 -0
- data/test/test_app.rb +269 -0
- data/test/test_bitclust.rb +2 -0
- data/test/test_capi_converter.rb +91 -0
- data/test/test_class_screen.rb +413 -0
- data/test/test_copy_doc_md.rb +53 -0
- data/test/test_doc_converter.rb +78 -0
- data/test/test_entity_splitter.rb +231 -0
- data/test/test_entry.rb +207 -2
- data/test/test_eol_warning.rb +43 -0
- data/test/test_functionreferenceparser.rb +11 -0
- data/test/test_include_graph.rb +640 -0
- data/test/test_include_pruner.rb +133 -0
- data/test/test_link_checker.rb +114 -0
- data/test/test_lookup_command.rb +135 -0
- data/test/test_markdown_bridge.rb +217 -0
- data/test/test_markdown_orchestrator.rb +478 -0
- data/test/test_markdown_to_rrd.rb +757 -0
- data/test/test_markdown_tree.rb +369 -0
- data/test/test_mdcompiler.rb +1276 -0
- data/test/test_mdparser.rb +538 -0
- data/test/test_method_screen.rb +166 -0
- data/test/test_method_since_calculator.rb +290 -0
- data/test/test_methoddatabase.rb +16 -0
- data/test/test_methodentry.rb +328 -0
- data/test/test_methodsignature.rb +3 -1
- data/test/test_methodsince_command.rb +168 -0
- data/test/test_nameutils.rb +22 -0
- data/test/test_preprocessor.rb +215 -0
- data/test/test_rdcompiler.rb +401 -30
- data/test/test_refsdatabase.rb +32 -0
- data/test/test_rrd_to_markdown.rb +968 -0
- data/test/test_rrdparser.rb +295 -2
- data/test/test_run_ruby_wasm.rb +54 -0
- data/test/test_run_worker_prelude.rb +83 -0
- data/test/test_runner.rb +51 -0
- data/test/test_search_index_generator.rb +513 -0
- data/test/test_search_screen.rb +48 -0
- data/test/test_searcher.rb +132 -0
- data/test/test_searchpage_command.rb +167 -0
- data/test/test_simplesearcher.rb +28 -0
- data/test/test_statichtml_command.rb +204 -0
- data/test/test_syntax_highlighter.rb +60 -0
- data/test/test_whole_file_gate.rb +175 -0
- data/theme/default/js/NOTICE +42 -0
- data/theme/default/js/run-worker.js +111 -0
- data/theme/default/js/run.js +350 -0
- data/theme/default/js/search_controller.js +134 -0
- data/theme/default/js/search_init.js +176 -0
- data/theme/default/js/search_navigation.js +110 -0
- data/theme/default/js/search_page.js +202 -0
- data/theme/default/js/search_ranker.js +244 -0
- data/theme/default/script.js +91 -18
- data/theme/default/search.css +149 -0
- data/theme/default/style.css +193 -21
- data/theme/default/syntax-highlight.css +8 -0
- data/theme/lillia/style.css +45 -1
- metadata +161 -20
- data/README +0 -32
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
|
|
7
|
+
require 'bitclust/markdown_tree'
|
|
8
|
+
|
|
9
|
+
# MarkdownTree: 新パイプラインのファイル発見(MARKUP_SPEC §1.1)。
|
|
10
|
+
# refm/api/src/**/*.md を glob し、front matter と H1 から
|
|
11
|
+
# エンティティ / ライブラリ / 共有断片 に分類する。LIBRARIES は使わない。
|
|
12
|
+
#
|
|
13
|
+
# 検証(ビルド警告):
|
|
14
|
+
# - 孤児: エンティティ H1 も type: library も持たず、どの #@include からも参照されない
|
|
15
|
+
# - library の無いエンティティ(スコープ外サルベージ分は許容リストで扱う)
|
|
16
|
+
# - 未知の library を指すエンティティ
|
|
17
|
+
# - 関係リント: マルチエンティティファイルに front matter の関係キー、
|
|
18
|
+
# または本文 H1 直後の関係行があれば警告(関係は front matter が唯一の記述場所)
|
|
19
|
+
# - #@include 先の欠損
|
|
20
|
+
#
|
|
21
|
+
# テストリスト:
|
|
22
|
+
# [x] type: library → ライブラリ(名前 = パスから .md を除いたもの)
|
|
23
|
+
# [x] エンティティ H1 → エンティティ(名前・library を読む)
|
|
24
|
+
# [x] 両方持つ dual ファイル(pathname 型)は両方に数える
|
|
25
|
+
# [x] どちらでもない + 参照あり → 断片
|
|
26
|
+
# [x] どちらでもない + 参照なし → 孤児警告
|
|
27
|
+
# [x] コードフェンス内の「# class」風の行は H1 に数えない
|
|
28
|
+
# [x] #@include の解決: target / target.md / target の .rd → .md
|
|
29
|
+
# [x] 断片からの #@include も参照として辿る
|
|
30
|
+
# [x] library なしエンティティ → 警告
|
|
31
|
+
# [x] 未知 library 参照 → 警告
|
|
32
|
+
# [x] マルチエンティティ + front matter 関係キー → リント警告
|
|
33
|
+
# [x] マルチエンティティ + 本文 H1 直後の関係行 → リント警告
|
|
34
|
+
# [x] include 先欠損 → 警告
|
|
35
|
+
class TestMarkdownTree < Test::Unit::TestCase
|
|
36
|
+
def scan(files)
|
|
37
|
+
Dir.mktmpdir do |dir|
|
|
38
|
+
files.each do |path, content|
|
|
39
|
+
full = File.join(dir, path)
|
|
40
|
+
FileUtils.mkdir_p(File.dirname(full))
|
|
41
|
+
File.write(full, content)
|
|
42
|
+
end
|
|
43
|
+
return BitClust::MarkdownTree.scan(dir)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
LIB = "---\ntype: library\ncategory: Cat\n---\n概要。\n"
|
|
48
|
+
|
|
49
|
+
def test_library_file
|
|
50
|
+
tree = scan("foo.md" => LIB)
|
|
51
|
+
assert_equal ["foo"], tree.libraries.keys
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_entity_file
|
|
55
|
+
tree = scan(
|
|
56
|
+
"foo.md" => LIB,
|
|
57
|
+
"foo/Bar.md" => "---\nlibrary: foo\n---\n# class Bar < Object\n\n説明。\n"
|
|
58
|
+
)
|
|
59
|
+
assert_equal ["Bar"], tree.entities["foo/Bar.md"][:names]
|
|
60
|
+
assert_equal "foo", tree.entities["foo/Bar.md"][:library]
|
|
61
|
+
assert_equal [], tree.warnings
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_scalar_library_is_normalized_to_memberships
|
|
65
|
+
tree = scan(
|
|
66
|
+
"foo.md" => LIB,
|
|
67
|
+
"foo/Bar.md" => "---\nlibrary: foo\n---\n# class Bar < Object\n"
|
|
68
|
+
)
|
|
69
|
+
assert_equal [{ library: "foo" }], tree.entities["foo/Bar.md"][:memberships]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_gated_library_list_memberships
|
|
73
|
+
# 多重所属(MARKUP_SPEC §1.2): ゲート付きリスト形式の library を
|
|
74
|
+
# memberships として読む。先頭が主所属(:library は後方互換の別名)
|
|
75
|
+
tree = scan(
|
|
76
|
+
"builtin.md" => LIB,
|
|
77
|
+
"thread.md" => LIB,
|
|
78
|
+
"thread/Mutex.md" =>
|
|
79
|
+
"---\n" \
|
|
80
|
+
"library:\n" \
|
|
81
|
+
" - builtin\n" \
|
|
82
|
+
"\#@until 1.9.1\n" \
|
|
83
|
+
" - thread\n" \
|
|
84
|
+
"\#@end\n" \
|
|
85
|
+
"---\n" \
|
|
86
|
+
"# class Mutex < Object\n\n説明。\n"
|
|
87
|
+
)
|
|
88
|
+
e = tree.entities["thread/Mutex.md"]
|
|
89
|
+
assert_equal "builtin", e[:library]
|
|
90
|
+
assert_equal [
|
|
91
|
+
{ library: "builtin" },
|
|
92
|
+
{ library: "thread", until: "1.9.1" },
|
|
93
|
+
], e[:memberships]
|
|
94
|
+
assert_equal [], tree.warnings
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_gated_library_list_with_both_bounds
|
|
98
|
+
tree = scan(
|
|
99
|
+
"builtin.md" => LIB,
|
|
100
|
+
"thread.md" => LIB,
|
|
101
|
+
"thread/CV.md" =>
|
|
102
|
+
"---\n" \
|
|
103
|
+
"library:\n" \
|
|
104
|
+
"\#@since 2.3.0\n" \
|
|
105
|
+
" - builtin\n" \
|
|
106
|
+
"\#@end\n" \
|
|
107
|
+
"\#@since 1.9.1\n" \
|
|
108
|
+
"\#@until 2.3.0\n" \
|
|
109
|
+
" - thread\n" \
|
|
110
|
+
"\#@end\n" \
|
|
111
|
+
"\#@end\n" \
|
|
112
|
+
"---\n" \
|
|
113
|
+
"# class ConditionVariable < Object\n"
|
|
114
|
+
)
|
|
115
|
+
assert_equal [
|
|
116
|
+
{ library: "builtin", since: "2.3.0" },
|
|
117
|
+
{ library: "thread", since: "1.9.1", until: "2.3.0" },
|
|
118
|
+
], tree.entities["thread/CV.md"][:memberships]
|
|
119
|
+
assert_equal [], tree.warnings
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_version_gated_body_relations_do_not_lint
|
|
123
|
+
# H1 自体が版分岐するファイル(rbconfig の Config⇔RbConfig 等)や
|
|
124
|
+
# ゲート付きヘッダ関係は body 残置が正しい(#@ ブロック内は
|
|
125
|
+
# ヘッダ関係扱いしない)。lint はゲート外の関係行だけを警告する
|
|
126
|
+
tree = scan(
|
|
127
|
+
"foo.md" => LIB,
|
|
128
|
+
"foo/Bar.md" =>
|
|
129
|
+
"---\nlibrary: foo\n---\n" \
|
|
130
|
+
"\#@since 1.9.1\n" \
|
|
131
|
+
"# module Bar\n" \
|
|
132
|
+
"\#@until 2.2.0\n" \
|
|
133
|
+
"alias Config\n" \
|
|
134
|
+
"\#@end\n" \
|
|
135
|
+
"説明。\n" \
|
|
136
|
+
"\#@else\n" \
|
|
137
|
+
"# module Config\n" \
|
|
138
|
+
"alias Bar\n" \
|
|
139
|
+
"\#@end\n"
|
|
140
|
+
)
|
|
141
|
+
assert tree.warnings.none? { |w| w.include?("relations in body") },
|
|
142
|
+
tree.warnings.inspect
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def test_relation_after_gated_h1_block_does_not_lint
|
|
146
|
+
# 版分岐 H1 ペアの直後(ゲートの外)に両ブランチ共通の関係行が続く形
|
|
147
|
+
# (net/Net__HTTPURITooLong の alias)。H1 がゲート内にある間は
|
|
148
|
+
# ヘッダ領域全体を lint 対象から外す
|
|
149
|
+
tree = scan(
|
|
150
|
+
"foo.md" => LIB,
|
|
151
|
+
"foo/Bar.md" =>
|
|
152
|
+
"---\nlibrary: foo\n---\n" \
|
|
153
|
+
"\#@since 2.6.0\n" \
|
|
154
|
+
"# class Bar < Object\n" \
|
|
155
|
+
"alias NewName\n" \
|
|
156
|
+
"\#@else\n" \
|
|
157
|
+
"# class OldBar < Object\n" \
|
|
158
|
+
"\#@end\n" \
|
|
159
|
+
"alias CommonName\n" \
|
|
160
|
+
"説明。\n"
|
|
161
|
+
)
|
|
162
|
+
assert tree.warnings.none? { |w| w.include?("relations in body") },
|
|
163
|
+
tree.warnings.inspect
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def test_gated_library_list_unknown_library_warns
|
|
167
|
+
tree = scan(
|
|
168
|
+
"foo.md" => LIB,
|
|
169
|
+
"foo/Bar.md" =>
|
|
170
|
+
"---\nlibrary:\n - foo\n\#@until 2.0.0\n - ghost\n\#@end\n---\n# class Bar < Object\n"
|
|
171
|
+
)
|
|
172
|
+
assert tree.warnings.any? { |w| w.include?("unknown library ghost") },
|
|
173
|
+
tree.warnings.inspect
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def test_dual_library_entity_file
|
|
177
|
+
tree = scan("foo.md" => "---\ntype: library\n---\n# class Foo < Object\n説明。\n")
|
|
178
|
+
assert_equal ["foo"], tree.libraries.keys
|
|
179
|
+
assert_equal ["Foo"], tree.entities["foo.md"][:names]
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def test_fragment_and_orphan
|
|
183
|
+
tree = scan(
|
|
184
|
+
"foo.md" => LIB + "\#@include(frag)\n",
|
|
185
|
+
"foo/orphan.md" => "誰からも参照されない断片。\n",
|
|
186
|
+
"frag.md" => "参照される断片。\n"
|
|
187
|
+
)
|
|
188
|
+
assert_equal ["frag.md"], tree.fragments
|
|
189
|
+
assert tree.warnings.any? { |w| w.include?("orphan") && w.include?("foo/orphan.md") },
|
|
190
|
+
tree.warnings.inspect
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def test_code_fence_h1_is_not_entity
|
|
194
|
+
md = "---\nlibrary: foo\n---\n# class Bar < Object\n\n`````\n# class Fake < Object\n`````\n"
|
|
195
|
+
tree = scan("foo.md" => LIB, "foo/Bar.md" => md)
|
|
196
|
+
assert_equal ["Bar"], tree.entities["foo/Bar.md"][:names]
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def test_include_resolution_variants
|
|
200
|
+
tree = scan(
|
|
201
|
+
"foo.md" => LIB + "\#@include(frag)\n\#@include(other.rd)\n\#@include(third.md)\n",
|
|
202
|
+
"frag.md" => "断片1。\n",
|
|
203
|
+
"other.md" => "断片2。\n",
|
|
204
|
+
"third.md" => "断片3。\n"
|
|
205
|
+
)
|
|
206
|
+
assert_equal ["frag.md", "other.md", "third.md"], tree.fragments.sort
|
|
207
|
+
assert_equal [], tree.warnings
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def test_fragment_chain_is_followed
|
|
211
|
+
tree = scan(
|
|
212
|
+
"foo.md" => LIB + "\#@include(a)\n",
|
|
213
|
+
"a.md" => "断片A。\n\#@include(b)\n",
|
|
214
|
+
"b.md" => "断片B。\n"
|
|
215
|
+
)
|
|
216
|
+
assert_equal ["a.md", "b.md"], tree.fragments.sort
|
|
217
|
+
assert_equal [], tree.warnings
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def test_referenced_file_without_front_matter_is_fragment_even_with_h1
|
|
221
|
+
# fiddle/2.0/types.rd 型: エンティティ H1 を含む断片が include 参照される
|
|
222
|
+
# (transclusion で取り込まれるので単独エンティティとしては数えない)
|
|
223
|
+
tree = scan(
|
|
224
|
+
"foo.md" => LIB + "\#@include(part)\n",
|
|
225
|
+
"part.md" => "断片。\n\n# reopen Fiddle\n### def win_types\n"
|
|
226
|
+
)
|
|
227
|
+
assert_equal ["part.md"], tree.fragments
|
|
228
|
+
assert_false tree.entities.key?("part.md")
|
|
229
|
+
assert_equal [], tree.warnings
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def test_entity_kinds_are_recorded
|
|
233
|
+
tree = scan(
|
|
234
|
+
"foo.md" => LIB,
|
|
235
|
+
"foo/Bar.md" => "---\nlibrary: foo\n---\n# class Bar < Object\n\n# reopen Kernel\n"
|
|
236
|
+
)
|
|
237
|
+
assert_equal [%w[class Bar], %w[reopen Kernel]], tree.entities["foo/Bar.md"][:kinds]
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def test_entity_without_library_warns
|
|
241
|
+
tree = scan("foo.md" => LIB, "Dead.md" => "# class Dead < Object\n説明。\n")
|
|
242
|
+
assert tree.warnings.any? { |w| w.include?("no library") && w.include?("Dead.md") },
|
|
243
|
+
tree.warnings.inspect
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def test_unknown_library_reference_warns
|
|
247
|
+
tree = scan("Bar.md" => "---\nlibrary: ghost\n---\n# class Bar < Object\n")
|
|
248
|
+
assert tree.warnings.any? { |w| w.include?("unknown library") && w.include?("ghost") },
|
|
249
|
+
tree.warnings.inspect
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def test_multi_entity_with_front_matter_relations_lints
|
|
253
|
+
md = "---\nlibrary: foo\ninclude:\n - Enumerable\n---\n# class A < Object\n\n# class B < Object\n"
|
|
254
|
+
tree = scan("foo.md" => LIB, "foo/AB.md" => md)
|
|
255
|
+
assert tree.warnings.any? { |w| w.include?("relation") && w.include?("foo/AB.md") },
|
|
256
|
+
tree.warnings.inspect
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def test_multi_entity_with_body_relations_lints
|
|
260
|
+
md = "---\nlibrary: foo\n---\n# class A < Object\ninclude Enumerable\n\n# class B < Object\n"
|
|
261
|
+
tree = scan("foo.md" => LIB, "foo/AB.md" => md)
|
|
262
|
+
assert tree.warnings.any? { |w| w.include?("relation") && w.include?("foo/AB.md") },
|
|
263
|
+
tree.warnings.inspect
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def test_single_entity_body_relation_also_lints
|
|
267
|
+
# O3 後の正しい形では本文関係行は存在しないはず(単一でも警告)
|
|
268
|
+
md = "---\nlibrary: foo\n---\n# class A < Object\ninclude Enumerable\n"
|
|
269
|
+
tree = scan("foo.md" => LIB, "foo/A.md" => md)
|
|
270
|
+
assert tree.warnings.any? { |w| w.include?("relation") && w.include?("foo/A.md") },
|
|
271
|
+
tree.warnings.inspect
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def test_missing_include_target_warns
|
|
275
|
+
tree = scan("foo.md" => LIB + "\#@include(nothing)\n")
|
|
276
|
+
assert tree.warnings.any? { |w| w.include?("include target not found") },
|
|
277
|
+
tree.warnings.inspect
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def test_library_name_front_matter_override
|
|
281
|
+
# 出力名の大文字小文字衝突回避で改名されたライブラリファイル
|
|
282
|
+
# (rdoc/rdoc → rdoc/rdoc.lib.md)は front matter の name: が名前になる
|
|
283
|
+
tree = scan(
|
|
284
|
+
"rdoc.md" => LIB,
|
|
285
|
+
"rdoc/rdoc.lib.md" => "---\ntype: library\nname: rdoc/rdoc\n---\n概要。\n"
|
|
286
|
+
)
|
|
287
|
+
assert tree.libraries.key?("rdoc/rdoc"), tree.libraries.keys.inspect
|
|
288
|
+
assert_equal "rdoc/rdoc.lib.md", tree.libraries["rdoc/rdoc"][:path]
|
|
289
|
+
assert_false tree.libraries.key?("rdoc/rdoc.lib")
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def test_case_insensitive_filename_collision_warns
|
|
293
|
+
# 大文字小文字のみが異なる名前は macOS/Windows の case-insensitive FS で
|
|
294
|
+
# チェックアウト不能になるため、同一ディレクトリ内の衝突を警告する
|
|
295
|
+
tree = scan(
|
|
296
|
+
"x.md" => LIB,
|
|
297
|
+
"x/Foo.md" => "---\nlibrary: x\n---\n# class Foo < Object\nFoo。\n",
|
|
298
|
+
"x/foo.md" => "---\ntype: library\n---\n概要。\n"
|
|
299
|
+
)
|
|
300
|
+
assert tree.warnings.any? { |w|
|
|
301
|
+
w.include?("case-insensitive") && w.include?("x/Foo.md") && w.include?("x/foo.md")
|
|
302
|
+
}, tree.warnings.inspect
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# bitclust#285: 新 prefix #% でも構造発見(所属ゲート・include・版ゲート深度)
|
|
306
|
+
# が同一に動くこと。旧 #@ との混在も許す
|
|
307
|
+
def test_percent_prefix_gated_memberships
|
|
308
|
+
tree = scan(
|
|
309
|
+
"builtin.md" => LIB,
|
|
310
|
+
"thread.md" => LIB,
|
|
311
|
+
"thread/Mutex.md" =>
|
|
312
|
+
"---\n" \
|
|
313
|
+
"library:\n" \
|
|
314
|
+
" - builtin\n" \
|
|
315
|
+
"#%until 1.9.1\n" \
|
|
316
|
+
" - thread\n" \
|
|
317
|
+
"#%end\n" \
|
|
318
|
+
"---\n" \
|
|
319
|
+
"# class Mutex < Object\n\n説明。\n"
|
|
320
|
+
)
|
|
321
|
+
e = tree.entities["thread/Mutex.md"]
|
|
322
|
+
assert_equal [
|
|
323
|
+
{ library: "builtin" },
|
|
324
|
+
{ library: "thread", until: "1.9.1" },
|
|
325
|
+
], e[:memberships]
|
|
326
|
+
assert_equal [], tree.warnings
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def test_percent_prefix_include
|
|
330
|
+
tree = scan(
|
|
331
|
+
"foo.md" => LIB + "#%include(frag)\n\#@include(other)\n",
|
|
332
|
+
"frag.md" => "断片1。\n",
|
|
333
|
+
"other.md" => "断片2。\n"
|
|
334
|
+
)
|
|
335
|
+
assert_equal ["frag.md", "other.md"], tree.fragments.sort
|
|
336
|
+
assert_equal [], tree.warnings
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def test_percent_prefix_gated_h1_relations_do_not_lint
|
|
340
|
+
tree = scan(
|
|
341
|
+
"foo.md" => LIB,
|
|
342
|
+
"foo/Bar.md" =>
|
|
343
|
+
"---\nlibrary: foo\n---\n" \
|
|
344
|
+
"#%since 3.0\n" \
|
|
345
|
+
"# class Bar < Object\n" \
|
|
346
|
+
"include Enumerable\n" \
|
|
347
|
+
"#%end\n"
|
|
348
|
+
)
|
|
349
|
+
refute tree.entities["foo/Bar.md"][:body_relations],
|
|
350
|
+
"gated H1 relations must not be flagged (nil or false)"
|
|
351
|
+
assert_equal [], tree.warnings
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def test_version_range_gated_h1_relations_do_not_lint
|
|
355
|
+
# #%version A...B(#285 の版範囲記法)も版ゲートとして深度に数える
|
|
356
|
+
tree = scan(
|
|
357
|
+
"foo.md" => LIB,
|
|
358
|
+
"foo/Bar.md" =>
|
|
359
|
+
"---\nlibrary: foo\n---\n" \
|
|
360
|
+
"#%version 3.0...4.0\n" \
|
|
361
|
+
"# class Bar < Object\n" \
|
|
362
|
+
"include Enumerable\n" \
|
|
363
|
+
"#%end\n"
|
|
364
|
+
)
|
|
365
|
+
refute tree.entities["foo/Bar.md"][:body_relations],
|
|
366
|
+
"version-range-gated H1 relations must not be flagged"
|
|
367
|
+
assert_equal [], tree.warnings
|
|
368
|
+
end
|
|
369
|
+
end
|