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,640 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
|
|
7
|
+
require 'bitclust/include_graph'
|
|
8
|
+
|
|
9
|
+
# IncludeGraph: doctree の #@include グラフを版ゲート付きで解析する faithful 層。
|
|
10
|
+
# スコープ([3.0,4.2) 等)は適用せず、生の全所属・全ゲートを収集する。
|
|
11
|
+
# スコープ適用は IncludeGraph::Scope(別テストセクション)が担う。
|
|
12
|
+
#
|
|
13
|
+
# テストリスト:
|
|
14
|
+
# [x] LIBRARIES の 1行1ライブラリ → root (<name>.rd) から grouping メンバーを収集
|
|
15
|
+
# [x] 分類: 最初の非空・非#@行が = class|module|object|reopen|redefine → grouping、他 → fragment
|
|
16
|
+
# [x] パス解決: include 元ディレクトリ相対、target そのまま → 無ければ target.rd
|
|
17
|
+
# [x] LIBRARIES の重複エントリは dedupe
|
|
18
|
+
# [x] include サイトの #@since/#@until → membership conditions
|
|
19
|
+
# [x] #@else で最内条件を反転(since↔until、同一バージョン)
|
|
20
|
+
# [x] #@if は版制約なしの条件として記録(#@else でも版制約なしのまま)
|
|
21
|
+
# [x] ネストした条件は全て積む、#@end で pop
|
|
22
|
+
# [x] LIBRARIES 内の版ゲートはそのライブラリの全 membership の先頭条件になる
|
|
23
|
+
# [x] 再帰: grouping メンバーが include する grouping にも経路の条件を継承した membership
|
|
24
|
+
# [x] 多重所属: 複数経路から include される grouping は memberships 複数(生のまま保持)
|
|
25
|
+
# [x] 同一 (library, conditions) の重複 membership は dedupe
|
|
26
|
+
# [x] 循環 include で無限ループしない(warning 記録)
|
|
27
|
+
# [x] 存在しない include 対象 → warning 記録(エラーにしない)
|
|
28
|
+
# [x] interval: conditions → [lo, hi)(since は max、until は min、:if は無視)
|
|
29
|
+
# [x] Scope#cover?: 範囲 [lo, hi) と交差するか
|
|
30
|
+
# [x] Scope#gate: front matter に書く since/until(スコープ境界内のみ、範囲外は省略)
|
|
31
|
+
class TestIncludeGraph < Test::Unit::TestCase
|
|
32
|
+
def analyze(files)
|
|
33
|
+
Dir.mktmpdir do |dir|
|
|
34
|
+
files.each do |path, content|
|
|
35
|
+
full = File.join(dir, path)
|
|
36
|
+
FileUtils.mkdir_p(File.dirname(full))
|
|
37
|
+
File.write(full, content)
|
|
38
|
+
end
|
|
39
|
+
return BitClust::IncludeGraph.analyze(dir)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def membership(library, conditions = [])
|
|
44
|
+
BitClust::IncludeGraph::Membership.new(
|
|
45
|
+
library,
|
|
46
|
+
conditions.map { |kind, version| BitClust::IncludeGraph::Condition.new(kind, version) }
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# ---- roots と分類 ----
|
|
51
|
+
|
|
52
|
+
def test_simple_grouping_membership
|
|
53
|
+
graph = analyze(
|
|
54
|
+
"LIBRARIES" => "foo\n",
|
|
55
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
56
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
57
|
+
)
|
|
58
|
+
assert_equal [membership("foo")], graph.memberships("foo/Bar")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_fragment_classification
|
|
62
|
+
graph = analyze(
|
|
63
|
+
"LIBRARIES" => "foo\n",
|
|
64
|
+
"foo.rd" => "\#@include(foo/Bar)\n\#@include(foo/frag)\n",
|
|
65
|
+
"foo/Bar" => "= class Bar < Object\n",
|
|
66
|
+
"foo/frag" => "ただの散文断片。\n"
|
|
67
|
+
)
|
|
68
|
+
assert_equal ["foo/Bar"], graph.groupings.keys
|
|
69
|
+
assert_equal ["foo/frag"], graph.fragments
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_classification_skips_blank_and_directive_lines
|
|
73
|
+
graph = analyze(
|
|
74
|
+
"LIBRARIES" => "foo\n",
|
|
75
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
76
|
+
"foo/Bar" => "\n\#@since 1.9.1\n= reopen Kernel\n\#@end\n"
|
|
77
|
+
)
|
|
78
|
+
assert_equal ["foo/Bar"], graph.groupings.keys
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_include_resolves_with_rd_fallback
|
|
82
|
+
graph = analyze(
|
|
83
|
+
"LIBRARIES" => "foo\n",
|
|
84
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
85
|
+
"foo/Bar.rd" => "= class Bar < Object\n"
|
|
86
|
+
)
|
|
87
|
+
assert_equal [membership("foo")], graph.memberships("foo/Bar.rd")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_include_resolves_relative_to_including_file
|
|
91
|
+
graph = analyze(
|
|
92
|
+
"LIBRARIES" => "foo/sub\n",
|
|
93
|
+
"foo/sub.rd" => "\#@include(Bar)\n",
|
|
94
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
95
|
+
)
|
|
96
|
+
assert_equal [membership("foo/sub")], graph.memberships("foo/Bar")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_libraries_skips_preprocessor_comment_lines
|
|
100
|
+
# LIBRARIES には「#@# json/add/rails.rd」のようなコメントアウト行がある
|
|
101
|
+
graph = analyze(
|
|
102
|
+
"LIBRARIES" => "foo\n\#@# ghost\n",
|
|
103
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
104
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
105
|
+
)
|
|
106
|
+
assert_equal [], graph.warnings
|
|
107
|
+
assert_equal [membership("foo")], graph.memberships("foo/Bar")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_duplicate_libraries_entries_are_deduped
|
|
111
|
+
graph = analyze(
|
|
112
|
+
"LIBRARIES" => "foo\nfoo\n",
|
|
113
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
114
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
115
|
+
)
|
|
116
|
+
assert_equal [membership("foo")], graph.memberships("foo/Bar")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# ---- 版ゲート ----
|
|
120
|
+
|
|
121
|
+
def test_include_under_since_gate
|
|
122
|
+
graph = analyze(
|
|
123
|
+
"LIBRARIES" => "foo\n",
|
|
124
|
+
"foo.rd" => "\#@since 3.2\n\#@include(foo/Bar)\n\#@end\n",
|
|
125
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
126
|
+
)
|
|
127
|
+
assert_equal [membership("foo", [[:since, "3.2"]])], graph.memberships("foo/Bar")
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def test_include_in_else_branch_inverts_since
|
|
131
|
+
# thread.rd パターン: #@since 2.3.0 ... #@else [include群] #@end → 実効 until 2.3.0
|
|
132
|
+
graph = analyze(
|
|
133
|
+
"LIBRARIES" => "foo\n",
|
|
134
|
+
"foo.rd" => "\#@since 2.3.0\ntext\n\#@else\n\#@include(foo/Bar)\n\#@end\n",
|
|
135
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
136
|
+
)
|
|
137
|
+
assert_equal [membership("foo", [[:until, "2.3.0"]])], graph.memberships("foo/Bar")
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_include_in_else_branch_inverts_until
|
|
141
|
+
graph = analyze(
|
|
142
|
+
"LIBRARIES" => "foo\n",
|
|
143
|
+
"foo.rd" => "\#@until 1.9.1\ntext\n\#@else\n\#@include(foo/Bar)\n\#@end\n",
|
|
144
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
145
|
+
)
|
|
146
|
+
assert_equal [membership("foo", [[:since, "1.9.1"]])], graph.memberships("foo/Bar")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_include_under_if_gate_records_condition_without_version_bound
|
|
150
|
+
graph = analyze(
|
|
151
|
+
"LIBRARIES" => "foo\n",
|
|
152
|
+
"foo.rd" => "\#@if (version < \"1.8.2\")\n\#@include(foo/Bar)\n\#@end\n",
|
|
153
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
154
|
+
)
|
|
155
|
+
assert_equal [membership("foo", [[:if, '(version < "1.8.2")']])],
|
|
156
|
+
graph.memberships("foo/Bar")
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def test_include_in_else_branch_of_if_records_negation
|
|
160
|
+
graph = analyze(
|
|
161
|
+
"LIBRARIES" => "foo\n",
|
|
162
|
+
"foo.rd" => "\#@if (version < \"1.8.2\")\ntext\n\#@else\n\#@include(foo/Bar)\n\#@end\n",
|
|
163
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
164
|
+
)
|
|
165
|
+
assert_equal [membership("foo", [[:if, '!((version < "1.8.2"))']])],
|
|
166
|
+
graph.memberships("foo/Bar")
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def test_nested_gates_accumulate_and_end_pops
|
|
170
|
+
src = <<~RRD
|
|
171
|
+
\#@since 2.0.0
|
|
172
|
+
\#@until 3.0
|
|
173
|
+
\#@include(foo/Bar)
|
|
174
|
+
\#@end
|
|
175
|
+
\#@include(foo/Baz)
|
|
176
|
+
\#@end
|
|
177
|
+
\#@include(foo/Qux)
|
|
178
|
+
RRD
|
|
179
|
+
graph = analyze(
|
|
180
|
+
"LIBRARIES" => "foo\n",
|
|
181
|
+
"foo.rd" => src,
|
|
182
|
+
"foo/Bar" => "= class Bar < Object\n",
|
|
183
|
+
"foo/Baz" => "= class Baz < Object\n",
|
|
184
|
+
"foo/Qux" => "= class Qux < Object\n"
|
|
185
|
+
)
|
|
186
|
+
assert_equal [membership("foo", [[:since, "2.0.0"], [:until, "3.0"]])],
|
|
187
|
+
graph.memberships("foo/Bar")
|
|
188
|
+
assert_equal [membership("foo", [[:since, "2.0.0"]])], graph.memberships("foo/Baz")
|
|
189
|
+
assert_equal [membership("foo")], graph.memberships("foo/Qux")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_libraries_gate_prefixes_membership_conditions
|
|
193
|
+
# LIBRARIES の cmath は #@until 2.7.0 に包まれている実例に対応
|
|
194
|
+
graph = analyze(
|
|
195
|
+
"LIBRARIES" => "\#@until 2.7.0\nfoo\n\#@end\nother\n",
|
|
196
|
+
"foo.rd" => "\#@since 1.9.1\n\#@include(foo/Bar)\n\#@end\n",
|
|
197
|
+
"other.rd" => "text\n",
|
|
198
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
199
|
+
)
|
|
200
|
+
assert_equal [membership("foo", [[:until, "2.7.0"], [:since, "1.9.1"]])],
|
|
201
|
+
graph.memberships("foo/Bar")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# ---- 再帰と多重所属 ----
|
|
205
|
+
|
|
206
|
+
def test_nested_grouping_inherits_path_conditions
|
|
207
|
+
# rdoc/context.rd → RDoc__Context のような2段 grouping
|
|
208
|
+
graph = analyze(
|
|
209
|
+
"LIBRARIES" => "foo\n",
|
|
210
|
+
"foo.rd" => "\#@since 2.0.0\n\#@include(foo/Bar)\n\#@end\n",
|
|
211
|
+
"foo/Bar" => "= class Bar < Object\n\#@until 3.0\n\#@include(Baz)\n\#@end\n",
|
|
212
|
+
"foo/Baz" => "= class Baz < Object\n"
|
|
213
|
+
)
|
|
214
|
+
assert_equal [membership("foo", [[:since, "2.0.0"], [:until, "3.0"]])],
|
|
215
|
+
graph.memberships("foo/Baz")
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def test_fragment_include_from_member
|
|
219
|
+
# _builtin/Array → pack-template のような断片 include
|
|
220
|
+
graph = analyze(
|
|
221
|
+
"LIBRARIES" => "foo\n",
|
|
222
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
223
|
+
"foo/Bar" => "= class Bar < Object\n\#@include(frag)\n",
|
|
224
|
+
"foo/frag" => "断片テキスト。\n"
|
|
225
|
+
)
|
|
226
|
+
assert_equal ["foo/frag"], graph.fragments
|
|
227
|
+
assert_equal [], graph.memberships("foo/frag")
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def test_multiple_memberships_are_kept_raw
|
|
231
|
+
# cgi/core.rd が util.rd(cgi/util のルート)を #@until 内で include する実例に対応
|
|
232
|
+
graph = analyze(
|
|
233
|
+
"LIBRARIES" => "foo\nbar\n",
|
|
234
|
+
"foo.rd" => "\#@include(shared/Thing)\n",
|
|
235
|
+
"bar.rd" => "\#@until 1.9.1\n\#@include(shared/Thing)\n\#@end\n",
|
|
236
|
+
"shared/Thing" => "= class Thing < Object\n"
|
|
237
|
+
)
|
|
238
|
+
assert_equal [
|
|
239
|
+
membership("foo"),
|
|
240
|
+
membership("bar", [[:until, "1.9.1"]]),
|
|
241
|
+
], graph.memberships("shared/Thing")
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def test_identical_memberships_are_deduped
|
|
245
|
+
# _builtin/Data → Data.attention 9回のような同一 include の繰り返し(grouping 版)
|
|
246
|
+
graph = analyze(
|
|
247
|
+
"LIBRARIES" => "foo\n",
|
|
248
|
+
"foo.rd" => "\#@include(foo/Bar)\n\#@include(foo/Bar)\n",
|
|
249
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
250
|
+
)
|
|
251
|
+
assert_equal [membership("foo")], graph.memberships("foo/Bar")
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def test_entity_h1_without_space_is_grouping
|
|
255
|
+
# RRDParser は /\A=[^=]/ で H1 を認識するため「=class Encoding」も有効
|
|
256
|
+
# (実データ: _builtin/Encoding, _builtin/Encoding__Converter)
|
|
257
|
+
graph = analyze(
|
|
258
|
+
"LIBRARIES" => "foo\n",
|
|
259
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
260
|
+
"foo/Bar" => "=class Bar < Object\n"
|
|
261
|
+
)
|
|
262
|
+
assert_equal [membership("foo")], graph.memberships("foo/Bar")
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def test_membership_propagates_through_fragment_chain
|
|
266
|
+
# fiddle.rd → fiddle/2.0/fiddle.lib.rd(散文開始=fragment)→ Fiddle(grouping)の
|
|
267
|
+
# transclusion チェーン。fragment を経由しても所属と経路条件は伝播する
|
|
268
|
+
graph = analyze(
|
|
269
|
+
"LIBRARIES" => "foo\n",
|
|
270
|
+
"foo.rd" => "\#@until 2.0.0\n\#@include(foo/1.9/frag.rd)\n\#@else\n\#@include(foo/2.0/frag.rd)\n\#@end\n",
|
|
271
|
+
"foo/1.9/frag.rd" => "散文。\n\#@include(Bar)\n",
|
|
272
|
+
"foo/2.0/frag.rd" => "散文。\n\#@include(Bar)\n",
|
|
273
|
+
"foo/1.9/Bar" => "= class Bar < Object\n",
|
|
274
|
+
"foo/2.0/Bar" => "= class Bar < Object\n"
|
|
275
|
+
)
|
|
276
|
+
assert_equal [membership("foo", [[:until, "2.0.0"]])], graph.memberships("foo/1.9/Bar")
|
|
277
|
+
assert_equal [membership("foo", [[:since, "2.0.0"]])], graph.memberships("foo/2.0/Bar")
|
|
278
|
+
assert_equal ["foo/1.9/frag.rd", "foo/2.0/frag.rd"], graph.fragments
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def test_include_with_dotdot_path_is_normalized
|
|
282
|
+
# rdoc/parsers/parse_c.rd の #@include(../RDoc__KNOWN_CLASSES) に対応。
|
|
283
|
+
# 正規化しないと同一ファイルが別キーで二重登録される
|
|
284
|
+
graph = analyze(
|
|
285
|
+
"LIBRARIES" => "foo\n",
|
|
286
|
+
"foo.rd" => "\#@include(foo/sub/Baz)\n\#@include(foo/Bar)\n",
|
|
287
|
+
"foo/sub/Baz" => "= class Baz < Object\n\#@include(../Bar)\n",
|
|
288
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
289
|
+
)
|
|
290
|
+
assert_equal ["foo/Bar", "foo/sub/Baz"], graph.groupings.keys
|
|
291
|
+
assert_equal [membership("foo")], graph.memberships("foo/Bar")
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def test_include_cycle_terminates_with_warning
|
|
295
|
+
graph = analyze(
|
|
296
|
+
"LIBRARIES" => "foo\n",
|
|
297
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
298
|
+
"foo/Bar" => "= class Bar < Object\n\#@include(Baz)\n",
|
|
299
|
+
"foo/Baz" => "= class Baz < Object\n\#@include(Bar)\n"
|
|
300
|
+
)
|
|
301
|
+
assert graph.warnings.any? { |w| w.include?("cycle") },
|
|
302
|
+
"expected cycle warning, got: #{graph.warnings.inspect}"
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def test_missing_include_target_records_warning
|
|
306
|
+
graph = analyze(
|
|
307
|
+
"LIBRARIES" => "foo\n",
|
|
308
|
+
"foo.rd" => "\#@include(foo/Nothing)\n"
|
|
309
|
+
)
|
|
310
|
+
assert_equal ["include target not found: foo/Nothing (from foo.rd)"], graph.warnings
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def test_missing_library_root_records_warning
|
|
314
|
+
graph = analyze("LIBRARIES" => "ghost\n")
|
|
315
|
+
assert_equal ["library root not found: ghost.rd"], graph.warnings
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def test_samplecode_block_end_does_not_pop_version_gate
|
|
319
|
+
# #@samplecode ブロックも #@end で閉じるため、pop の対応を取る必要がある
|
|
320
|
+
src = <<~RRD
|
|
321
|
+
\#@since 3.2
|
|
322
|
+
\#@samplecode 例
|
|
323
|
+
p 1
|
|
324
|
+
\#@end
|
|
325
|
+
\#@include(foo/Bar)
|
|
326
|
+
\#@end
|
|
327
|
+
\#@include(foo/Baz)
|
|
328
|
+
RRD
|
|
329
|
+
graph = analyze(
|
|
330
|
+
"LIBRARIES" => "foo\n",
|
|
331
|
+
"foo.rd" => src,
|
|
332
|
+
"foo/Bar" => "= class Bar < Object\n",
|
|
333
|
+
"foo/Baz" => "= class Baz < Object\n"
|
|
334
|
+
)
|
|
335
|
+
assert_equal [membership("foo", [[:since, "3.2"]])], graph.memberships("foo/Bar")
|
|
336
|
+
assert_equal [membership("foo")], graph.memberships("foo/Baz")
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def test_include_allows_space_before_paren
|
|
340
|
+
# Preprocessor は #@include\s*\( を許容する
|
|
341
|
+
graph = analyze(
|
|
342
|
+
"LIBRARIES" => "foo\n",
|
|
343
|
+
"foo.rd" => "\#@include (foo/Bar)\n",
|
|
344
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
345
|
+
)
|
|
346
|
+
assert_equal [membership("foo")], graph.memberships("foo/Bar")
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# ---- interval とスコープ適用 ----
|
|
350
|
+
|
|
351
|
+
def conditions(*pairs)
|
|
352
|
+
pairs.map { |kind, version| BitClust::IncludeGraph::Condition.new(kind, version) }
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def interval(*pairs)
|
|
356
|
+
BitClust::IncludeGraph.interval(conditions(*pairs))
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def test_interval_unconstrained
|
|
360
|
+
assert_equal [nil, nil], interval
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def test_interval_since_takes_max_and_until_takes_min
|
|
364
|
+
assert_equal [Gem::Version.new("2.3.0"), nil], interval([:since, "2.3.0"])
|
|
365
|
+
assert_equal [nil, Gem::Version.new("2.7.0")], interval([:until, "2.7.0"])
|
|
366
|
+
assert_equal [Gem::Version.new("2.3.0"), Gem::Version.new("3.0")],
|
|
367
|
+
interval([:since, "1.9.1"], [:since, "2.3.0"], [:until, "3.1"], [:until, "3.0"])
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def test_interval_ignores_if_conditions
|
|
371
|
+
assert_equal [Gem::Version.new("3.2"), nil],
|
|
372
|
+
interval([:if, '(version > "1.8.2")'], [:since, "3.2"])
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def test_scope_cover
|
|
376
|
+
scope = BitClust::IncludeGraph::Scope.new("3.0", "4.2")
|
|
377
|
+
assert_true scope.cover?(conditions) # 無条件
|
|
378
|
+
assert_true scope.cover?(conditions([:since, "3.2"])) # Data
|
|
379
|
+
assert_true scope.cover?(conditions([:since, "2.3.0"])) # 下限跨ぎ
|
|
380
|
+
assert_true scope.cover?(conditions([:until, "3.1"])) # 上限側交差
|
|
381
|
+
assert_false scope.cover?(conditions([:until, "2.3.0"])) # thread 旧所属
|
|
382
|
+
assert_false scope.cover?(conditions([:until, "3.0"])) # 境界: [_,3.0) は交差なし
|
|
383
|
+
assert_false scope.cover?(conditions([:since, "4.2"])) # 境界: [4.2,_) は交差なし
|
|
384
|
+
assert_false scope.cover?(conditions([:since, "3.5"], [:until, "3.2"])) # 空区間
|
|
385
|
+
assert_true scope.cover?(conditions([:if, 'x'])) # :if は制約なし扱い
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def test_scope_gate_keeps_only_bounds_inside_scope
|
|
389
|
+
scope = BitClust::IncludeGraph::Scope.new("3.0", "4.2")
|
|
390
|
+
assert_equal({}, scope.gate(conditions))
|
|
391
|
+
assert_equal({ since: "3.2" }, scope.gate(conditions([:since, "3.2"])))
|
|
392
|
+
assert_equal({}, scope.gate(conditions([:since, "2.3.0"]))) # 下限以下は省略
|
|
393
|
+
assert_equal({}, scope.gate(conditions([:since, "3.0"]))) # 下限ちょうども省略
|
|
394
|
+
assert_equal({ until: "4.0" }, scope.gate(conditions([:until, "4.0"])))
|
|
395
|
+
assert_equal({ since: "3.2", until: "4.0" },
|
|
396
|
+
scope.gate(conditions([:since, "3.2"], [:until, "4.0"])))
|
|
397
|
+
assert_nil scope.gate(conditions([:until, "2.3.0"])) # スコープ外
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def test_scope_gate_preserves_original_version_spelling
|
|
401
|
+
scope = BitClust::IncludeGraph::Scope.new("3.0", "4.2")
|
|
402
|
+
assert_equal({ since: "3.2.0" }, scope.gate(conditions([:since, "3.2.0"])))
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def test_scope_always_and_never
|
|
406
|
+
scope = BitClust::IncludeGraph::Scope.new("3.0", "4.2")
|
|
407
|
+
cond = ->(kind, v) { BitClust::IncludeGraph::Condition.new(kind, v) }
|
|
408
|
+
# since v: スコープ全体で真 ⇔ v <= 下限
|
|
409
|
+
assert_true scope.always?(cond[:since, "2.3.0"])
|
|
410
|
+
assert_true scope.always?(cond[:since, "3.0"])
|
|
411
|
+
assert_false scope.always?(cond[:since, "3.2"])
|
|
412
|
+
assert_false scope.never?(cond[:since, "3.2"])
|
|
413
|
+
assert_true scope.never?(cond[:since, "4.2"])
|
|
414
|
+
# until v: スコープ全体で真 ⇔ v >= 上限
|
|
415
|
+
assert_true scope.always?(cond[:until, "4.2"])
|
|
416
|
+
assert_false scope.always?(cond[:until, "3.1"])
|
|
417
|
+
assert_true scope.never?(cond[:until, "3.0"])
|
|
418
|
+
assert_false scope.never?(cond[:until, "3.1"])
|
|
419
|
+
# if は原則判定不能(常に false)
|
|
420
|
+
assert_false scope.always?(cond[:if, "(version > \"1.8\")"])
|
|
421
|
+
assert_false scope.never?(cond[:if, "(version > \"1.8\")"])
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def test_scope_never_for_provable_if_conditions
|
|
425
|
+
# LIBRARIES の ubygems: #@if("1.9.1" <= version and version < "2.5.0")
|
|
426
|
+
scope = BitClust::IncludeGraph::Scope.new("3.0", "4.2")
|
|
427
|
+
cond = ->(v) { BitClust::IncludeGraph::Condition.new(:if, v) }
|
|
428
|
+
assert_true scope.never?(cond['("1.9.1" <= version and version < "2.5.0")'])
|
|
429
|
+
assert_true scope.never?(cond['(version < "1.8.2")'])
|
|
430
|
+
assert_true scope.never?(cond['(version == "2.0.0")'])
|
|
431
|
+
assert_false scope.never?(cond['(version >= "1.8.2")'])
|
|
432
|
+
assert_false scope.never?(cond['(version == "3.1")'])
|
|
433
|
+
assert_false scope.never?(cond['(version < "4.0")']) # スコープ内で真偽が変わる
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def test_scope_cover_excludes_never_if_conditions
|
|
437
|
+
scope = BitClust::IncludeGraph::Scope.new("3.0", "4.2")
|
|
438
|
+
conds = [BitClust::IncludeGraph::Condition.new(:if, '("1.9.1" <= version and version < "2.5.0")')]
|
|
439
|
+
assert_false scope.cover?(conds)
|
|
440
|
+
assert_nil scope.gate(conds)
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def test_scope_gate_decomposes_conjunctive_if_into_bounds
|
|
444
|
+
# 旧版サルベージ: ubygems の #@if("1.9.1" <= version and version < "2.5.0") は
|
|
445
|
+
# ワイドスコープでは in-scope になり、since/until に分解して front matter へ
|
|
446
|
+
scope = BitClust::IncludeGraph::Scope.new("1.8.7", "4.2")
|
|
447
|
+
conds = [BitClust::IncludeGraph::Condition.new(:if, '("1.9.1" <= version and version < "2.5.0")')]
|
|
448
|
+
assert_true scope.cover?(conds)
|
|
449
|
+
assert_equal({ since: "1.9.1", until: "2.5.0" }, scope.gate(conds))
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def test_scope_gate_decomposes_simple_if_forms
|
|
453
|
+
scope = BitClust::IncludeGraph::Scope.new("1.8.7", "4.2")
|
|
454
|
+
cond = ->(v) { [BitClust::IncludeGraph::Condition.new(:if, v)] }
|
|
455
|
+
# version >= "X" 形(rss)。X がスコープ下限以下なら無条件
|
|
456
|
+
assert_equal({}, scope.gate(cond['(version >= "1.8.2")']))
|
|
457
|
+
assert_equal({ since: "2.0.0" }, scope.gate(cond['(version >= "2.0.0")']))
|
|
458
|
+
# version < "X" 形は until X
|
|
459
|
+
assert_equal({ until: "2.0.0" }, scope.gate(cond['(version < "2.0.0")']))
|
|
460
|
+
# 分解できない形(<= / 否定)は境界に寄与しない(従来どおり無条件扱い)
|
|
461
|
+
assert_equal({}, scope.gate(cond['(version <= "2.0.0")']))
|
|
462
|
+
assert_equal({}, scope.gate(cond['!((version < "2.0.0"))']))
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# ---- front_matter_map: メンバーへの注入値(スコープ適用済み)----
|
|
466
|
+
|
|
467
|
+
def scope30_42
|
|
468
|
+
BitClust::IncludeGraph::Scope.new("3.0", "4.2")
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
def test_front_matter_map_simple_membership
|
|
472
|
+
graph = analyze(
|
|
473
|
+
"LIBRARIES" => "foo\n",
|
|
474
|
+
"foo.rd" => "\#@include(foo/Bar)\n",
|
|
475
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
476
|
+
)
|
|
477
|
+
assert_equal({ "foo/Bar" => { "library" => "foo" } }, graph.front_matter_map(scope30_42))
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def test_front_matter_map_with_structural_gate
|
|
481
|
+
graph = analyze(
|
|
482
|
+
"LIBRARIES" => "foo\n",
|
|
483
|
+
"foo.rd" => "\#@since 3.2\n\#@include(foo/Bar)\n\#@end\n",
|
|
484
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
485
|
+
)
|
|
486
|
+
assert_equal({ "foo/Bar" => { "library" => "foo", "since" => "3.2" } },
|
|
487
|
+
graph.front_matter_map(scope30_42))
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
def test_front_matter_map_excludes_out_of_scope_members
|
|
491
|
+
graph = analyze(
|
|
492
|
+
"LIBRARIES" => "foo\n",
|
|
493
|
+
"foo.rd" => "\#@until 2.4.0\n\#@include(foo/Bar)\n\#@end\n",
|
|
494
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
495
|
+
)
|
|
496
|
+
assert_equal({}, graph.front_matter_map(scope30_42))
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
def test_front_matter_map_multi_library_membership_becomes_list
|
|
500
|
+
# 同時多重所属(旧 rdoc の code_objects+個別ファイル等)は
|
|
501
|
+
# ゲート付きリスト形式で表現する(旧挙動の警告スキップを置換)
|
|
502
|
+
graph = analyze(
|
|
503
|
+
"LIBRARIES" => "foo\nbar\n",
|
|
504
|
+
"foo.rd" => "\#@include(shared/Thing)\n",
|
|
505
|
+
"bar.rd" => "\#@include(shared/Thing)\n",
|
|
506
|
+
"shared/Thing" => "= class Thing < Object\n"
|
|
507
|
+
)
|
|
508
|
+
assert_equal(
|
|
509
|
+
{ "shared/Thing" => { "library" => [
|
|
510
|
+
{ "name" => "bar" }, { "name" => "foo" }
|
|
511
|
+
] } },
|
|
512
|
+
graph.front_matter_map(scope30_42))
|
|
513
|
+
assert graph.warnings.none? { |w| w.include?("multi-membership") },
|
|
514
|
+
"multi-membership should be supported now, got: #{graph.warnings.inspect}"
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
def test_front_matter_map_multi_membership_orders_modern_side_first
|
|
518
|
+
# Mutex 型: 片方は無条件、片方は until 付き →
|
|
519
|
+
# 「現在まで存在する側」(until なし)を先頭に置く
|
|
520
|
+
graph = analyze(
|
|
521
|
+
"LIBRARIES" => "thread\nbuiltin\n",
|
|
522
|
+
"builtin.rd" => "\#@include(shared/Mutex)\n",
|
|
523
|
+
"thread.rd" => "\#@until 3.1\n\#@include(shared/Mutex)\n\#@end\n",
|
|
524
|
+
"shared/Mutex" => "= class Mutex < Object\n"
|
|
525
|
+
)
|
|
526
|
+
assert_equal(
|
|
527
|
+
{ "shared/Mutex" => { "library" => [
|
|
528
|
+
{ "name" => "builtin" },
|
|
529
|
+
{ "name" => "thread", "until" => "3.1" }
|
|
530
|
+
] } },
|
|
531
|
+
graph.front_matter_map(scope30_42))
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
def test_front_matter_map_multi_membership_partition_has_no_entity_gate
|
|
535
|
+
# ConditionVariable 型: since X / until X の相補分割。
|
|
536
|
+
# エンティティ自体はスコープ全域に存在するので since/until キーは付かない
|
|
537
|
+
graph = analyze(
|
|
538
|
+
"LIBRARIES" => "thread\nbuiltin\n",
|
|
539
|
+
"builtin.rd" => "\#@since 3.2\n\#@include(shared/CV)\n\#@end\n",
|
|
540
|
+
"thread.rd" => "\#@until 3.2\n\#@include(shared/CV)\n\#@end\n",
|
|
541
|
+
"shared/CV" => "= class ConditionVariable < Object\n"
|
|
542
|
+
)
|
|
543
|
+
fm = graph.front_matter_map(scope30_42)
|
|
544
|
+
assert_equal(
|
|
545
|
+
[{ "name" => "builtin", "since" => "3.2" },
|
|
546
|
+
{ "name" => "thread", "until" => "3.2" }],
|
|
547
|
+
fm["shared/CV"]["library"])
|
|
548
|
+
assert_nil fm["shared/CV"]["since"]
|
|
549
|
+
assert_nil fm["shared/CV"]["until"]
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def test_front_matter_map_takes_interval_hull_within_same_library
|
|
553
|
+
# 同一ライブラリから複数サイトで include される場合、エンティティは
|
|
554
|
+
# いずれかのサイトが有効なら存在する → ゲートは区間の hull(弱い方)を取る
|
|
555
|
+
graph = analyze(
|
|
556
|
+
"LIBRARIES" => "foo\n",
|
|
557
|
+
"foo.rd" => "\#@since 3.2\n\#@include(foo/Bar)\n\#@end\n" \
|
|
558
|
+
"\#@since 3.1\n\#@include(foo/Bar)\n\#@end\n",
|
|
559
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
560
|
+
)
|
|
561
|
+
assert_equal({ "foo/Bar" => { "library" => "foo", "since" => "3.1" } },
|
|
562
|
+
graph.front_matter_map(scope30_42))
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
def test_front_matter_map_unconditional_site_wins_over_gated_site
|
|
566
|
+
graph = analyze(
|
|
567
|
+
"LIBRARIES" => "foo\n",
|
|
568
|
+
"foo.rd" => "\#@include(foo/Bar)\n\#@since 3.2\n\#@include(foo/Bar)\n\#@end\n",
|
|
569
|
+
"foo/Bar" => "= class Bar < Object\n"
|
|
570
|
+
)
|
|
571
|
+
assert_equal({ "foo/Bar" => { "library" => "foo" } }, graph.front_matter_map(scope30_42))
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
# ---- grouping_include_sites: prune 対象(ファイル => 記載どおりの target)----
|
|
575
|
+
|
|
576
|
+
def test_grouping_include_sites
|
|
577
|
+
graph = analyze(
|
|
578
|
+
"LIBRARIES" => "foo\n",
|
|
579
|
+
"foo.rd" => "\#@include(foo/Bar)\n\#@include(foo/frag)\n",
|
|
580
|
+
"foo/Bar" => "= class Bar < Object\n\#@include(Baz)\n\#@include(frag2)\n",
|
|
581
|
+
"foo/Baz" => "= class Baz < Object\n",
|
|
582
|
+
"foo/frag" => "断片。\n",
|
|
583
|
+
"foo/frag2" => "断片2。\n"
|
|
584
|
+
)
|
|
585
|
+
# fragment include(foo/frag, frag2)は含まれない。target は記載どおりの文字列
|
|
586
|
+
assert_equal({ "foo.rd" => ["foo/Bar"], "foo/Bar" => ["Baz"] },
|
|
587
|
+
graph.grouping_include_sites)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def test_grouping_include_sites_dedupes_multi_path_walks
|
|
591
|
+
# 同一ファイルが複数経路で走査されてもサイトは重複しない
|
|
592
|
+
graph = analyze(
|
|
593
|
+
"LIBRARIES" => "foo\nbar\n",
|
|
594
|
+
"foo.rd" => "\#@include(shared/frag)\n",
|
|
595
|
+
"bar.rd" => "\#@include(shared/frag)\n",
|
|
596
|
+
"shared/frag" => "断片。\n\#@include(Thing)\n",
|
|
597
|
+
"shared/Thing" => "= class Thing < Object\n"
|
|
598
|
+
)
|
|
599
|
+
assert_equal({ "shared/frag" => ["Thing"] }, graph.grouping_include_sites)
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
# ---- library_front_matter_map: ライブラリ概要ファイルへの注入値 ----
|
|
603
|
+
|
|
604
|
+
def test_library_front_matter_map_marks_roots
|
|
605
|
+
graph = analyze(
|
|
606
|
+
"LIBRARIES" => "foo\nbar/sub\n",
|
|
607
|
+
"foo.rd" => "本文。\n",
|
|
608
|
+
"bar/sub.rd" => "本文。\n"
|
|
609
|
+
)
|
|
610
|
+
assert_equal(
|
|
611
|
+
{ "foo.rd" => { "type" => "library" }, "bar/sub.rd" => { "type" => "library" } },
|
|
612
|
+
graph.library_front_matter_map(scope30_42)
|
|
613
|
+
)
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def test_library_front_matter_map_applies_scoped_gate
|
|
617
|
+
# LIBRARIES の fiber: until 3.1 / set: until 3.2 に相当
|
|
618
|
+
graph = analyze(
|
|
619
|
+
"LIBRARIES" => "\#@until 3.1\nfoo\n\#@end\nbar\n",
|
|
620
|
+
"foo.rd" => "本文。\n",
|
|
621
|
+
"bar.rd" => "本文。\n"
|
|
622
|
+
)
|
|
623
|
+
assert_equal(
|
|
624
|
+
{ "foo.rd" => { "type" => "library", "until" => "3.1" },
|
|
625
|
+
"bar.rd" => { "type" => "library" } },
|
|
626
|
+
graph.library_front_matter_map(scope30_42)
|
|
627
|
+
)
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def test_library_front_matter_map_excludes_out_of_scope_libraries
|
|
631
|
+
# cmath/scanf/sync(until 2.7.0)は [3.0,4.2) の対象外
|
|
632
|
+
graph = analyze(
|
|
633
|
+
"LIBRARIES" => "\#@until 2.7.0\nfoo\n\#@end\nbar\n",
|
|
634
|
+
"foo.rd" => "本文。\n",
|
|
635
|
+
"bar.rd" => "本文。\n"
|
|
636
|
+
)
|
|
637
|
+
assert_equal({ "bar.rd" => { "type" => "library" } },
|
|
638
|
+
graph.library_front_matter_map(scope30_42))
|
|
639
|
+
end
|
|
640
|
+
end
|