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
data/lib/bitclust/methodentry.rb
CHANGED
|
@@ -44,7 +44,8 @@ module BitClust
|
|
|
44
44
|
sort_key() <=> other.sort_key
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
KIND_NUM = {:defined => 0, :redefined => 1, :added => 2
|
|
47
|
+
KIND_NUM = {:defined => 0, :redefined => 1, :added => 2,
|
|
48
|
+
:undefined => 3, :nomethod => 4}
|
|
48
49
|
|
|
49
50
|
def sort_key
|
|
50
51
|
[label(), KIND_NUM[kind()]]
|
|
@@ -73,6 +74,14 @@ module BitClust
|
|
|
73
74
|
methodid2typechar(@id)
|
|
74
75
|
end
|
|
75
76
|
|
|
77
|
+
# bitclust#250: 表示専用の typemark。DB のバージョンが 4.0 以降なら
|
|
78
|
+
# module function の "." を "?." にする(それ以外の typemark は不変)。
|
|
79
|
+
# typemark 自体(識別子として使う方)は変えない -- URL・spec 文字列・
|
|
80
|
+
# refsdatabase のアンカーキー等はすべて typemark() 経由のまま
|
|
81
|
+
def display_typemark
|
|
82
|
+
NameUtils.display_typemark(typemark(), @db.propget('version'))
|
|
83
|
+
end
|
|
84
|
+
|
|
76
85
|
def type_label
|
|
77
86
|
case typemark()
|
|
78
87
|
when '.' then 'singleton method'
|
|
@@ -80,6 +89,7 @@ module BitClust
|
|
|
80
89
|
when '.#' then 'module function'
|
|
81
90
|
when '::' then 'constant'
|
|
82
91
|
when '$' then 'variable'
|
|
92
|
+
else raise "invalid typemark: #{typemark().inspect}"
|
|
83
93
|
end
|
|
84
94
|
end
|
|
85
95
|
|
|
@@ -97,10 +107,17 @@ module BitClust
|
|
|
97
107
|
|
|
98
108
|
persistent_properties {
|
|
99
109
|
property :names, '[String]'
|
|
100
|
-
property :visibility, 'Symbol'
|
|
101
|
-
property :kind, 'Symbol'
|
|
110
|
+
property :visibility, 'Symbol' ## :public | :private | :protected
|
|
111
|
+
property :kind, 'Symbol' ## :defined | :added | :redefined | :undefined | :nomethod
|
|
102
112
|
property :source, 'String'
|
|
103
113
|
property :source_location, 'Location'
|
|
114
|
+
# 名前別の since/until(bitclust#132)。トークンは
|
|
115
|
+
# "#{エンコード名}=#{バージョン}" の配列([String] 型を再利用)で、
|
|
116
|
+
# 生名の ',' '=' は encodename_url でエスケープ済みなので最後の '='
|
|
117
|
+
# がバージョンとの区切りになる(バージョン文字列には '=' も ',' も
|
|
118
|
+
# 現れない前提。fill_since/fill_until で検査する)
|
|
119
|
+
property :since_by_name, '[String]'
|
|
120
|
+
property :until_by_name, '[String]'
|
|
104
121
|
}
|
|
105
122
|
|
|
106
123
|
def inspect
|
|
@@ -109,7 +126,8 @@ module BitClust
|
|
|
109
126
|
end
|
|
110
127
|
|
|
111
128
|
def spec
|
|
112
|
-
|
|
129
|
+
c, t, m, lib = methodid2specparts(@id)
|
|
130
|
+
MethodSpec.new(c, t, m, lib)
|
|
113
131
|
end
|
|
114
132
|
|
|
115
133
|
def spec_string
|
|
@@ -121,11 +139,29 @@ module BitClust
|
|
|
121
139
|
"#{t == '$' ? '' : c}#{t}#{m}"
|
|
122
140
|
end
|
|
123
141
|
|
|
142
|
+
# bitclust#250: label の表示専用版(module function は 4.0 以降 "?." で
|
|
143
|
+
# 表示)。label 自身は refsdatabase.rb の [[a:...]] アンカーキーや
|
|
144
|
+
# `bitclust methods --diff` の突き合わせが literal ".#" 前提で使うので
|
|
145
|
+
# 変えない -- テンプレート側の実際の表示箇所だけがこちらを呼ぶ
|
|
146
|
+
def display_label
|
|
147
|
+
c, t, m, _lib = methodid2specparts(@id)
|
|
148
|
+
"#{t == '$' ? '' : c}#{display_typemark}#{m}"
|
|
149
|
+
end
|
|
150
|
+
|
|
124
151
|
def short_label
|
|
125
152
|
_c, t, m, _lib = methodid2specparts(@id)
|
|
126
153
|
"#{t == '#' ? '' : t}#{m}"
|
|
127
154
|
end
|
|
128
155
|
|
|
156
|
+
# bitclust#250: short_label の表示専用版。short_label 自身の唯一の
|
|
157
|
+
# 呼び出し元(htmlutils.rb の link_to_method)は display_short_label に
|
|
158
|
+
# 切り替え済みだが、short_label 自体は同じ理由(識別子的な使い方をする
|
|
159
|
+
# 将来のコードのため)で変えない
|
|
160
|
+
def display_short_label
|
|
161
|
+
_c, t, m, _lib = methodid2specparts(@id)
|
|
162
|
+
"#{t == '#' ? '' : display_typemark}#{m}"
|
|
163
|
+
end
|
|
164
|
+
|
|
129
165
|
def index_id
|
|
130
166
|
"#{methodid2typechar(@id)}_#{encodename_fs(name).gsub(/=/, '--')}".upcase
|
|
131
167
|
end
|
|
@@ -135,10 +171,79 @@ module BitClust
|
|
|
135
171
|
names().map {|name| "#{c}#{t}#{name}" }
|
|
136
172
|
end
|
|
137
173
|
|
|
174
|
+
# Every name of this entry, formatted the same way as #label (i.e.
|
|
175
|
+
# without the redundant class prefix on special variables such as $!,
|
|
176
|
+
# unlike #labels). Used where all aliases of a method need to be listed
|
|
177
|
+
# together, e.g. the <title> of its page.
|
|
178
|
+
def title_labels
|
|
179
|
+
c, t, _m, _lib = methodid2specparts(@id)
|
|
180
|
+
names().map {|name| "#{t == '$' ? '' : c}#{t}#{name}" }
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# bitclust#250: title_labels の表示専用版(<title> タグ・見出しで使う)
|
|
184
|
+
def display_title_labels
|
|
185
|
+
c, t, _m, _lib = methodid2specparts(@id)
|
|
186
|
+
names().map {|name| "#{t == '$' ? '' : c}#{display_typemark}#{name}" }
|
|
187
|
+
end
|
|
188
|
+
|
|
138
189
|
def name?(name)
|
|
139
190
|
names().include?(name)
|
|
140
191
|
end
|
|
141
192
|
|
|
193
|
+
# 名前別 since/until(bitclust#132)。名前ごとに別バージョンで
|
|
194
|
+
# 追加/削除されうる別名(例: alias)を区別して記録する
|
|
195
|
+
|
|
196
|
+
def since_of(name)
|
|
197
|
+
since_map[name]
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def until_of(name)
|
|
201
|
+
until_map[name]
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def since_map
|
|
205
|
+
decode_version_tokens(since_by_name)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def until_map
|
|
209
|
+
decode_version_tokens(until_by_name)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# name の since が未設定の場合のみ version を追加する。追加したら true、
|
|
213
|
+
# 既に値があって何もしなければ false を返す
|
|
214
|
+
def fill_since(name, version)
|
|
215
|
+
fill_version_token(:since_by_name, :since_of, name, version)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# fill_since の until 版
|
|
219
|
+
def fill_until(name, version)
|
|
220
|
+
fill_version_token(:until_by_name, :until_of, name, version)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
private
|
|
224
|
+
|
|
225
|
+
def decode_version_tokens(tokens)
|
|
226
|
+
h = {} #: Hash[String, String]
|
|
227
|
+
tokens.each do |token|
|
|
228
|
+
i = token.rindex('=') or raise "must not happen: malformed version token #{token.inspect}"
|
|
229
|
+
raw_name = decodename_url(token[0...i] || raise)
|
|
230
|
+
h[raw_name] = token[(i + 1)..] || raise
|
|
231
|
+
end
|
|
232
|
+
h
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def fill_version_token(prop, reader, name, version)
|
|
236
|
+
if version.include?('=') || version.include?(',')
|
|
237
|
+
raise ArgumentError, "version must not contain '=' or ',': #{version.inspect}"
|
|
238
|
+
end
|
|
239
|
+
return false if __send__(reader, name)
|
|
240
|
+
token = "#{encodename_url(name)}=#{version}"
|
|
241
|
+
__send__("#{prop}=", __send__(prop) + [token])
|
|
242
|
+
true
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
public
|
|
246
|
+
|
|
142
247
|
def name_match?(re)
|
|
143
248
|
names().any? {|n| re =~ n }
|
|
144
249
|
end
|
|
@@ -148,7 +253,7 @@ module BitClust
|
|
|
148
253
|
end
|
|
149
254
|
|
|
150
255
|
def public?
|
|
151
|
-
visibility() != :private
|
|
256
|
+
visibility() != :private && visibility() != :protected
|
|
152
257
|
end
|
|
153
258
|
|
|
154
259
|
def protected?
|
|
@@ -172,7 +277,11 @@ module BitClust
|
|
|
172
277
|
end
|
|
173
278
|
|
|
174
279
|
def private_instance_method?
|
|
175
|
-
instance_method? and
|
|
280
|
+
instance_method? and private?
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def protected_instance_method?
|
|
284
|
+
instance_method? and protected?
|
|
176
285
|
end
|
|
177
286
|
|
|
178
287
|
def singleton_method?
|
|
@@ -209,8 +318,17 @@ module BitClust
|
|
|
209
318
|
kind() == :undefined
|
|
210
319
|
end
|
|
211
320
|
|
|
321
|
+
# 説明のためだけに記載されていて実際には定義されていないメソッド
|
|
322
|
+
# (ソースの @nomethod メタデータ行で指定する)
|
|
323
|
+
def nomethod?
|
|
324
|
+
kind() == :nomethod
|
|
325
|
+
end
|
|
326
|
+
|
|
212
327
|
def description
|
|
213
|
-
source.split(/\n\n
|
|
328
|
+
paragraphs = source.split(/\n\n+/).drop(1)
|
|
329
|
+
# {: ...} 属性行や @param などのメタデータ段落は説明文として使わない
|
|
330
|
+
para = paragraphs.find {|p| !p.start_with?('@', '{:') } || paragraphs.first || ''
|
|
331
|
+
description_text(para)
|
|
214
332
|
end
|
|
215
333
|
end
|
|
216
334
|
end
|
data/lib/bitclust/methodid.rb
CHANGED
|
@@ -66,7 +66,8 @@ module BitClust
|
|
|
66
66
|
class MethodSpec
|
|
67
67
|
|
|
68
68
|
def MethodSpec.parse(str)
|
|
69
|
-
|
|
69
|
+
c, t, m = NameUtils.split_method_spec(str)
|
|
70
|
+
new(c, t, m)
|
|
70
71
|
end
|
|
71
72
|
|
|
72
73
|
def initialize(c, t, m, library = nil)
|
|
@@ -89,8 +90,13 @@ module BitClust
|
|
|
89
90
|
"#{@klass}#{@type}#{@method}"
|
|
90
91
|
end
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
# version はドキュメント対象の Ruby バージョン(DB の version プロパティ)。
|
|
94
|
+
# 指定すると module function の typemark を表示用に畳む
|
|
95
|
+
# (4.0 以降は "?."。NameUtils#display_typemark と同じ規則)
|
|
96
|
+
def display_name(version = nil)
|
|
97
|
+
return "$#{@method}" if @type == '$'
|
|
98
|
+
return "#{@klass}#{NameUtils.display_typemark(_ = @type, version)}#{@method}" if version
|
|
99
|
+
to_s()
|
|
94
100
|
end
|
|
95
101
|
|
|
96
102
|
def ==(other)
|
|
@@ -182,15 +188,10 @@ module BitClust
|
|
|
182
188
|
private :tesc
|
|
183
189
|
|
|
184
190
|
def match?(m)
|
|
185
|
-
(not @library or m.library.name?(@library)) and
|
|
186
|
-
(not @klass or m.klass.name?(@klass)) and
|
|
191
|
+
(not @library or m.library.name?(@library || raise)) and
|
|
192
|
+
(not @klass or m.klass.name?(@klass || raise)) and
|
|
187
193
|
(not @type or m.typemark == @type) and
|
|
188
|
-
(not @method or m.name?(@method))
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def select_classes(cs)
|
|
192
|
-
return cs unless @klass
|
|
193
|
-
expand_ic(cs, @klass, @crecache)
|
|
194
|
+
(not @method or m.name?(@method || raise))
|
|
194
195
|
end
|
|
195
196
|
|
|
196
197
|
def empty?
|
|
@@ -33,7 +33,7 @@ module BitClust
|
|
|
33
33
|
m = METHOD_SIGNATURE_RE.match(line) or
|
|
34
34
|
raise ParseError, %Q(unknown signature format: "#{line.strip}")
|
|
35
35
|
method, gvar, params, block, type = m.captures
|
|
36
|
-
new(method || gvar, params && params.strip, block && block.strip, type && type.strip)
|
|
36
|
+
new(method || gvar || raise, params && params.strip, block && block.strip, type && type.strip)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def initialize(name, params, block, type)
|
|
@@ -64,9 +64,15 @@ module BitClust
|
|
|
64
64
|
when "[]" # aref
|
|
65
65
|
"self[#{@params}]" + (@type ? " -> #{@type}" : "")
|
|
66
66
|
when "[]=" # aset
|
|
67
|
-
params = @params
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
params = @params&.split(',')
|
|
68
|
+
if params && params.size >= 2
|
|
69
|
+
val = params.pop || raise
|
|
70
|
+
"self[#{params.join(',').strip}] = #{val.strip}"
|
|
71
|
+
else
|
|
72
|
+
# Signatures like []=(*idxary) in historic documents cannot be
|
|
73
|
+
# shaped into "self[...] = ..."; show the raw signature instead
|
|
74
|
+
to_s()
|
|
75
|
+
end
|
|
70
76
|
when "`" # `command`
|
|
71
77
|
"`#{@params}`" + (@type ? " -> #{@type}" : "")
|
|
72
78
|
when /\A\W/ # binary operator
|
data/lib/bitclust/nameutils.rb
CHANGED
|
@@ -59,51 +59,55 @@ module BitClust
|
|
|
59
59
|
def split_method_spec(spec)
|
|
60
60
|
case spec
|
|
61
61
|
when /\AKernel\$/
|
|
62
|
-
return 'Kernel', '$', $'
|
|
62
|
+
return ['Kernel', '$', $' || raise]
|
|
63
63
|
else
|
|
64
64
|
m = /\A(#{CLASS_PATH_RE})(#{TYPEMARK_RE})(#{METHOD_NAME_RE})\z/o.match(spec) or
|
|
65
65
|
raise ArgumentError, "wrong method spec: #{spec.inspect}"
|
|
66
|
-
|
|
66
|
+
cname = m[1] || raise
|
|
67
|
+
# @type var tmark: NameUtils::typemark
|
|
68
|
+
tmark = _ = m[2] || raise
|
|
69
|
+
mname = m[3] || raise
|
|
70
|
+
return [cname, tmark, mname]
|
|
67
71
|
end
|
|
68
72
|
end
|
|
69
73
|
|
|
70
74
|
def methodid2specstring(id)
|
|
71
|
-
c, t, m, _lib =
|
|
75
|
+
c, t, m, _lib = split_method_id(id)
|
|
72
76
|
classid2name(c) + typechar2mark(t) + decodename_url(m)
|
|
73
77
|
end
|
|
74
78
|
|
|
75
79
|
def methodid2specparts(id)
|
|
76
|
-
c, t, m, lib =
|
|
77
|
-
|
|
80
|
+
c, t, m, lib = split_method_id(id)
|
|
81
|
+
[classid2name(c), typechar2mark(t), decodename_url(m), libid2name(lib)]
|
|
78
82
|
end
|
|
79
83
|
|
|
80
84
|
def methodid2libid(id)
|
|
81
|
-
_c, _t, _m, lib =
|
|
85
|
+
_c, _t, _m, lib = split_method_id(id)
|
|
82
86
|
lib
|
|
83
87
|
end
|
|
84
88
|
|
|
85
89
|
def methodid2classid(id)
|
|
86
|
-
c, _t, _m, _lib =
|
|
90
|
+
c, _t, _m, _lib = split_method_id(id)
|
|
87
91
|
c
|
|
88
92
|
end
|
|
89
93
|
|
|
90
94
|
def methodid2typechar(id)
|
|
91
|
-
_c, t, _m, _lib =
|
|
95
|
+
_c, t, _m, _lib = split_method_id(id)
|
|
92
96
|
t
|
|
93
97
|
end
|
|
94
98
|
|
|
95
99
|
def methodid2typename(id)
|
|
96
|
-
_c, t, _m, _lib =
|
|
100
|
+
_c, t, _m, _lib = split_method_id(id)
|
|
97
101
|
typechar2name(t)
|
|
98
102
|
end
|
|
99
103
|
|
|
100
104
|
def methodid2typemark(id)
|
|
101
|
-
_c, t, _m, _lib =
|
|
105
|
+
_c, t, _m, _lib = split_method_id(id)
|
|
102
106
|
typechar2mark(t)
|
|
103
107
|
end
|
|
104
108
|
|
|
105
109
|
def methodid2mname(id)
|
|
106
|
-
_c, _t, m, _lib =
|
|
110
|
+
_c, _t, m, _lib = split_method_id(id)
|
|
107
111
|
decodename_url(m)
|
|
108
112
|
end
|
|
109
113
|
|
|
@@ -121,13 +125,13 @@ module BitClust
|
|
|
121
125
|
"#{cid}/#{typename2char(t)}.#{encodename_url(name)}.#{libid}"
|
|
122
126
|
end
|
|
123
127
|
|
|
124
|
-
@@split_method_id = {}
|
|
128
|
+
@@split_method_id = {} #: Hash[String, untyped]
|
|
125
129
|
|
|
126
130
|
# private module function
|
|
127
131
|
def split_method_id(id)
|
|
128
132
|
@@split_method_id[id] ||= begin
|
|
129
133
|
c, rest = id.split("/")
|
|
130
|
-
[c, *rest
|
|
134
|
+
[c, *rest&.split(%r<[/\.]>, 3)]
|
|
131
135
|
end
|
|
132
136
|
end
|
|
133
137
|
|
|
@@ -142,7 +146,7 @@ module BitClust
|
|
|
142
146
|
MARK_TO_NAME = NAME_TO_MARK.invert
|
|
143
147
|
|
|
144
148
|
def typename?(n)
|
|
145
|
-
NAME_TO_MARK.key?(n)
|
|
149
|
+
NAME_TO_MARK.key?(_ = n)
|
|
146
150
|
end
|
|
147
151
|
|
|
148
152
|
def typename2mark(name)
|
|
@@ -166,7 +170,7 @@ module BitClust
|
|
|
166
170
|
CHAR_TO_NAME = NAME_TO_CHAR.invert
|
|
167
171
|
|
|
168
172
|
def typechar?(c)
|
|
169
|
-
CHAR_TO_NAME.key?(c)
|
|
173
|
+
CHAR_TO_NAME.key?(_ = c)
|
|
170
174
|
end
|
|
171
175
|
|
|
172
176
|
def typename2char(name)
|
|
@@ -190,7 +194,7 @@ module BitClust
|
|
|
190
194
|
CHAR_TO_MARK = MARK_TO_CHAR.invert
|
|
191
195
|
|
|
192
196
|
def typemark?(m)
|
|
193
|
-
MARK_TO_CHAR.key?(m)
|
|
197
|
+
MARK_TO_CHAR.key?(_ = m)
|
|
194
198
|
end
|
|
195
199
|
|
|
196
200
|
def typechar2mark(char)
|
|
@@ -203,24 +207,39 @@ module BitClust
|
|
|
203
207
|
raise "must not happen: #{mark.inspect}"
|
|
204
208
|
end
|
|
205
209
|
|
|
210
|
+
# bitclust#250: Ruby 4.0 以降のドキュメントでは module function の表記を
|
|
211
|
+
# るりま独自の ".#" から "?." に変える(表示のみ。ソース側は既に "?."
|
|
212
|
+
# 記法に対応済みで、内部的には従来どおり ".#" に変換される)。
|
|
213
|
+
#
|
|
214
|
+
# これは見た目だけの変換であり、method id・URL・spec 文字列など識別子と
|
|
215
|
+
# して使う ".#" 自体は一切変えない。typemark が '.#' 以外、または version
|
|
216
|
+
# が不明(nil/空)な場合はそのまま返す。バージョン比較は文字列比較では
|
|
217
|
+
# なく Gem::Version で行う("10.0" を文字列比較すると "4.0" より小さく
|
|
218
|
+
# 見えてしまうため)。
|
|
219
|
+
def display_typemark(mark, version)
|
|
220
|
+
return mark unless mark == '.#'
|
|
221
|
+
return mark unless version && !version.empty?
|
|
222
|
+
Gem::Version.new(version) >= Gem::Version.new('4.0') ? '?.' : mark
|
|
223
|
+
end
|
|
224
|
+
|
|
206
225
|
def functionname?(n)
|
|
207
226
|
/\A\w+\z/ =~ n ? true : false
|
|
208
227
|
end
|
|
209
228
|
|
|
210
229
|
# string -> case-sensitive ID
|
|
211
230
|
def encodename_url(str)
|
|
212
|
-
str.gsub(/[^A-Za-z0-9_]/n) {|ch| sprintf('=%02x', ch[0].ord) }
|
|
231
|
+
str.gsub(/[^A-Za-z0-9_]/n) {|ch| sprintf('=%02x', (ch[0] || raise).ord) }
|
|
213
232
|
end
|
|
214
233
|
|
|
215
234
|
# case-sensitive ID -> string
|
|
216
235
|
def decodename_url(str)
|
|
217
|
-
str.gsub(/=[\da-h]{2}/ni) {|s| s[1,2].hex.chr }
|
|
236
|
+
str.gsub(/=[\da-h]{2}/ni) {|s| (s[1,2] || raise).hex.chr }
|
|
218
237
|
end
|
|
219
238
|
|
|
220
239
|
# string -> encoded string in a rdoc way
|
|
221
240
|
def encodename_rdocurl(str)
|
|
222
241
|
str = str.gsub(/[^A-Za-z0-9_.]/n) {|ch|
|
|
223
|
-
sprintf('-%02X', ch[0].ord)
|
|
242
|
+
sprintf('-%02X', (ch[0] || raise).ord)
|
|
224
243
|
}
|
|
225
244
|
str.sub(/\A-/, '')
|
|
226
245
|
end
|
|
@@ -232,18 +251,18 @@ module BitClust
|
|
|
232
251
|
|
|
233
252
|
# encoded string -> case-sensitive ID (decode only [A-Z])
|
|
234
253
|
def decodeid(str)
|
|
235
|
-
str.gsub(/-[a-z]/ni) {|s| s[1,1].upcase }
|
|
254
|
+
str.gsub(/-[a-z]/ni) {|s| (s[1,1] || raise).upcase }
|
|
236
255
|
end
|
|
237
256
|
|
|
238
257
|
def encodename_fs(str)
|
|
239
258
|
str.gsub(/[^a-z0-9_]/n) {|ch|
|
|
240
|
-
(/[A-Z]/n =~ ch) ? "-#{ch}" : sprintf('=%02x', ch[0].ord)
|
|
259
|
+
(/[A-Z]/n =~ ch) ? "-#{ch}" : sprintf('=%02x', (ch[0] || raise).ord)
|
|
241
260
|
}.downcase
|
|
242
261
|
end
|
|
243
262
|
|
|
244
263
|
def decodename_fs(str)
|
|
245
264
|
str.gsub(/=[\da-h]{2}|-[a-z]/ni) {|s|
|
|
246
|
-
(/\A-/ =~ s) ? s[1,1].upcase : s[1,2].hex.chr
|
|
265
|
+
(/\A-/ =~ s) ? (s[1,1] || raise).upcase : (s[1,2] || raise).hex.chr
|
|
247
266
|
}
|
|
248
267
|
end
|
|
249
268
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
# You can distribute/modify this program under the Ruby License.
|
|
9
9
|
#
|
|
10
10
|
|
|
11
|
+
require 'bitclust/compat'
|
|
11
12
|
require 'bitclust/parseutils'
|
|
12
13
|
require 'strscan'
|
|
13
14
|
|
|
@@ -40,10 +41,15 @@ module BitClust
|
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
# Handle pragmas like #@todo, #@include, #@since, etc.
|
|
44
|
+
#
|
|
45
|
+
# bitclust#285: prefix は #% が正式(GitHub が #@since 等の @英字 を
|
|
46
|
+
# ユーザー mention として解釈してしまうため)。旧 prefix #@ も、凍結タグ
|
|
47
|
+
# (frozen-*)の旧ソースを再取込する場合に備えて引き続き受け付ける。
|
|
43
48
|
class Preprocessor < LineFilter
|
|
44
49
|
|
|
45
50
|
def self.read(path, params = {})
|
|
46
51
|
if path.respond_to?(:gets)
|
|
52
|
+
# @type var path: File
|
|
47
53
|
io = wrap(path, params)
|
|
48
54
|
else
|
|
49
55
|
io = wrap(fopen(path, 'r:UTF-8'), params)
|
|
@@ -81,36 +87,48 @@ module BitClust
|
|
|
81
87
|
def next_line(f)
|
|
82
88
|
while line = f.gets
|
|
83
89
|
case line
|
|
84
|
-
when /\A(
|
|
90
|
+
when /\A(?!\#[@%])/
|
|
85
91
|
if current_cond.processing?
|
|
86
92
|
@buf.push line
|
|
87
93
|
break
|
|
88
94
|
end
|
|
89
|
-
when /\A
|
|
95
|
+
when /\A\#[@%]\#/ # preprocessor comment
|
|
90
96
|
;
|
|
91
|
-
when /\A
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
when /\A\#[@%]todo/i
|
|
98
|
+
# 出力は prefix によらず @todo に正規化する(下流の表示処理は
|
|
99
|
+
# 従来どおり @todo だけを見ればよい)
|
|
100
|
+
@buf.push line.sub(/\A\#[@%]/, '@') if current_cond.processing?
|
|
101
|
+
when /\A\#[@%]include\s*\((.*?)\)/
|
|
94
102
|
next unless current_cond.processing?
|
|
95
103
|
begin
|
|
96
|
-
file = $1.strip
|
|
97
|
-
basedir = File.dirname(line.location.file)
|
|
98
|
-
|
|
104
|
+
file = ($1 || raise).strip
|
|
105
|
+
basedir = File.dirname(line.location.file || raise)
|
|
106
|
+
path = "#{basedir}/#{file}"
|
|
107
|
+
# md ツリーのネイティブパース: 断片は .md 拡張子付きで保存されるが
|
|
108
|
+
# include ターゲットは元式の名前のまま(拡張子なしの pack-template、
|
|
109
|
+
# .rd 付きの fiddle/2.0/fiddle.lib.rd 等)。md 側の実ファイル名を試す
|
|
110
|
+
unless File.exist?(path)
|
|
111
|
+
cand = ["#{path}.md", path.sub(/\.rd\z/, '.md')].find { |c| File.exist?(c) }
|
|
112
|
+
path = cand if cand
|
|
113
|
+
end
|
|
114
|
+
@buf.concat Preprocessor.process(path, @params)
|
|
99
115
|
rescue Errno::ENOENT => _err
|
|
100
116
|
raise WrongInclude, "#{line.location}: \#@include'ed file not exist: #{file}"
|
|
101
117
|
end
|
|
102
|
-
when /\A
|
|
118
|
+
when /\A\#[@%]since\b/
|
|
103
119
|
cond_stmt_begin line, build_cond_by_value(line, 'version >=')
|
|
104
|
-
when /\A
|
|
120
|
+
when /\A\#[@%]until\b/
|
|
105
121
|
cond_stmt_begin line, build_cond_by_value(line, 'version <')
|
|
106
|
-
when /\A
|
|
122
|
+
when /\A\#[@%]version\b/
|
|
123
|
+
cond_stmt_begin line, build_cond_by_range(line)
|
|
124
|
+
when /\A\#[@%]samplecode\b/
|
|
107
125
|
samplecode_begin(line, samplecode_description_by_value(line))
|
|
108
|
-
when /\A
|
|
109
|
-
cond_stmt_begin line, line.sub(/\A
|
|
110
|
-
when /\A
|
|
126
|
+
when /\A\#[@%]if\b/
|
|
127
|
+
cond_stmt_begin line, line.sub(/\A\#[@%]if/, '').strip
|
|
128
|
+
when /\A\#[@%]else\s*\z/
|
|
111
129
|
parse_error "no matching \#@if", line if cond_toplevel?
|
|
112
130
|
cond_invert
|
|
113
|
-
when /\A
|
|
131
|
+
when /\A\#[@%]end\s*\z/
|
|
114
132
|
if samplecode_processing?
|
|
115
133
|
samplecode_end
|
|
116
134
|
else
|
|
@@ -123,7 +141,7 @@ module BitClust
|
|
|
123
141
|
end
|
|
124
142
|
if @buf.empty?
|
|
125
143
|
unless cond_toplevel?
|
|
126
|
-
parse_error "unterminated \#@if", @last_if
|
|
144
|
+
parse_error "unterminated \#@if", @last_if || raise
|
|
127
145
|
end
|
|
128
146
|
end
|
|
129
147
|
@buf.shift
|
|
@@ -138,8 +156,27 @@ module BitClust
|
|
|
138
156
|
end
|
|
139
157
|
end
|
|
140
158
|
|
|
159
|
+
# 版範囲の省略記法(#285): #%version A...B は半開区間 [A, B)。
|
|
160
|
+
# Ruby の終端排他 Range リテラルに合わせて3点ドット(.. は終端を含むと
|
|
161
|
+
# 誤解しやすいため受け付けない)。A... は A 以上、...B は B 未満。
|
|
162
|
+
# 版はダブルクォート付きでもよい
|
|
163
|
+
VERSION_LITERAL = /"(\d+(?:\.\d+)*)"|(\d+(?:\.\d+)*)/
|
|
164
|
+
def build_cond_by_range(line)
|
|
165
|
+
raw = line.sub(/\A\#[@%]version\b/, '').strip
|
|
166
|
+
case raw
|
|
167
|
+
when /\A#{VERSION_LITERAL}\.\.\.#{VERSION_LITERAL}\z/o
|
|
168
|
+
%Q(version >= "#{$1 || $2}" and version < "#{$3 || $4}")
|
|
169
|
+
when /\A#{VERSION_LITERAL}\.\.\.\z/o
|
|
170
|
+
%Q(version >= "#{$1 || $2}")
|
|
171
|
+
when /\A\.\.\.#{VERSION_LITERAL}\z/o
|
|
172
|
+
%Q(version < "#{$1 || $2}")
|
|
173
|
+
else
|
|
174
|
+
parse_error "wrong version range (expected A...B / A... / ...B)", line
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
141
178
|
def build_cond_by_value(line, left)
|
|
142
|
-
case ver = line.sub(/\A
|
|
179
|
+
case ver = line.sub(/\A\#[@%]\w+/, '').strip
|
|
143
180
|
when /\A[\d\.]+\z/
|
|
144
181
|
%Q(#{left} "#{ver}")
|
|
145
182
|
when /\A"[\d\.]+"\z/
|
|
@@ -150,7 +187,7 @@ module BitClust
|
|
|
150
187
|
end
|
|
151
188
|
|
|
152
189
|
def current_cond
|
|
153
|
-
@state_stack.last
|
|
190
|
+
@state_stack.last || raise
|
|
154
191
|
end
|
|
155
192
|
|
|
156
193
|
def cond_init
|
|
@@ -162,13 +199,13 @@ module BitClust
|
|
|
162
199
|
end
|
|
163
200
|
|
|
164
201
|
def cond_push(bool)
|
|
165
|
-
last = @state_stack.last
|
|
202
|
+
last = @state_stack.last || raise
|
|
166
203
|
@state_stack.push(last.next(bool, :condition))
|
|
167
204
|
end
|
|
168
205
|
|
|
169
206
|
def cond_invert
|
|
170
|
-
b = @state_stack.pop.processing?
|
|
171
|
-
last = @state_stack.last
|
|
207
|
+
b = (@state_stack.pop || raise).processing?
|
|
208
|
+
last = @state_stack.last || raise
|
|
172
209
|
@state_stack.push(last.next(!b, :condition))
|
|
173
210
|
end
|
|
174
211
|
|
|
@@ -229,10 +266,10 @@ module BitClust
|
|
|
229
266
|
def eval_primary(s)
|
|
230
267
|
s.skip(/\s+/)
|
|
231
268
|
if t = s.scan(/\w+/)
|
|
232
|
-
unless @params.key?(t)
|
|
269
|
+
unless @params.key?(t) # steep:ignore
|
|
233
270
|
scan_error "database property `#{t}' not exist"
|
|
234
271
|
end
|
|
235
|
-
@params[t]
|
|
272
|
+
@params[t] # steep:ignore
|
|
236
273
|
elsif t = s.scan(/".*?"/)
|
|
237
274
|
eval(t)
|
|
238
275
|
elsif t = s.scan(/'.*?'/)
|
|
@@ -258,7 +295,7 @@ module BitClust
|
|
|
258
295
|
end
|
|
259
296
|
|
|
260
297
|
def samplecode_push(description)
|
|
261
|
-
last = @state_stack.last
|
|
298
|
+
last = @state_stack.last || raise
|
|
262
299
|
@state_stack.push(last.next(true, :samplecode))
|
|
263
300
|
end
|
|
264
301
|
|
|
@@ -267,11 +304,11 @@ module BitClust
|
|
|
267
304
|
end
|
|
268
305
|
|
|
269
306
|
def samplecode_processing?
|
|
270
|
-
@state_stack.last.samplecode?
|
|
307
|
+
(@state_stack.last || raise).samplecode?
|
|
271
308
|
end
|
|
272
309
|
|
|
273
310
|
def samplecode_description_by_value(line)
|
|
274
|
-
line.sub(/\A
|
|
311
|
+
line.sub(/\A\#[@%]samplecode/, "")
|
|
275
312
|
end
|
|
276
313
|
|
|
277
314
|
def scan_error(msg)
|
|
@@ -321,10 +358,10 @@ module BitClust
|
|
|
321
358
|
|
|
322
359
|
def next_line(f)
|
|
323
360
|
while line = f.gets
|
|
324
|
-
if /\A
|
|
361
|
+
if /\A\#[@%]include\s*\((.*?)\)/ =~ line
|
|
325
362
|
begin
|
|
326
|
-
file = $1.strip
|
|
327
|
-
basedir = File.dirname(line.location.file)
|
|
363
|
+
file = ($1 || raise).strip
|
|
364
|
+
basedir = File.dirname(line.location.file || raise)
|
|
328
365
|
@buf.concat LineCollector.process("#{basedir}/#{file}")
|
|
329
366
|
rescue Errno::ENOENT => _err
|
|
330
367
|
raise WrongInclude, "#{line.location}: \#@include'ed file not exist: #{file}"
|