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,290 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'bitclust'
|
|
4
|
+
require 'bitclust/methoddatabase'
|
|
5
|
+
require 'bitclust/method_since_calculator'
|
|
6
|
+
require 'tmpdir'
|
|
7
|
+
require 'fileutils'
|
|
8
|
+
|
|
9
|
+
# メソッド名別 since/until の算出(bitclust#132 P2)。
|
|
10
|
+
#
|
|
11
|
+
# テストリスト:
|
|
12
|
+
# [x] フロア(ラダー最古版から存在)のメソッドは since も until も付かない
|
|
13
|
+
# [x] #@since ゲート付きメソッドは、追加された版以降の対象すべてで
|
|
14
|
+
# since が付く
|
|
15
|
+
# [x] 別名グループ: シグネチャごとに異なるゲートを持てば名前ごとに
|
|
16
|
+
# 別の since になる(-@ は 2.0.0、dedup は 3.0)。ゲートが効いて
|
|
17
|
+
# いない版の対象ではその別名自体が存在しない
|
|
18
|
+
# [x] #@until ゲート付きメソッドは、消える1つ前の版の対象で until が付き、
|
|
19
|
+
# 消えた後の対象にはエントリ自体が存在しない
|
|
20
|
+
# [x] インスタンスメソッドとシンゲルトンメソッドは同名でも別キー
|
|
21
|
+
# [x] kind=:undefined のエントリは走査で無視される: {: undef} → 実メソッド化
|
|
22
|
+
# したものは実メソッド化した版が since になり、逆に undef 化は削除扱いで
|
|
23
|
+
# 前の版の対象に until が付く
|
|
24
|
+
# [x] kind=:undefined のエントリには適用でも書き込まない
|
|
25
|
+
# [x] ラダーに同じバージョンが重複していれば .new で UserError
|
|
26
|
+
# [x] apply は冪等: 2回目は floor_skipped 以外すべて0
|
|
27
|
+
# [x] 既に値がある名前は上書きしない(著者値が算出値より優先)
|
|
28
|
+
# [x] 対象DBのバージョンがラダーに無ければ apply は UserError
|
|
29
|
+
# [x] 統合: `{: since="X"}` 属性行(#132 P4)でパース時に記録された値は
|
|
30
|
+
# 算出結果で上書きされない(RD ソース上の明示注記が算出値より優先)
|
|
31
|
+
class TestMethodSinceCalculator < Test::Unit::TestCase
|
|
32
|
+
RD = <<~'RD'
|
|
33
|
+
description
|
|
34
|
+
|
|
35
|
+
= class MSCTest
|
|
36
|
+
== Instance Methods
|
|
37
|
+
--- old_timer
|
|
38
|
+
|
|
39
|
+
説明
|
|
40
|
+
|
|
41
|
+
#@since 2.0.0
|
|
42
|
+
--- newmeth
|
|
43
|
+
|
|
44
|
+
説明
|
|
45
|
+
#@end
|
|
46
|
+
|
|
47
|
+
#@since 3.0
|
|
48
|
+
--- overridden
|
|
49
|
+
{: since="2.5"}
|
|
50
|
+
|
|
51
|
+
説明
|
|
52
|
+
#@end
|
|
53
|
+
|
|
54
|
+
#@since 2.0.0
|
|
55
|
+
--- suppressed
|
|
56
|
+
{: since=""}
|
|
57
|
+
|
|
58
|
+
説明
|
|
59
|
+
#@end
|
|
60
|
+
|
|
61
|
+
#@since 2.0.0
|
|
62
|
+
--- -@
|
|
63
|
+
#@since 3.0
|
|
64
|
+
--- dedup
|
|
65
|
+
#@end
|
|
66
|
+
|
|
67
|
+
説明
|
|
68
|
+
#@end
|
|
69
|
+
|
|
70
|
+
#@until 3.0
|
|
71
|
+
--- legacy
|
|
72
|
+
|
|
73
|
+
説明
|
|
74
|
+
#@end
|
|
75
|
+
|
|
76
|
+
--- undefmeth
|
|
77
|
+
{: undef}
|
|
78
|
+
|
|
79
|
+
説明
|
|
80
|
+
|
|
81
|
+
--- undef_then_real
|
|
82
|
+
#@until 2.0.0
|
|
83
|
+
{: undef}
|
|
84
|
+
#@end
|
|
85
|
+
|
|
86
|
+
説明
|
|
87
|
+
|
|
88
|
+
#@since 2.0.0
|
|
89
|
+
--- real_then_undef
|
|
90
|
+
#@since 3.0
|
|
91
|
+
{: undef}
|
|
92
|
+
#@end
|
|
93
|
+
|
|
94
|
+
説明
|
|
95
|
+
#@end
|
|
96
|
+
|
|
97
|
+
--- marker
|
|
98
|
+
|
|
99
|
+
説明
|
|
100
|
+
|
|
101
|
+
== Singleton Methods
|
|
102
|
+
#@since 2.0.0
|
|
103
|
+
--- marker
|
|
104
|
+
|
|
105
|
+
説明
|
|
106
|
+
#@end
|
|
107
|
+
RD
|
|
108
|
+
|
|
109
|
+
LADDER_VERSIONS = %w[1.8.7 2.0.0 3.0]
|
|
110
|
+
|
|
111
|
+
def setup
|
|
112
|
+
@tmpdir = Dir.mktmpdir
|
|
113
|
+
@paths = {}
|
|
114
|
+
LADDER_VERSIONS.each {|v| build_db(v) }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def teardown
|
|
118
|
+
FileUtils.rm_rf(@tmpdir)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def test_floor_method_has_no_since_or_until
|
|
122
|
+
run_calculator('2.0.0')
|
|
123
|
+
run_calculator('3.0')
|
|
124
|
+
assert_nil find_entry('2.0.0', 'i', 'old_timer').since_of('old_timer')
|
|
125
|
+
assert_nil find_entry('2.0.0', 'i', 'old_timer').until_of('old_timer')
|
|
126
|
+
assert_nil find_entry('3.0', 'i', 'old_timer').since_of('old_timer')
|
|
127
|
+
assert_nil find_entry('3.0', 'i', 'old_timer').until_of('old_timer')
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def test_since_gated_method_gets_since_in_every_later_target
|
|
131
|
+
run_calculator('2.0.0')
|
|
132
|
+
run_calculator('3.0')
|
|
133
|
+
assert_equal '2.0.0', find_entry('2.0.0', 'i', 'newmeth').since_of('newmeth')
|
|
134
|
+
assert_equal '2.0.0', find_entry('3.0', 'i', 'newmeth').since_of('newmeth')
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def test_alias_group_since_is_split_by_name
|
|
138
|
+
run_calculator('2.0.0')
|
|
139
|
+
run_calculator('3.0')
|
|
140
|
+
|
|
141
|
+
at_2_0_0 = find_entry('2.0.0', 'i', '-@')
|
|
142
|
+
assert_equal ['-@'], at_2_0_0.names
|
|
143
|
+
assert_equal '2.0.0', at_2_0_0.since_of('-@')
|
|
144
|
+
|
|
145
|
+
at_3_0 = find_entry('3.0', 'i', '-@')
|
|
146
|
+
assert_equal ['-@', 'dedup'], at_3_0.names.sort
|
|
147
|
+
assert_equal '2.0.0', at_3_0.since_of('-@')
|
|
148
|
+
assert_equal '3.0', at_3_0.since_of('dedup')
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def test_until_gated_method
|
|
152
|
+
run_calculator('2.0.0')
|
|
153
|
+
assert_equal '3.0', find_entry('2.0.0', 'i', 'legacy').until_of('legacy')
|
|
154
|
+
assert_nil find_entry('3.0', 'i', 'legacy')
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def test_singleton_and_instance_method_are_distinct_keys
|
|
158
|
+
run_calculator('2.0.0')
|
|
159
|
+
assert_nil find_entry('2.0.0', 'i', 'marker').since_of('marker')
|
|
160
|
+
assert_equal '2.0.0', find_entry('2.0.0', 's', 'marker').since_of('marker')
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def test_undefined_entries_are_ignored_in_scan
|
|
164
|
+
run_calculator('3.0')
|
|
165
|
+
# 全版 {: undef} の undefmeth は presence ゼロ → 何も書かれない
|
|
166
|
+
e = find_entry('3.0', 'i', 'undefmeth')
|
|
167
|
+
assert_equal :undefined, e.kind
|
|
168
|
+
assert_nil e.since_of('undefmeth')
|
|
169
|
+
assert_nil e.until_of('undefmeth')
|
|
170
|
+
# 1.8.7 では {: undef}(存在しない印)なので presence に数えず、実メソッド化
|
|
171
|
+
# した 2.0.0 が since になる(scan がフィルタしなければ floor 扱いで nil)
|
|
172
|
+
assert_equal '2.0.0',
|
|
173
|
+
find_entry('3.0', 'i', 'undef_then_real').since_of('undef_then_real')
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def test_undefined_entries_are_ignored_in_apply
|
|
177
|
+
run_calculator('2.0.0')
|
|
178
|
+
run_calculator('3.0')
|
|
179
|
+
# 3.0 で undef 化 → presence は 2.0.0 のみ。2.0.0 の対象では削除扱いで
|
|
180
|
+
# until が付く
|
|
181
|
+
at_2_0_0 = find_entry('2.0.0', 'i', 'real_then_undef')
|
|
182
|
+
assert_equal '2.0.0', at_2_0_0.since_of('real_then_undef')
|
|
183
|
+
assert_equal '3.0', at_2_0_0.until_of('real_then_undef')
|
|
184
|
+
# 3.0 の :undefined エントリ自体には(算出値があっても)書き込まない
|
|
185
|
+
at_3_0 = find_entry('3.0', 'i', 'real_then_undef')
|
|
186
|
+
assert_equal :undefined, at_3_0.kind
|
|
187
|
+
assert_nil at_3_0.since_of('real_then_undef')
|
|
188
|
+
assert_nil at_3_0.until_of('real_then_undef')
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def test_duplicate_version_in_ladder_raises
|
|
192
|
+
dbs = ladder_dbs + [fresh_db('2.0.0')]
|
|
193
|
+
assert_raise(BitClust::UserError) { BitClust::MethodSinceCalculator.new(dbs) }
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def test_apply_is_idempotent
|
|
197
|
+
calc = BitClust::MethodSinceCalculator.new(ladder_dbs)
|
|
198
|
+
calc.scan
|
|
199
|
+
first_stats = calc.apply(fresh_db('2.0.0'))
|
|
200
|
+
second_stats = calc.apply(fresh_db('2.0.0'))
|
|
201
|
+
|
|
202
|
+
assert_operator first_stats[:since_filled], :>, 0
|
|
203
|
+
assert_equal 0, second_stats[:since_filled]
|
|
204
|
+
assert_equal 0, second_stats[:until_filled]
|
|
205
|
+
assert_equal 0, second_stats[:entries_updated]
|
|
206
|
+
assert_equal first_stats[:floor_skipped], second_stats[:floor_skipped]
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def test_author_value_takes_precedence_over_computed_value
|
|
210
|
+
pre = fresh_db('3.0')
|
|
211
|
+
entry = pre.get_class('MSCTest').entries.find {|m| m.typechar == 'i' && m.name?('newmeth') } or raise
|
|
212
|
+
entry.fill_since('newmeth', '1.9.9')
|
|
213
|
+
entry.save
|
|
214
|
+
|
|
215
|
+
calc = BitClust::MethodSinceCalculator.new(ladder_dbs)
|
|
216
|
+
calc.scan
|
|
217
|
+
calc.apply(fresh_db('3.0'))
|
|
218
|
+
|
|
219
|
+
assert_equal '1.9.9', find_entry('3.0', 'i', 'newmeth').since_of('newmeth')
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def test_author_since_attribute_parsed_from_source_survives_apply
|
|
223
|
+
# overridden は #@since 3.0 でゲートされているのでラダー上は 3.0 と算出
|
|
224
|
+
# されるが、RD ソースの {: since="2.5"} がパース時点(update_by_stdlibtree)
|
|
225
|
+
# で既に記録されているため、apply(fill_since は未設定時のみ書く)では
|
|
226
|
+
# 上書きされずそのまま残る
|
|
227
|
+
run_calculator('2.0.0')
|
|
228
|
+
run_calculator('3.0')
|
|
229
|
+
|
|
230
|
+
assert_nil find_entry('2.0.0', 'i', 'overridden')
|
|
231
|
+
assert_equal '2.5', find_entry('3.0', 'i', 'overridden').since_of('overridden')
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def test_explicit_empty_since_suppresses_computed_value
|
|
235
|
+
# suppressed は #@since 2.0.0 ゲートによりラダー上は 2.0.0 と算出されるが、
|
|
236
|
+
# {: since=""}(明示的に不明=バッジ非表示)がパース時に記録されているため
|
|
237
|
+
# apply は上書きしない(bitclust#132: ドキュメント追加がメソッド追加より
|
|
238
|
+
# 遅れて算出が誤る場合の抑止)
|
|
239
|
+
run_calculator('3.0')
|
|
240
|
+
assert_equal '', find_entry('3.0', 'i', 'suppressed').since_of('suppressed')
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def test_apply_rejects_target_whose_version_is_not_in_ladder
|
|
244
|
+
build_db('4.0')
|
|
245
|
+
calc = BitClust::MethodSinceCalculator.new(ladder_dbs)
|
|
246
|
+
calc.scan
|
|
247
|
+
assert_raise(BitClust::UserError) { calc.apply(fresh_db('4.0')) }
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
private
|
|
251
|
+
|
|
252
|
+
def build_db(version)
|
|
253
|
+
root = "#{@tmpdir}/tree-#{version}/refm/api/src"
|
|
254
|
+
FileUtils.mkdir_p("#{root}/_builtin")
|
|
255
|
+
File.write("#{root}/LIBRARIES", "_builtin\n")
|
|
256
|
+
File.write("#{root}/_builtin.rd", RD)
|
|
257
|
+
prefix = "#{@tmpdir}/db-#{version}"
|
|
258
|
+
db = BitClust::MethodDatabase.new(prefix)
|
|
259
|
+
db.init
|
|
260
|
+
db.transaction do
|
|
261
|
+
db.propset('version', version)
|
|
262
|
+
db.propset('encoding', 'utf-8')
|
|
263
|
+
end
|
|
264
|
+
db.transaction do
|
|
265
|
+
db.update_by_stdlibtree(root)
|
|
266
|
+
end
|
|
267
|
+
@paths[version] = prefix
|
|
268
|
+
prefix
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def fresh_db(version)
|
|
272
|
+
BitClust::MethodDatabase.new(@paths[version] || raise("no such db: #{version}"))
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def ladder_dbs
|
|
276
|
+
LADDER_VERSIONS.map {|v| fresh_db(v) }
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def run_calculator(target_version)
|
|
280
|
+
calc = BitClust::MethodSinceCalculator.new(ladder_dbs)
|
|
281
|
+
calc.scan
|
|
282
|
+
calc.apply(fresh_db(target_version))
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def find_entry(version, typechar, name)
|
|
286
|
+
fresh_db(version).get_class('MSCTest').entries.find {|m|
|
|
287
|
+
m.typechar == typechar && m.name?(name)
|
|
288
|
+
}
|
|
289
|
+
end
|
|
290
|
+
end
|
data/test/test_methoddatabase.rb
CHANGED
|
@@ -57,6 +57,22 @@ class TestMethodDatabase < Test::Unit::TestCase
|
|
|
57
57
|
@db.get_class("B").dynamically_included.map{|m| m.name})
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
+
# source_location must be stored without a line number so that regenerating
|
|
61
|
+
# the database does not churn the persisted entries (and the generated HTML).
|
|
62
|
+
def test_source_location_serialized_without_line_number
|
|
63
|
+
entry = @db.search_methods(BitClust::MethodNamePattern.new(nil, nil, 'at_exit')).records.first.entry
|
|
64
|
+
entry.source_location = BitClust::Location.new('refm/api/src/_builtin/Kernel', 42)
|
|
65
|
+
assert_equal('refm/api/src/_builtin/Kernel', entry._get_properties['source_location'])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_source_location_roundtrip_drops_line_number
|
|
69
|
+
entry = @db.search_methods(BitClust::MethodNamePattern.new(nil, nil, 'at_exit')).records.first.entry
|
|
70
|
+
entry.source_location = BitClust::Location.new('refm/api/src/_builtin/Kernel', 42)
|
|
71
|
+
entry._set_properties(entry._get_properties)
|
|
72
|
+
assert_equal('refm/api/src/_builtin/Kernel', entry.source_location.file)
|
|
73
|
+
assert_nil(entry.source_location.line)
|
|
74
|
+
end
|
|
75
|
+
|
|
60
76
|
private
|
|
61
77
|
def setup_files
|
|
62
78
|
FileUtils.mkdir_p("#{@root}/_builtin")
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'bitclust'
|
|
3
|
+
require 'bitclust/methoddatabase'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
|
|
7
|
+
class TestMethodEntryTitleLabels < Test::Unit::TestCase
|
|
8
|
+
def test_title_labels_matches_label_when_no_alias
|
|
9
|
+
lib, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
|
|
10
|
+
= class Enumerable2
|
|
11
|
+
== Instance Methods
|
|
12
|
+
--- select -> Array
|
|
13
|
+
|
|
14
|
+
説明のためのエントリ
|
|
15
|
+
HERE
|
|
16
|
+
_ = lib
|
|
17
|
+
m = db.get_method(BitClust::MethodSpec.parse('Enumerable2#select'))
|
|
18
|
+
assert_equal(['Enumerable2#select'], m.title_labels)
|
|
19
|
+
assert_equal(m.label, m.title_labels.join(', '))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_title_labels_lists_every_alias
|
|
23
|
+
lib, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
|
|
24
|
+
= class Enumerable2
|
|
25
|
+
== Instance Methods
|
|
26
|
+
--- collect -> Array
|
|
27
|
+
--- map -> Array
|
|
28
|
+
|
|
29
|
+
説明のためのエントリ
|
|
30
|
+
HERE
|
|
31
|
+
_ = lib
|
|
32
|
+
m = db.get_method(BitClust::MethodSpec.parse('Enumerable2#collect'))
|
|
33
|
+
assert_equal(['Enumerable2#collect', 'Enumerable2#map'], m.title_labels)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# #label omits the class prefix for special variables (e.g. "$;", not
|
|
37
|
+
# "Kernel$;"); #title_labels must keep that convention for every alias,
|
|
38
|
+
# unlike #labels which always includes the prefix.
|
|
39
|
+
def test_title_labels_omits_class_prefix_for_special_variables
|
|
40
|
+
lib, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
|
|
41
|
+
= module Kernel
|
|
42
|
+
description
|
|
43
|
+
== Special Variables
|
|
44
|
+
--- $;
|
|
45
|
+
--- $FIELD_SEPARATOR
|
|
46
|
+
|
|
47
|
+
区切り文字。
|
|
48
|
+
HERE
|
|
49
|
+
_ = lib
|
|
50
|
+
m = db.get_method(BitClust::MethodSpec.parse('Kernel$;'))
|
|
51
|
+
assert_equal('$;', m.label)
|
|
52
|
+
assert_equal(['$;', '$FIELD_SEPARATOR'], m.title_labels)
|
|
53
|
+
assert_equal(['Kernel$;', 'Kernel$FIELD_SEPARATOR'], m.labels)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_title_labels_matches_label_for_single_special_variable
|
|
57
|
+
lib, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
|
|
58
|
+
= module Kernel
|
|
59
|
+
description
|
|
60
|
+
== Special Variables
|
|
61
|
+
--- $stdout -> IO
|
|
62
|
+
|
|
63
|
+
標準出力。
|
|
64
|
+
HERE
|
|
65
|
+
_ = lib
|
|
66
|
+
m = db.get_method(BitClust::MethodSpec.parse('Kernel$stdout'))
|
|
67
|
+
assert_equal(['$stdout'], m.title_labels)
|
|
68
|
+
assert_equal(m.label, m.title_labels.join(', '))
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# bitclust#250: Ruby 4.0 以降のドキュメントでは module function の表記を
|
|
73
|
+
# 独自の「.#」から「?.」に変える(表示のみ。識別子は変えない)。
|
|
74
|
+
#
|
|
75
|
+
# label/short_label/labels/title_labels 自身は refsdatabase.rb の
|
|
76
|
+
# [[a:...]] アンカー解決キー(labels)や `bitclust methods --diff` の
|
|
77
|
+
# expand_mf マッチング(labels)が literal ".#" を前提にしているため、
|
|
78
|
+
# 一切変更しない。表示用には display_label/display_short_label/
|
|
79
|
+
# display_title_labels/display_typemark を新設し、テンプレート側の
|
|
80
|
+
# 実際の表示箇所だけがそちらを呼ぶようにする。
|
|
81
|
+
class TestMethodEntryDisplayTypemark < Test::Unit::TestCase
|
|
82
|
+
SRC = <<HERE
|
|
83
|
+
= module Kernel
|
|
84
|
+
description
|
|
85
|
+
== Module Functions
|
|
86
|
+
--- mf
|
|
87
|
+
--- mf2
|
|
88
|
+
|
|
89
|
+
説明
|
|
90
|
+
|
|
91
|
+
== Instance Methods
|
|
92
|
+
--- im
|
|
93
|
+
|
|
94
|
+
説明
|
|
95
|
+
|
|
96
|
+
== Special Variables
|
|
97
|
+
--- $stdout -> IO
|
|
98
|
+
|
|
99
|
+
標準出力。
|
|
100
|
+
HERE
|
|
101
|
+
|
|
102
|
+
def build(version)
|
|
103
|
+
_lib, db = BitClust::RRDParser.parse(SRC, 'testlib', {'version' => version})
|
|
104
|
+
db
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def test_module_function_display_stays_dot_hash_before_4_0
|
|
108
|
+
db = build('3.4')
|
|
109
|
+
m = db.get_method(BitClust::MethodSpec.parse('Kernel.#mf'))
|
|
110
|
+
assert_equal('.#', m.display_typemark)
|
|
111
|
+
assert_equal('Kernel.#mf', m.display_label)
|
|
112
|
+
assert_equal('.#mf', m.display_short_label)
|
|
113
|
+
assert_equal(['Kernel.#mf', 'Kernel.#mf2'], m.display_title_labels)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_module_function_display_switches_to_question_dot_at_4_0
|
|
117
|
+
db = build('4.0')
|
|
118
|
+
m = db.get_method(BitClust::MethodSpec.parse('Kernel.#mf'))
|
|
119
|
+
assert_equal('?.', m.display_typemark)
|
|
120
|
+
assert_equal('Kernel?.mf', m.display_label)
|
|
121
|
+
assert_equal('?.mf', m.display_short_label)
|
|
122
|
+
assert_equal(['Kernel?.mf', 'Kernel?.mf2'], m.display_title_labels)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# 識別子として使われる label/labels/short_label/title_labels は、
|
|
126
|
+
# 表示版とは無関係に version が 4.0 以降でも従来どおり ".#" のまま
|
|
127
|
+
def test_identity_methods_are_unaffected_by_version
|
|
128
|
+
db = build('4.0')
|
|
129
|
+
m = db.get_method(BitClust::MethodSpec.parse('Kernel.#mf'))
|
|
130
|
+
assert_equal('.#', m.typemark)
|
|
131
|
+
assert_equal('Kernel.#mf', m.label)
|
|
132
|
+
assert_equal('.#mf', m.short_label)
|
|
133
|
+
assert_equal(['Kernel.#mf', 'Kernel.#mf2'], m.title_labels)
|
|
134
|
+
assert_equal(['Kernel.#mf', 'Kernel.#mf2'], m.labels)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def test_instance_method_and_special_variable_display_are_unaffected_by_version
|
|
138
|
+
db = build('4.0')
|
|
139
|
+
im = db.get_method(BitClust::MethodSpec.parse('Kernel#im'))
|
|
140
|
+
assert_equal('#', im.display_typemark)
|
|
141
|
+
assert_equal('Kernel#im', im.display_label)
|
|
142
|
+
assert_equal('im', im.display_short_label)
|
|
143
|
+
|
|
144
|
+
sv = db.get_method(BitClust::MethodSpec.parse('Kernel$stdout'))
|
|
145
|
+
assert_equal('$', sv.display_typemark)
|
|
146
|
+
assert_equal('$stdout', sv.display_label)
|
|
147
|
+
assert_equal('$stdout', sv.display_short_label)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# meta description(コンパイラを通さない表示テキスト)内の module function
|
|
152
|
+
# 参照 [[m:Kernel.#mf2]] のラベルも、可視ページの bracket_link と同様に
|
|
153
|
+
# DB バージョン 4.0 以降では "?." で表示する(bitclust#282/#283 の続き。
|
|
154
|
+
# 従来この経路だけ ".#" のまま残っていた)
|
|
155
|
+
class TestMethodEntryDescriptionQdot < Test::Unit::TestCase
|
|
156
|
+
SRC = <<HERE
|
|
157
|
+
= module Kernel
|
|
158
|
+
|
|
159
|
+
== Module Functions
|
|
160
|
+
|
|
161
|
+
--- mf
|
|
162
|
+
|
|
163
|
+
[[m:Kernel.#mf2]] を参照してください。
|
|
164
|
+
|
|
165
|
+
--- mf2
|
|
166
|
+
|
|
167
|
+
説明。
|
|
168
|
+
HERE
|
|
169
|
+
|
|
170
|
+
def description(version)
|
|
171
|
+
_lib, db = BitClust::RRDParser.parse(SRC, 'testlib', {'version' => version})
|
|
172
|
+
db.get_method(BitClust::MethodSpec.parse('Kernel.#mf')).description
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def test_meta_description_keeps_dot_hash_before_4_0
|
|
176
|
+
assert_equal('Kernel.#mf2 を参照してください。', description('3.4'))
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def test_meta_description_uses_question_dot_at_4_0
|
|
180
|
+
assert_equal('Kernel?.mf2 を参照してください。', description('4.0'))
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# メソッド名別の since/until (bitclust#132 P1)。
|
|
185
|
+
#
|
|
186
|
+
# テストリスト:
|
|
187
|
+
# [x] 新規エントリの since_map/until_map は空、since_of/until_of は nil
|
|
188
|
+
# [x] fill_since は初回のみ追加して true を返す。既に値があれば false で上書きしない
|
|
189
|
+
# [x] fill_until も同様
|
|
190
|
+
# [x] fill_since/fill_until は version に '=' や ',' を含むと ArgumentError
|
|
191
|
+
# [x] 実ディスク DB への保存→別インスタンスで再読込しても since_of/until_of が一致
|
|
192
|
+
# [x] 名前に '=' を含む("==", "foo=")・',' を含む("," )・"-@" が
|
|
193
|
+
# エンコード/デコードを経て正しく往復する
|
|
194
|
+
# [x] since_by_name/until_by_name のキー自体がプロパティファイルに無い
|
|
195
|
+
# (旧DB)場合も落ちずに空配列として読める(Entry の '[String]' デシリアライザの
|
|
196
|
+
# nil 安全化)
|
|
197
|
+
class TestMethodEntrySinceUntil < Test::Unit::TestCase
|
|
198
|
+
def setup
|
|
199
|
+
@dir = Dir.mktmpdir
|
|
200
|
+
@db = BitClust::MethodDatabase.new(@dir)
|
|
201
|
+
@db.init
|
|
202
|
+
@db.transaction do
|
|
203
|
+
@db.propset('version', '2.0')
|
|
204
|
+
@db.propset('encoding', 'utf-8')
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def teardown
|
|
209
|
+
FileUtils.rm_rf(@dir)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def test_defaults_are_empty
|
|
213
|
+
m = build_entry('marker')
|
|
214
|
+
assert_equal({}, m.since_map)
|
|
215
|
+
assert_equal({}, m.until_map)
|
|
216
|
+
assert_nil m.since_of('marker')
|
|
217
|
+
assert_nil m.until_of('marker')
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def test_fill_since_adds_once
|
|
221
|
+
m = build_entry('marker')
|
|
222
|
+
assert_equal(true, m.fill_since('marker', '2.0'))
|
|
223
|
+
assert_equal('2.0', m.since_of('marker'))
|
|
224
|
+
# 既に値があるので上書きされず false
|
|
225
|
+
assert_equal(false, m.fill_since('marker', '3.0'))
|
|
226
|
+
assert_equal('2.0', m.since_of('marker'))
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def test_fill_until_adds_once
|
|
230
|
+
m = build_entry('marker')
|
|
231
|
+
assert_equal(true, m.fill_until('marker', '3.0'))
|
|
232
|
+
assert_equal('3.0', m.until_of('marker'))
|
|
233
|
+
assert_equal(false, m.fill_until('marker', '4.0'))
|
|
234
|
+
assert_equal('3.0', m.until_of('marker'))
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def test_fill_since_rejects_version_with_equal_or_comma
|
|
238
|
+
m = build_entry('marker')
|
|
239
|
+
assert_raise(ArgumentError) { m.fill_since('marker', '2.0=1') }
|
|
240
|
+
assert_raise(ArgumentError) { m.fill_since('marker', '2.0,1') }
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def test_fill_until_rejects_version_with_equal_or_comma
|
|
244
|
+
m = build_entry('marker')
|
|
245
|
+
assert_raise(ArgumentError) { m.fill_until('marker', '2.0=1') }
|
|
246
|
+
assert_raise(ArgumentError) { m.fill_until('marker', '2.0,1') }
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def test_roundtrip_through_disk
|
|
250
|
+
m = build_entry('marker')
|
|
251
|
+
m.fill_since('marker', '2.0')
|
|
252
|
+
m.fill_until('marker', '3.0')
|
|
253
|
+
m.save
|
|
254
|
+
|
|
255
|
+
reloaded = reload_entry(m.id)
|
|
256
|
+
assert_equal('2.0', reloaded.since_of('marker'))
|
|
257
|
+
assert_equal('3.0', reloaded.until_of('marker'))
|
|
258
|
+
assert_equal({'marker' => '2.0'}, reloaded.since_map)
|
|
259
|
+
assert_equal({'marker' => '3.0'}, reloaded.until_map)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def test_roundtrip_names_with_special_characters
|
|
263
|
+
[ '==', 'foo=', '-@', ',' ].each do |name|
|
|
264
|
+
m = build_entry(name)
|
|
265
|
+
m.fill_since(name, '2.0')
|
|
266
|
+
m.save
|
|
267
|
+
|
|
268
|
+
reloaded = reload_entry(m.id)
|
|
269
|
+
assert_equal('2.0', reloaded.since_of(name),
|
|
270
|
+
"since_of(#{name.inspect}) should round-trip")
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def test_multiple_names_share_one_entry
|
|
275
|
+
m = build_entry_with_names(['-@', 'dedup'])
|
|
276
|
+
m.fill_since('-@', '2.0')
|
|
277
|
+
m.fill_since('dedup', '3.0')
|
|
278
|
+
m.save
|
|
279
|
+
|
|
280
|
+
reloaded = reload_entry(m.id)
|
|
281
|
+
assert_equal('2.0', reloaded.since_of('-@'))
|
|
282
|
+
assert_equal('3.0', reloaded.since_of('dedup'))
|
|
283
|
+
assert_equal({'-@' => '2.0', 'dedup' => '3.0'}, reloaded.since_map)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def test_missing_since_by_name_key_is_backward_compatible
|
|
287
|
+
m = build_entry('old_method')
|
|
288
|
+
m.save
|
|
289
|
+
strip_property_line(m.id, 'since_by_name')
|
|
290
|
+
strip_property_line(m.id, 'until_by_name')
|
|
291
|
+
|
|
292
|
+
reloaded = reload_entry(m.id)
|
|
293
|
+
assert_equal([], reloaded.since_by_name)
|
|
294
|
+
assert_equal([], reloaded.until_by_name)
|
|
295
|
+
assert_nil reloaded.since_of('old_method')
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
private
|
|
299
|
+
|
|
300
|
+
def build_entry(name)
|
|
301
|
+
build_entry_with_names([name])
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def build_entry_with_names(names)
|
|
305
|
+
id = BitClust::NameUtils.build_method_id('_builtin', 'Foo', :instance_method, names.first)
|
|
306
|
+
m = BitClust::MethodEntry.new(@db, id)
|
|
307
|
+
m.names = names
|
|
308
|
+
m.visibility = :public
|
|
309
|
+
m.kind = :defined
|
|
310
|
+
m.source = "説明\n"
|
|
311
|
+
m
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def reload_entry(id)
|
|
315
|
+
fresh_db = BitClust::MethodDatabase.new(@dir)
|
|
316
|
+
BitClust::MethodEntry.new(fresh_db, id)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def property_file_path(id)
|
|
320
|
+
File.join(@dir, BitClust::NameUtils.encodeid("method/#{id}"))
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def strip_property_line(id, key)
|
|
324
|
+
path = property_file_path(id)
|
|
325
|
+
lines = File.readlines(path).reject {|l| l.start_with?("#{key}=") }
|
|
326
|
+
File.write(path, lines.join)
|
|
327
|
+
end
|
|
328
|
+
end
|
|
@@ -4,7 +4,9 @@ require 'bitclust/methodsignature'
|
|
|
4
4
|
class TestMethodSignature < Test::Unit::TestCase
|
|
5
5
|
|
|
6
6
|
data("special var" => ["$_ -> String | nil", "--- $_ -> String | nil"],
|
|
7
|
-
"backquote" => ["`command` -> String", "--- `(command) -> String"]
|
|
7
|
+
"backquote" => ["`command` -> String", "--- `(command) -> String"],
|
|
8
|
+
"aset" => ["self[key] = value", "--- []=(key, value)"],
|
|
9
|
+
"aset splat" => ["[]=(*idxary)", "--- []=(*idxary)"])
|
|
8
10
|
def test_friendlyname(data)
|
|
9
11
|
friendly_string, method_signature = data
|
|
10
12
|
assert_equal(friendly_string, BitClust::MethodSignature.parse(method_signature).friendly_string)
|