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,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
|
|
5
|
+
require 'bitclust/include_pruner'
|
|
6
|
+
|
|
7
|
+
# IncludePruner: RD テキストから指定 target の #@include 行を除去する純変換(rd→rd)。
|
|
8
|
+
# 新パイプラインでは grouping include(エンティティの取り込み)は glob + front matter の
|
|
9
|
+
# 発見に置き換わるため、ライブラリ概要ファイルから除去する。fragment include は温存。
|
|
10
|
+
#
|
|
11
|
+
# テストリスト:
|
|
12
|
+
# [x] target が無ければ入力を変更しない(バイト一致)
|
|
13
|
+
# [x] 指定 target の #@include 行を除去する
|
|
14
|
+
# [x] 指定外の target(fragment include)は残す
|
|
15
|
+
# [x] 連続する include 行の除去
|
|
16
|
+
# [x] 空行で区切られた include 群 → 空行が1つに畳まれる(net/http.rd パターン)
|
|
17
|
+
# [x] 除去で空になった版ゲートブロックはブロックごと除去(_builtin.rd の Bignum パターン)
|
|
18
|
+
# [x] ネストしたブロックが連鎖的に空になる場合も除去
|
|
19
|
+
# [x] #@else 枝の中の include 除去、枝に他の内容があればブロックは残る(thread.rd パターン)
|
|
20
|
+
# [x] 片枝だけ空になった #@else ブロックは構造を保持
|
|
21
|
+
# [x] 両枝とも空になったブロックは全体を除去
|
|
22
|
+
# [x] もともと空のブロックは(除去が起きなければ)そのまま
|
|
23
|
+
# [x] 末尾 include 除去後、直前の空行は保持する(continuation.rd/webrick/server.rd パターン。
|
|
24
|
+
# メタデータ領域再生成の空行仕様と整合し md→rd がバイト一致する。空行終端は既存149ファイルと同スタイル)
|
|
25
|
+
# [x] ファイル先頭の include 除去で残る先頭空行は削る(doctree 正規化と整合)
|
|
26
|
+
# [x] #@samplecode ブロックは版ゲートとして扱わない(空でも除去しない)
|
|
27
|
+
class TestIncludePruner < Test::Unit::TestCase
|
|
28
|
+
def prune(src, targets)
|
|
29
|
+
BitClust::IncludePruner.prune(src, targets)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_no_targets_returns_input_unchanged
|
|
33
|
+
src = "text\n\n\#@include(foo/Bar)\n"
|
|
34
|
+
assert_equal src, prune(src, [])
|
|
35
|
+
assert_equal src, prune(src, ["other/Target"])
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_removes_matching_include_line
|
|
39
|
+
src = "text\n\#@include(foo/Bar)\ntext2\n"
|
|
40
|
+
assert_equal "text\ntext2\n", prune(src, ["foo/Bar"])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_keeps_non_matching_includes
|
|
44
|
+
src = "\#@include(frag)\n\#@include(foo/Bar)\n"
|
|
45
|
+
assert_equal "\#@include(frag)\n", prune(src, ["foo/Bar"])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_unbalanced_gates_leave_input_unchanged
|
|
49
|
+
# 対応の取れない #@end を含むファイルは構造が判定できないので手を付けない
|
|
50
|
+
src = "\#@end\n\#@include(a/A)\n"
|
|
51
|
+
assert_equal src, prune(src, ["a/A"])
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_removes_consecutive_includes
|
|
55
|
+
src = "text\n\n\#@include(a/A)\n\#@include(a/B)\n\#@include(a/C)\n"
|
|
56
|
+
assert_equal "text\n\n", prune(src, ["a/A", "a/B", "a/C"])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_collapses_blank_lines_between_removed_includes
|
|
60
|
+
# net/http.rd: include が空行区切りで並ぶ
|
|
61
|
+
src = "text\n\n\#@include(a/A)\n\n\#@include(a/B)\n\n\#@include(a/C)\n\ntext2\n"
|
|
62
|
+
assert_equal "text\n\ntext2\n", prune(src, ["a/A", "a/B", "a/C"])
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_removes_emptied_gate_block
|
|
66
|
+
# _builtin.rd: #@until 2.4.0 / #@include(_builtin/Bignum) / #@end
|
|
67
|
+
src = "\#@include(a/A)\n\#@until 2.4.0\n\#@include(a/B)\n\#@end\n\#@include(a/C)\n"
|
|
68
|
+
assert_equal "", prune(src, ["a/A", "a/B", "a/C"])
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_removes_nested_emptied_blocks
|
|
72
|
+
src = "text\n\#@since 2.0.0\n\#@until 3.0\n\#@include(a/A)\n\#@end\n\#@end\n"
|
|
73
|
+
assert_equal "text\n", prune(src, ["a/A"])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_keeps_block_when_branch_retains_content
|
|
77
|
+
# thread.rd: #@else 枝に散文とエンティティ定義が残る
|
|
78
|
+
src = <<~RRD
|
|
79
|
+
\#@since 2.3.0
|
|
80
|
+
新しい説明。
|
|
81
|
+
\#@else
|
|
82
|
+
古い説明。
|
|
83
|
+
\#@until 1.9.1
|
|
84
|
+
\#@include(thread/Mutex)
|
|
85
|
+
\#@end
|
|
86
|
+
\#@include(thread/Queue)
|
|
87
|
+
\#@end
|
|
88
|
+
RRD
|
|
89
|
+
expected = <<~RRD
|
|
90
|
+
\#@since 2.3.0
|
|
91
|
+
新しい説明。
|
|
92
|
+
\#@else
|
|
93
|
+
古い説明。
|
|
94
|
+
\#@end
|
|
95
|
+
RRD
|
|
96
|
+
assert_equal expected, prune(src, ["thread/Mutex", "thread/Queue"])
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_keeps_block_structure_when_only_one_branch_empties
|
|
100
|
+
src = "\#@until 2.0.0\n\#@include(a/Old)\n\#@else\n説明。\n\#@end\n"
|
|
101
|
+
expected = "\#@until 2.0.0\n\#@else\n説明。\n\#@end\n"
|
|
102
|
+
assert_equal expected, prune(src, ["a/Old"])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_removes_block_when_both_branches_empty
|
|
106
|
+
src = "text\n\#@until 2.0.0\n\#@include(a/Old)\n\#@else\n\#@include(a/New)\n\#@end\n"
|
|
107
|
+
assert_equal "text\n", prune(src, ["a/Old", "a/New"])
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_keeps_preexisting_empty_block_without_removal
|
|
111
|
+
src = "\#@since 2.0.0\n\#@end\ntext\n\#@include(a/A)\n"
|
|
112
|
+
assert_equal "\#@since 2.0.0\n\#@end\ntext\n", prune(src, ["a/A"])
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def test_keeps_preceding_blank_when_trailing_include_removed
|
|
116
|
+
# continuation.rd: 本文 + 空行 + include で終わる。空行は保持する
|
|
117
|
+
# (webrick/server.rd の require 群 + 空行 + include 群でも、md→rd の
|
|
118
|
+
# メタデータ再生成が「require 群 + 空行」を出すため、保持しないと一致しない)
|
|
119
|
+
src = "本文。\n\n\#@include(_builtin/Continuation)\n"
|
|
120
|
+
assert_equal "本文。\n\n", prune(src, ["_builtin/Continuation"])
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_strips_leading_blank_after_removal_at_bof
|
|
124
|
+
src = "\#@include(a/A)\n\ntext\n"
|
|
125
|
+
assert_equal "text\n", prune(src, ["a/A"])
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def test_samplecode_block_is_not_a_gate_block
|
|
129
|
+
# samplecode の #@end を版ゲートと混同すると対応が壊れる
|
|
130
|
+
src = "\#@samplecode 例\ncode\n\#@end\n\#@since 3.0\n\#@include(a/A)\n\#@end\n"
|
|
131
|
+
assert_equal "\#@samplecode 例\ncode\n\#@end\n", prune(src, ["a/A"])
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'bitclust'
|
|
7
|
+
require 'bitclust/methoddatabase'
|
|
8
|
+
require 'bitclust/link_checker'
|
|
9
|
+
|
|
10
|
+
# bitclust#286 派生の要望: [[c:]]/[[m:]] 等の参照は描画時に存在検証されず
|
|
11
|
+
# リンク切れが静かに発生するため、DB 全体を走査して壊れた参照を報告する
|
|
12
|
+
# LinkChecker を提供する。抽出は実際のコンパイル経路(bracket_link)を
|
|
13
|
+
# 使うので、コードスパン・フェンス内の参照風テキストは対象外になる。
|
|
14
|
+
class TestLinkChecker < Test::Unit::TestCase
|
|
15
|
+
FOO_MD = <<~'MD'
|
|
16
|
+
---
|
|
17
|
+
library: foo
|
|
18
|
+
---
|
|
19
|
+
# class Foo < Object
|
|
20
|
+
|
|
21
|
+
正しい参照: [c:Foo] と [m:Foo#bar] と [m:Foo.baz] と [m:Foo::CONST]
|
|
22
|
+
と [lib:foo] と [d:spec/page]。
|
|
23
|
+
|
|
24
|
+
壊れた参照: [c:Nope] と [m:Foo#nope] と [m:Nope#x] と [lib:nolib]
|
|
25
|
+
と [d:spec/nope]。
|
|
26
|
+
|
|
27
|
+
コードスパン内は対象外: `[c:CodeSpan]`。
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
# フェンス内も対象外: [m:Fence#no]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Instance Methods
|
|
34
|
+
|
|
35
|
+
### def bar -> nil
|
|
36
|
+
|
|
37
|
+
メソッド本文からの壊れた参照: [m:Foo#missing_from_method]
|
|
38
|
+
|
|
39
|
+
## Class Methods
|
|
40
|
+
|
|
41
|
+
### def baz -> nil
|
|
42
|
+
|
|
43
|
+
baz です。
|
|
44
|
+
|
|
45
|
+
## Constants
|
|
46
|
+
|
|
47
|
+
### const CONST -> Integer
|
|
48
|
+
|
|
49
|
+
定数です。
|
|
50
|
+
MD
|
|
51
|
+
|
|
52
|
+
def build_db(dir)
|
|
53
|
+
api = File.join(dir, 'manual', 'api')
|
|
54
|
+
FileUtils.mkdir_p(File.join(api, 'foo'))
|
|
55
|
+
FileUtils.mkdir_p(File.join(dir, 'manual', 'doc', 'spec'))
|
|
56
|
+
File.write(File.join(api, 'foo.md'),
|
|
57
|
+
"---\ntype: library\n---\nライブラリ概要。壊れた参照: [c:AlsoNope]\n")
|
|
58
|
+
File.write(File.join(api, 'foo', 'Foo.md'), FOO_MD)
|
|
59
|
+
File.write(File.join(dir, 'manual', 'doc', 'spec', 'page.md'),
|
|
60
|
+
"# ページ\n\ndoc からの壊れた参照: [m:Foo#doc_missing]。正しい参照: [c:Foo]。\n")
|
|
61
|
+
|
|
62
|
+
prefix = File.join(dir, 'db')
|
|
63
|
+
db = BitClust::MethodDatabase.new(prefix)
|
|
64
|
+
db.init
|
|
65
|
+
db.transaction do
|
|
66
|
+
db.propset('version', '3.4')
|
|
67
|
+
db.propset('encoding', 'utf-8')
|
|
68
|
+
end
|
|
69
|
+
db.transaction do
|
|
70
|
+
db.update_by_markdowntree(api)
|
|
71
|
+
end
|
|
72
|
+
BitClust::MethodDatabase.new(prefix)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_check_all_reports_only_broken_refs
|
|
76
|
+
Dir.mktmpdir do |dir|
|
|
77
|
+
db = build_db(dir)
|
|
78
|
+
findings = BitClust::LinkChecker.new(db).check_all
|
|
79
|
+
refs = findings.map(&:ref).sort
|
|
80
|
+
assert_equal(
|
|
81
|
+
[
|
|
82
|
+
'c:AlsoNope',
|
|
83
|
+
'c:Nope',
|
|
84
|
+
'd:spec/nope',
|
|
85
|
+
'lib:nolib',
|
|
86
|
+
'm:Foo#doc_missing',
|
|
87
|
+
'm:Foo#missing_from_method',
|
|
88
|
+
'm:Foo#nope',
|
|
89
|
+
'm:Nope#x',
|
|
90
|
+
],
|
|
91
|
+
refs
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def test_findings_carry_location
|
|
97
|
+
Dir.mktmpdir do |dir|
|
|
98
|
+
db = build_db(dir)
|
|
99
|
+
findings = BitClust::LinkChecker.new(db).check_all
|
|
100
|
+
f = findings.find { |x| x.ref == 'm:Foo#nope' }
|
|
101
|
+
assert_not_nil f
|
|
102
|
+
assert_match(/Foo\.md/, f.location.to_s)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def test_exit_style_summary
|
|
107
|
+
Dir.mktmpdir do |dir|
|
|
108
|
+
db = build_db(dir)
|
|
109
|
+
checker = BitClust::LinkChecker.new(db)
|
|
110
|
+
checker.check_all
|
|
111
|
+
assert_equal 8, checker.broken_count
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'tmpdir'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'stringio'
|
|
6
|
+
require 'bitclust'
|
|
7
|
+
require 'bitclust/methoddatabase'
|
|
8
|
+
require 'bitclust/subcommands/lookup_command'
|
|
9
|
+
|
|
10
|
+
# lookup サブコマンド(bitclust#294)。
|
|
11
|
+
#
|
|
12
|
+
# テストリスト:
|
|
13
|
+
# [x] --method --html が Markdown ソースの DB で HTML を返す
|
|
14
|
+
# (シグネチャ dt に index_id の id 属性と permalink が付く)
|
|
15
|
+
# [x] --method --html が RD ソースの DB でも HTML を返す
|
|
16
|
+
# [x] --method(text)は従来どおりソースをそのまま出力する
|
|
17
|
+
# [x] --class --html は従来どおり動く
|
|
18
|
+
class TestLookupCommand < Test::Unit::TestCase
|
|
19
|
+
FOO_MD = <<~'MD'
|
|
20
|
+
---
|
|
21
|
+
library: foo
|
|
22
|
+
---
|
|
23
|
+
# class Foo < Object
|
|
24
|
+
|
|
25
|
+
クラスの説明。
|
|
26
|
+
|
|
27
|
+
## Instance Methods
|
|
28
|
+
|
|
29
|
+
### def bar -> nil
|
|
30
|
+
|
|
31
|
+
bar の説明。
|
|
32
|
+
MD
|
|
33
|
+
|
|
34
|
+
FOO_RD = <<~'RD'
|
|
35
|
+
description
|
|
36
|
+
|
|
37
|
+
= class Foo < Object
|
|
38
|
+
|
|
39
|
+
クラスの説明。
|
|
40
|
+
|
|
41
|
+
== Instance Methods
|
|
42
|
+
|
|
43
|
+
--- bar -> nil
|
|
44
|
+
|
|
45
|
+
bar の説明。
|
|
46
|
+
RD
|
|
47
|
+
|
|
48
|
+
def build_markdown_db(dir)
|
|
49
|
+
api = File.join(dir, 'manual', 'api')
|
|
50
|
+
FileUtils.mkdir_p(File.join(api, 'foo'))
|
|
51
|
+
File.write(File.join(api, 'foo.md'), "---\ntype: library\n---\nfoo ライブラリ。\n")
|
|
52
|
+
File.write(File.join(api, 'foo', 'Foo.md'), FOO_MD)
|
|
53
|
+
prefix = File.join(dir, 'db')
|
|
54
|
+
db = BitClust::MethodDatabase.new(prefix)
|
|
55
|
+
db.init
|
|
56
|
+
db.transaction do
|
|
57
|
+
db.propset('version', '3.4')
|
|
58
|
+
db.propset('encoding', 'utf-8')
|
|
59
|
+
end
|
|
60
|
+
db.transaction do
|
|
61
|
+
db.update_by_markdowntree(api)
|
|
62
|
+
end
|
|
63
|
+
prefix
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def build_rd_db(dir)
|
|
67
|
+
root = File.join(dir, 'refm', 'api', 'src')
|
|
68
|
+
FileUtils.mkdir_p(root)
|
|
69
|
+
File.write(File.join(root, 'LIBRARIES'), "foo\n")
|
|
70
|
+
File.write(File.join(root, 'foo.rd'), FOO_RD)
|
|
71
|
+
prefix = File.join(dir, 'db')
|
|
72
|
+
db = BitClust::MethodDatabase.new(prefix)
|
|
73
|
+
db.init
|
|
74
|
+
db.transaction do
|
|
75
|
+
db.propset('version', '3.4')
|
|
76
|
+
db.propset('encoding', 'utf-8')
|
|
77
|
+
end
|
|
78
|
+
db.transaction do
|
|
79
|
+
db.update_by_stdlibtree(root)
|
|
80
|
+
end
|
|
81
|
+
prefix
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def run_lookup(prefix, argv)
|
|
85
|
+
cmd = BitClust::Subcommands::LookupCommand.new
|
|
86
|
+
cmd.parse(argv)
|
|
87
|
+
out = StringIO.new
|
|
88
|
+
orig_stdout = $stdout
|
|
89
|
+
$stdout = out
|
|
90
|
+
begin
|
|
91
|
+
cmd.exec([], { prefix: prefix, capi: false })
|
|
92
|
+
ensure
|
|
93
|
+
$stdout = orig_stdout
|
|
94
|
+
end
|
|
95
|
+
out.string
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_method_html_on_markdown_db
|
|
99
|
+
Dir.mktmpdir do |dir|
|
|
100
|
+
prefix = build_markdown_db(dir)
|
|
101
|
+
html = run_lookup(prefix, ['--method', 'Foo#bar', '--html'])
|
|
102
|
+
assert_match(/<dt class="method-heading" id="[^"]+"><code>bar/, html)
|
|
103
|
+
assert_match(/permalink/, html)
|
|
104
|
+
assert_match(/bar の説明。/, html)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def test_method_html_on_rd_db
|
|
109
|
+
Dir.mktmpdir do |dir|
|
|
110
|
+
prefix = build_rd_db(dir)
|
|
111
|
+
html = run_lookup(prefix, ['--method', 'Foo#bar', '--html'])
|
|
112
|
+
assert_match(/<dt class="method-heading" id="[^"]+"><code>bar/, html)
|
|
113
|
+
assert_match(/permalink/, html)
|
|
114
|
+
assert_match(/bar の説明。/, html)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def test_method_text
|
|
119
|
+
Dir.mktmpdir do |dir|
|
|
120
|
+
prefix = build_markdown_db(dir)
|
|
121
|
+
text = run_lookup(prefix, ['--method', 'Foo#bar'])
|
|
122
|
+
assert_match(/\Atype: instance_method$/, text)
|
|
123
|
+
assert_match(/^### def bar -> nil$/, text)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_class_html
|
|
128
|
+
Dir.mktmpdir do |dir|
|
|
129
|
+
prefix = build_markdown_db(dir)
|
|
130
|
+
html = run_lookup(prefix, ['--class', 'Foo', '--html'])
|
|
131
|
+
assert_match(%r{<dt>name</dt><dd>Foo</dd>}, html)
|
|
132
|
+
assert_match(/クラスの説明。/, html)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
|
|
7
|
+
require 'bitclust/markdown_bridge'
|
|
8
|
+
|
|
9
|
+
# MarkdownBridge: md ツリー → 旧形式の rd ツリー(LIBRARIES + .rd)を生成する。
|
|
10
|
+
# 既存の update 機構(LIBRARIES → RRDParser/Preprocessor)をそのまま使って
|
|
11
|
+
# md ツリーから DB を組み立てるためのブリッジ。
|
|
12
|
+
#
|
|
13
|
+
# テストリスト:
|
|
14
|
+
# [x] LIBRARIES を発見結果から再生成(名前順、版ゲート付きライブラリは #@ で包む)
|
|
15
|
+
# [x] ライブラリ .rd = 変換済み本文 + メンバーへの #@include(lib のディレクトリ相対)
|
|
16
|
+
# [x] メンバー rd = 変換済み本文を front matter の since/until で #@ ラップ
|
|
17
|
+
# [x] 断片は拡張子なしで emit、include ターゲットは emit 名へ書き換え
|
|
18
|
+
# [x] dual ファイル(lib + インライン・エンティティ)はゲートラップしない(LIBRARIES 側で処理)
|
|
19
|
+
class TestMarkdownBridge < Test::Unit::TestCase
|
|
20
|
+
FILES = {
|
|
21
|
+
"foo.md" => "---\ntype: library\ncategory: Cat\n---\n概要。\n\n\#@include(frag)\n",
|
|
22
|
+
"foo/A.md" => "---\nlibrary: foo\nsince: \"3.2\"\n---\n# class A < Object\n\nA。\n",
|
|
23
|
+
"foo/B.md" => "---\nlibrary: foo\n---\n# class B < Object\nB。\n",
|
|
24
|
+
"frag.md" => "断片。\n",
|
|
25
|
+
"gated.md" => "---\ntype: library\nuntil: \"3.1\"\n---\ngated 概要。\n",
|
|
26
|
+
"bar/baz.md" => "---\ntype: library\n---\nbaz 概要。\n",
|
|
27
|
+
"bar/C.md" => "---\nlibrary: bar/baz\n---\n# class C < Object\nC。\n",
|
|
28
|
+
"dual.md" => "---\ntype: library\n---\n# class Dual < Object\nDual。\n",
|
|
29
|
+
# 大文字小文字衝突回避で改名されたサブライブラリ(rdoc/rdoc.lib.md 型)。
|
|
30
|
+
# 名前は front matter の name: が正
|
|
31
|
+
"sub/Sub.md" => "---\nlibrary: sub/sub\n---\n# class Sub < Object\nSub。\n",
|
|
32
|
+
"sub/sub.lib.md" => "---\ntype: library\nname: sub/sub\n---\nsub 概要。\n",
|
|
33
|
+
}.freeze
|
|
34
|
+
|
|
35
|
+
def build
|
|
36
|
+
Dir.mktmpdir do |md|
|
|
37
|
+
FILES.each do |path, content|
|
|
38
|
+
full = File.join(md, path)
|
|
39
|
+
FileUtils.mkdir_p(File.dirname(full))
|
|
40
|
+
File.write(full, content)
|
|
41
|
+
end
|
|
42
|
+
Dir.mktmpdir do |out|
|
|
43
|
+
BitClust::MarkdownBridge.build(md, out)
|
|
44
|
+
result = {}
|
|
45
|
+
Dir.glob('**/*', base: out).each do |f|
|
|
46
|
+
full = File.join(out, f)
|
|
47
|
+
result[f] = File.read(full) if File.file?(full)
|
|
48
|
+
end
|
|
49
|
+
return result
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def build_from(files)
|
|
55
|
+
Dir.mktmpdir do |md|
|
|
56
|
+
files.each do |path, content|
|
|
57
|
+
full = File.join(md, path)
|
|
58
|
+
FileUtils.mkdir_p(File.dirname(full))
|
|
59
|
+
File.write(full, content)
|
|
60
|
+
end
|
|
61
|
+
Dir.mktmpdir do |out|
|
|
62
|
+
BitClust::MarkdownBridge.build(md, out)
|
|
63
|
+
result = {}
|
|
64
|
+
Dir.glob('**/*', base: out).each do |f|
|
|
65
|
+
full = File.join(out, f)
|
|
66
|
+
result[f] = File.read(full) if File.file?(full)
|
|
67
|
+
end
|
|
68
|
+
return result
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_gated_membership_wraps_include_sites
|
|
74
|
+
# 多重所属(ゲート付き library リスト): 各ライブラリの .rd に、その
|
|
75
|
+
# membership のゲートで #@include サイトをラップして再具現化する
|
|
76
|
+
out = build_from(
|
|
77
|
+
"builtin.md" => "---\ntype: library\n---\nbuiltin 概要。\n",
|
|
78
|
+
"thread.md" => "---\ntype: library\n---\nthread 概要。\n",
|
|
79
|
+
"thread/Mutex.md" =>
|
|
80
|
+
"---\n" \
|
|
81
|
+
"library:\n" \
|
|
82
|
+
" - builtin\n" \
|
|
83
|
+
"\#@until 1.9.1\n" \
|
|
84
|
+
" - thread\n" \
|
|
85
|
+
"\#@end\n" \
|
|
86
|
+
"---\n" \
|
|
87
|
+
"# class Mutex < Object\nM。\n"
|
|
88
|
+
)
|
|
89
|
+
assert_equal "builtin 概要。\n\n\#@include(thread/Mutex)\n", out["builtin.rd"]
|
|
90
|
+
assert_equal "thread 概要。\n\n\#@until 1.9.1\n\#@include(thread/Mutex)\n\#@end\n",
|
|
91
|
+
out["thread.rd"]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def test_libraries_manifest
|
|
95
|
+
out = build
|
|
96
|
+
assert_equal "bar/baz\ndual\nfoo\n\#@until 3.1\ngated\n\#@end\nsub/sub\n", out["LIBRARIES"]
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_renamed_library_file_emits_by_front_matter_name
|
|
100
|
+
# sub/sub.lib.md(大文字小文字衝突回避の改名)は name: のライブラリ名で
|
|
101
|
+
# <name>.rd に emit され、メンバー include も付く
|
|
102
|
+
out = build
|
|
103
|
+
assert_equal "sub 概要。\n\n\#@include(Sub)\n", out["sub/sub.rd"]
|
|
104
|
+
assert_nil out["sub/sub.lib"]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def test_source_map_maps_emitted_to_md
|
|
108
|
+
# source_location の md パスへの再マップ用(emit 相対 → md 相対)
|
|
109
|
+
Dir.mktmpdir do |md|
|
|
110
|
+
FILES.each do |path, content|
|
|
111
|
+
full = File.join(md, path)
|
|
112
|
+
FileUtils.mkdir_p(File.dirname(full))
|
|
113
|
+
File.write(full, content)
|
|
114
|
+
end
|
|
115
|
+
Dir.mktmpdir do |out|
|
|
116
|
+
bridge = BitClust::MarkdownBridge.build(md, out)
|
|
117
|
+
assert_equal "foo.md", bridge.source_map["foo.rd"]
|
|
118
|
+
assert_equal "foo/A.md", bridge.source_map["foo/A"]
|
|
119
|
+
assert_equal "frag.md", bridge.source_map["frag"]
|
|
120
|
+
return
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def test_build_doc_returns_source_map
|
|
126
|
+
Dir.mktmpdir do |md|
|
|
127
|
+
File.write(File.join(md, "index.md"), "# はじめに\n\n本文。\n")
|
|
128
|
+
Dir.mktmpdir do |out|
|
|
129
|
+
map = BitClust::MarkdownBridge.build_doc(md, File.join(out, "doc"))
|
|
130
|
+
assert_equal({ "index.rd" => "index.md" }, map)
|
|
131
|
+
return
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def test_library_rd_with_member_includes
|
|
137
|
+
out = build
|
|
138
|
+
assert_equal "category Cat\n\n概要。\n\n\#@include(frag)\n\n" \
|
|
139
|
+
"\#@include(foo/A)\n\#@include(foo/B)\n", out["foo.rd"]
|
|
140
|
+
assert_equal "baz 概要。\n\n\#@include(C)\n", out["bar/baz.rd"]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def test_member_rd_with_gate_wrapper
|
|
144
|
+
out = build
|
|
145
|
+
assert_equal "\#@since 3.2\n= class A < Object\n\nA。\n\#@end\n", out["foo/A"]
|
|
146
|
+
assert_equal "= class B < Object\nB。\n", out["foo/B"]
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_fragment_is_emitted_without_extension
|
|
150
|
+
out = build
|
|
151
|
+
assert_equal "断片。\n", out["frag"]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def test_dual_file_keeps_inline_entities_without_wrapper
|
|
155
|
+
out = build
|
|
156
|
+
assert_equal "= class Dual < Object\nDual。\n", out["dual.rd"]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def test_build_doc_emits_local_fragments_without_extension
|
|
160
|
+
# spec/regexp.rd → #@include(regexp19): doc 内ローカル断片は拡張子なしで emit
|
|
161
|
+
# (copy_doc は **/*.rd だけをページとして読むため、断片に .rd を付けると
|
|
162
|
+
# ページとして二重取り込みされる上、include の解決も切れる)
|
|
163
|
+
Dir.mktmpdir do |md|
|
|
164
|
+
FileUtils.mkdir_p(File.join(md, "spec"))
|
|
165
|
+
File.write(File.join(md, "spec/regexp.md"), "# 正規表現\n\n\#@include(regexp19)\n")
|
|
166
|
+
File.write(File.join(md, "spec/regexp19.md"), "断片。\n")
|
|
167
|
+
Dir.mktmpdir do |out|
|
|
168
|
+
BitClust::MarkdownBridge.build_doc(md, File.join(out, "doc"))
|
|
169
|
+
assert_equal "= 正規表現\n\n\#@include(regexp19)\n",
|
|
170
|
+
File.read(File.join(out, "doc/spec/regexp.rd"))
|
|
171
|
+
assert_equal "断片。\n", File.read(File.join(out, "doc/spec/regexp19"))
|
|
172
|
+
return
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def test_build_doc_converts_and_rewrites_cross_tree_includes
|
|
178
|
+
# manual/doc の md → ブリッジの doc/*.rd。クロスツリー include は
|
|
179
|
+
# 旧レイアウト(../api/src/)へ戻す
|
|
180
|
+
Dir.mktmpdir do |md|
|
|
181
|
+
FileUtils.mkdir_p(File.join(md, "spec"))
|
|
182
|
+
File.write(File.join(md, "pack_template.md"),
|
|
183
|
+
"# pack テンプレート\n\n\#@include(../api/_builtin/pack-template)\n")
|
|
184
|
+
File.write(File.join(md, "spec/intro.md"), "# はじめに\n\n本文。\n")
|
|
185
|
+
Dir.mktmpdir do |out|
|
|
186
|
+
BitClust::MarkdownBridge.build_doc(md, File.join(out, "doc"))
|
|
187
|
+
assert_equal "= pack テンプレート\n\n\#@include(../api/src/_builtin/pack-template)\n",
|
|
188
|
+
File.read(File.join(out, "doc/pack_template.rd"))
|
|
189
|
+
assert_equal "= はじめに\n\n本文。\n", File.read(File.join(out, "doc/spec/intro.rd"))
|
|
190
|
+
return
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def test_reopen_members_are_included_last
|
|
196
|
+
# json.rd/rake.rd: reopen が dynamic include する module は先に定義されている
|
|
197
|
+
# 必要がある(RRDParser の検証)。reopen/redefine だけのファイルは後ろに並べる
|
|
198
|
+
files = {
|
|
199
|
+
"j.md" => "---\ntype: library\n---\nj 概要。\n",
|
|
200
|
+
"j/Array.md" => "---\nlibrary: j\n---\n# reopen Array\n",
|
|
201
|
+
"j/Gen.md" => "---\nlibrary: j\n---\n# module Gen\n",
|
|
202
|
+
}
|
|
203
|
+
Dir.mktmpdir do |md|
|
|
204
|
+
files.each do |path, content|
|
|
205
|
+
full = File.join(md, path)
|
|
206
|
+
FileUtils.mkdir_p(File.dirname(full))
|
|
207
|
+
File.write(full, content)
|
|
208
|
+
end
|
|
209
|
+
Dir.mktmpdir do |out|
|
|
210
|
+
BitClust::MarkdownBridge.build(md, out)
|
|
211
|
+
assert_equal "j 概要。\n\n\#@include(j/Gen)\n\#@include(j/Array)\n",
|
|
212
|
+
File.read(File.join(out, "j.rd"))
|
|
213
|
+
return
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|