bitclust-core 1.2.6 → 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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/README.md +65 -0
  4. data/Rakefile +32 -0
  5. data/data/bitclust/catalog/ja_JP.UTF-8 +19 -1
  6. data/data/bitclust/searchpage/index.html +90 -0
  7. data/data/bitclust/template/class +69 -8
  8. data/data/bitclust/template/function +2 -2
  9. data/data/bitclust/template/layout +11 -3
  10. data/data/bitclust/template/method +2 -2
  11. data/data/bitclust/template/search +1 -1
  12. data/data/bitclust/template.epub/class +22 -1
  13. data/data/bitclust/template.epub/function +2 -2
  14. data/data/bitclust/template.epub/layout +1 -3
  15. data/data/bitclust/template.epub/method +2 -2
  16. data/data/bitclust/template.lillia/class +26 -5
  17. data/data/bitclust/template.lillia/layout +1 -3
  18. data/data/bitclust/template.lillia/method +2 -2
  19. data/data/bitclust/template.offline/class +49 -5
  20. data/data/bitclust/template.offline/function +2 -2
  21. data/data/bitclust/template.offline/layout +27 -3
  22. data/data/bitclust/template.offline/method +2 -2
  23. data/lib/bitclust/app.rb +17 -17
  24. data/lib/bitclust/capi_converter.rb +20 -0
  25. data/lib/bitclust/classentry.rb +68 -17
  26. data/lib/bitclust/compat.rb +3 -2
  27. data/lib/bitclust/completion.rb +59 -27
  28. data/lib/bitclust/crossrubyutils.rb +9 -5
  29. data/lib/bitclust/database.rb +29 -8
  30. data/lib/bitclust/doc_converter.rb +63 -0
  31. data/lib/bitclust/docentry.rb +2 -1
  32. data/lib/bitclust/entity_splitter.rb +221 -0
  33. data/lib/bitclust/entry.rb +48 -7
  34. data/lib/bitclust/exception.rb +1 -0
  35. data/lib/bitclust/functiondatabase.rb +14 -1
  36. data/lib/bitclust/functionentry.rb +6 -1
  37. data/lib/bitclust/functionreferenceparser.rb +5 -4
  38. data/lib/bitclust/generators/epub.rb +11 -3
  39. data/lib/bitclust/htmlutils.rb +2 -1
  40. data/lib/bitclust/include_graph.rb +375 -0
  41. data/lib/bitclust/include_pruner.rb +144 -0
  42. data/lib/bitclust/interface.rb +2 -1
  43. data/lib/bitclust/libraryentry.rb +9 -7
  44. data/lib/bitclust/lineinput.rb +8 -5
  45. data/lib/bitclust/link_checker.rb +179 -0
  46. data/lib/bitclust/markdown_bridge.rb +186 -0
  47. data/lib/bitclust/markdown_orchestrator.rb +267 -0
  48. data/lib/bitclust/markdown_to_rrd.rb +824 -0
  49. data/lib/bitclust/markdown_tree.rb +217 -0
  50. data/lib/bitclust/mdcompiler.rb +883 -0
  51. data/lib/bitclust/mdparser.rb +347 -0
  52. data/lib/bitclust/messagecatalog.rb +4 -3
  53. data/lib/bitclust/method_since_calculator.rb +117 -0
  54. data/lib/bitclust/methoddatabase.rb +125 -14
  55. data/lib/bitclust/methodentry.rb +130 -7
  56. data/lib/bitclust/methodid.rb +13 -11
  57. data/lib/bitclust/methodsignature.rb +11 -4
  58. data/lib/bitclust/nameutils.rb +42 -22
  59. data/lib/bitclust/parseutils.rb +1 -0
  60. data/lib/bitclust/preprocessor.rb +70 -32
  61. data/lib/bitclust/progress_bar.rb +1 -0
  62. data/lib/bitclust/rdcompiler.rb +197 -96
  63. data/lib/bitclust/refsdatabase.rb +24 -8
  64. data/lib/bitclust/reloadable_request_handler.rb +72 -0
  65. data/lib/bitclust/requesthandler.rb +22 -16
  66. data/lib/bitclust/ridatabase.rb +11 -4
  67. data/lib/bitclust/rrd_to_markdown.rb +925 -0
  68. data/lib/bitclust/rrdparser.rb +197 -30
  69. data/lib/bitclust/runner.rb +18 -2
  70. data/lib/bitclust/screen.rb +81 -11
  71. data/lib/bitclust/search_index_generator.rb +288 -0
  72. data/lib/bitclust/searcher.rb +72 -22
  73. data/lib/bitclust/server.rb +6 -1
  74. data/lib/bitclust/silent_progress_bar.rb +1 -0
  75. data/lib/bitclust/simplesearcher.rb +25 -12
  76. data/lib/bitclust/subcommand.rb +8 -1
  77. data/lib/bitclust/subcommands/ancestors_command.rb +10 -2
  78. data/lib/bitclust/subcommands/checklink_command.rb +54 -0
  79. data/lib/bitclust/subcommands/chm_command.rb +16 -7
  80. data/lib/bitclust/subcommands/classes_command.rb +6 -0
  81. data/lib/bitclust/subcommands/epub_command.rb +1 -0
  82. data/lib/bitclust/subcommands/extract_command.rb +6 -0
  83. data/lib/bitclust/subcommands/htmlfile_command.rb +22 -7
  84. data/lib/bitclust/subcommands/init_command.rb +5 -1
  85. data/lib/bitclust/subcommands/list_command.rb +13 -4
  86. data/lib/bitclust/subcommands/lookup_command.rb +29 -9
  87. data/lib/bitclust/subcommands/methods_command.rb +11 -2
  88. data/lib/bitclust/subcommands/methodsince_command.rb +80 -0
  89. data/lib/bitclust/subcommands/preproc_command.rb +6 -0
  90. data/lib/bitclust/subcommands/property_command.rb +3 -1
  91. data/lib/bitclust/subcommands/query_command.rb +1 -0
  92. data/lib/bitclust/subcommands/searchpage_command.rb +102 -0
  93. data/lib/bitclust/subcommands/server_command.rb +16 -10
  94. data/lib/bitclust/subcommands/setup_command.rb +25 -10
  95. data/lib/bitclust/subcommands/statichtml_command.rb +132 -6
  96. data/lib/bitclust/subcommands/update_command.rb +111 -2
  97. data/lib/bitclust/syntax_highlighter.rb +52 -5
  98. data/lib/bitclust/textutils.rb +4 -3
  99. data/lib/bitclust/version.rb +2 -1
  100. data/lib/bitclust/version_badges.rb +90 -0
  101. data/lib/bitclust/whole_file_gate.rb +137 -0
  102. data/lib/bitclust.rb +1 -0
  103. data/test/test_app.rb +269 -0
  104. data/test/test_bitclust.rb +2 -0
  105. data/test/test_capi_converter.rb +91 -0
  106. data/test/test_class_screen.rb +413 -0
  107. data/test/test_copy_doc_md.rb +53 -0
  108. data/test/test_doc_converter.rb +78 -0
  109. data/test/test_entity_splitter.rb +231 -0
  110. data/test/test_entry.rb +207 -2
  111. data/test/test_eol_warning.rb +43 -0
  112. data/test/test_functionreferenceparser.rb +11 -0
  113. data/test/test_include_graph.rb +640 -0
  114. data/test/test_include_pruner.rb +133 -0
  115. data/test/test_link_checker.rb +114 -0
  116. data/test/test_lookup_command.rb +135 -0
  117. data/test/test_markdown_bridge.rb +217 -0
  118. data/test/test_markdown_orchestrator.rb +478 -0
  119. data/test/test_markdown_to_rrd.rb +757 -0
  120. data/test/test_markdown_tree.rb +369 -0
  121. data/test/test_mdcompiler.rb +1276 -0
  122. data/test/test_mdparser.rb +538 -0
  123. data/test/test_method_screen.rb +166 -0
  124. data/test/test_method_since_calculator.rb +290 -0
  125. data/test/test_methoddatabase.rb +16 -0
  126. data/test/test_methodentry.rb +328 -0
  127. data/test/test_methodsignature.rb +3 -1
  128. data/test/test_methodsince_command.rb +168 -0
  129. data/test/test_nameutils.rb +22 -0
  130. data/test/test_preprocessor.rb +215 -0
  131. data/test/test_rdcompiler.rb +429 -27
  132. data/test/test_refsdatabase.rb +32 -0
  133. data/test/test_rrd_to_markdown.rb +968 -0
  134. data/test/test_rrdparser.rb +295 -2
  135. data/test/test_run_ruby_wasm.rb +54 -0
  136. data/test/test_run_worker_prelude.rb +83 -0
  137. data/test/test_runner.rb +51 -0
  138. data/test/test_search_index_generator.rb +513 -0
  139. data/test/test_search_screen.rb +48 -0
  140. data/test/test_searcher.rb +153 -0
  141. data/test/test_searchpage_command.rb +167 -0
  142. data/test/test_simplesearcher.rb +28 -0
  143. data/test/test_statichtml_command.rb +204 -0
  144. data/test/test_syntax_highlighter.rb +60 -0
  145. data/test/test_whole_file_gate.rb +175 -0
  146. data/theme/default/js/NOTICE +42 -0
  147. data/theme/default/js/run-worker.js +111 -0
  148. data/theme/default/js/run.js +350 -0
  149. data/theme/default/js/search_controller.js +134 -0
  150. data/theme/default/js/search_init.js +176 -0
  151. data/theme/default/js/search_navigation.js +110 -0
  152. data/theme/default/js/search_page.js +202 -0
  153. data/theme/default/js/search_ranker.js +244 -0
  154. data/theme/default/script.js +91 -18
  155. data/theme/default/search.css +149 -0
  156. data/theme/default/style.css +193 -21
  157. data/theme/default/syntax-highlight.css +8 -0
  158. data/theme/lillia/style.css +45 -1
  159. metadata +178 -21
  160. data/README +0 -32
@@ -0,0 +1,221 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bitclust/include_graph'
4
+ require 'bitclust/whole_file_gate'
5
+
6
+ module BitClust
7
+ # マルチエンティティ RD のエンティティ単位分割(O3)。
8
+ #
9
+ # 「ヘッダ関係(include/extend/alias)を持つエンティティは自分のファイルを持ち、
10
+ # 関係は front matter に一元化する」ため、関係を持つマルチエンティティファイルを
11
+ # エンティティ単位のセグメントへ分割する。関係を持たない束ね(Errno 族等)は
12
+ # 分割しない(判断はオーケストレータが行う。ここは純テキスト変換)。
13
+ #
14
+ # 分割の前処理として、スコープ定数(スコープ内で常に真/偽)の版ゲートのうち
15
+ # エンティティ H1 を包むものを解決する。版で改名されたエンティティ
16
+ # (thread/Mutex, Net::HTTPURITooLong 等の #@since/#@else H1 ペア)が
17
+ # スコープ内の単一 H1 に収束する(旧名は活き枝の alias 行として残っている)。
18
+ module EntitySplitter
19
+ H1_RE = /\A=(?!=)\s*(?:class|module|object|reopen|redefine)\s+(\S+)/
20
+ GATE_OPEN_RE = /\A\#@(since|until|if)\s*(.*)$/
21
+ BLOCK_OPEN_RE = /\A\#@(?:since|until|if|samplecode)\b/
22
+ BLANK_RE = /\A\s*\z/
23
+
24
+ module_function
25
+
26
+ # スコープ定数(スコープ内で常に真/偽)な版ゲートのうち、エンティティ H1 を
27
+ # 含むブロックを解決する。活きている枝の内容(再帰的に解決)を残し、
28
+ # ゲート行と死んだ枝を落とす。スコープ内で真偽が変わるゲートと、
29
+ # H1 を含まないゲート(散文の版分岐・gated relations)は触らない。
30
+ def resolve_header_gates(src, scope)
31
+ lines = src.lines
32
+ out = [] #: Array[String]
33
+ i = 0
34
+ while i < lines.length
35
+ line = lines[i]
36
+ truth = constant_truth(line, scope)
37
+ if !truth.nil? && (block = parse_block(lines, i)) &&
38
+ contains_entity_h1?(block[:body] + block[:else_body])
39
+ active = truth ? block[:body] : block[:else_body]
40
+ resolved = resolve_header_gates(active.join, scope).lines
41
+ if resolved.empty? && out.last =~ BLANK_RE && lines[block[:next]] =~ BLANK_RE
42
+ i = block[:next] + 1 # ブロックごと消えた場合は後続の空行を1つ畳む
43
+ else
44
+ i = block[:next]
45
+ end
46
+ out.concat(resolved)
47
+ else
48
+ out << line
49
+ i += 1
50
+ end
51
+ end
52
+ out.join
53
+ end
54
+
55
+ # ゲート行のスコープ定数評価: 常真なら true、常偽なら false、
56
+ # 定数でない/ゲートでないなら nil。
57
+ # #@if は「version >= "X"(X <= 下限)」形のみ常真と証明できる
58
+ def constant_truth(line, scope)
59
+ cond = gate_condition(line)
60
+ return nil unless cond
61
+ if cond.kind == :if
62
+ WholeFileGate.provably_true_if?(cond.version, scope) ? true : nil
63
+ elsif scope.always?(cond)
64
+ true
65
+ elsif scope.never?(cond)
66
+ false
67
+ end
68
+ end
69
+
70
+ # samplecode の内容を除いて、エンティティ H1 行を含むか
71
+ def contains_entity_h1?(lines)
72
+ code = 0
73
+ lines.each do |l|
74
+ case l
75
+ when /\A\#@samplecode\b/ then code += 1
76
+ when /\A\#@end\b/ then code -= 1 if code > 0
77
+ when H1_RE then return true if code.zero?
78
+ end
79
+ end
80
+ false
81
+ end
82
+
83
+ # エンティティ単位のセグメント列 [[エンティティ名, テキスト], ...] を返す。
84
+ # 境界は深さ0の H1 行、または最初の内容行が H1 の版ゲートブロック
85
+ # (スコープ内ゲート付きエンティティ。ブロック全体が1セグメント)。
86
+ # 先頭に H1 以外の内容がある場合(ライブラリ概要部)は name=nil の
87
+ # ベースセグメントとして返す。連結すると入力に一致する。
88
+ def segments(src)
89
+ lines = src.lines
90
+ # [行index, エンティティ名, ゲート付きか]
91
+ boundaries = [] #: Array[[Integer, String?, bool]]
92
+ depth = 0
93
+ lines.each_with_index do |line, i|
94
+ case line
95
+ when BLOCK_OPEN_RE
96
+ if depth.zero? && line =~ /\A\#@(?:since|until|if)\b/ &&
97
+ (name = first_h1_name(lines, i + 1))
98
+ boundaries << [i, name, true]
99
+ end
100
+ depth += 1
101
+ when /\A\#@end\b/
102
+ depth -= 1
103
+ when H1_RE
104
+ boundaries << [i, $1, false] if depth.zero?
105
+ end
106
+ end
107
+ # ゲート付き H1 境界は、ゲートがセグメント全体を包む場合のみ分割境界にする。
108
+ # H1 と見出しだけがゲートされ内容がゲートの外にある形(syslog の旧構造)を
109
+ # 単独ファイル化すると、ゲートが偽の版で自立パースできない
110
+ # (旧世界では直前エンティティの内容として付く)ため、直前セグメントに残す
111
+ boundaries = boundaries.each_with_index.select { |(start, _, gated), idx|
112
+ next true unless gated
113
+ stop = idx + 1 < boundaries.length ? boundaries[idx + 1][0] : lines.length
114
+ gate_wraps_segment?(lines, start, stop)
115
+ }.map { |(start, name, _), _| [start, name] } #: Array[[Integer, String?]]
116
+ return nil if boundaries.empty?
117
+ if (lines[0...(boundaries.first || raise)[0]] || raise).all? { |l| l =~ BLANK_RE }
118
+ boundaries[0] = [0, boundaries[0][1]] # 先頭の空行は最初のセグメントへ
119
+ else
120
+ boundaries.unshift([0, nil]) # ライブラリ概要部(ベースセグメント)
121
+ end
122
+
123
+ boundaries.each_with_index.map do |(start, name), idx|
124
+ stop = idx + 1 < boundaries.length ? boundaries[idx + 1][0] : lines.length
125
+ [name, (lines[start...stop] || raise).join]
126
+ end
127
+ end
128
+
129
+ # start のゲート開き行に対応する #@end がセグメント終端(末尾の空行は許容)に
130
+ # あるか。ゲートがセグメント全体を包むときのみ真
131
+ def gate_wraps_segment?(lines, start, stop)
132
+ depth = 0
133
+ close = nil #: Integer?
134
+ (start...stop).each do |i|
135
+ case lines[i]
136
+ when BLOCK_OPEN_RE then depth += 1
137
+ when /\A\#@end\b/
138
+ depth -= 1
139
+ if depth.zero?
140
+ close = i
141
+ break
142
+ end
143
+ end
144
+ end
145
+ return false unless close
146
+ (lines[(close + 1)...stop] || raise).all? { |l| l =~ BLANK_RE }
147
+ end
148
+
149
+ # エンティティ名 → 出力ファイル名(拡張子なし)。既存の命名規約に合わせ :: → __
150
+ def entity_filename(name)
151
+ name.gsub('::', '__')
152
+ end
153
+
154
+ # いずれかのエンティティの H1 直後のヘッダ領域(関係行・#@・空行が続く範囲)に
155
+ # include/extend/alias があるか。本文中やコード例の同名行は数えない
156
+ def header_relations?(src)
157
+ in_header = false
158
+ src.each_line do |line|
159
+ if line =~ H1_RE
160
+ in_header = true
161
+ elsif in_header
162
+ case line
163
+ when /\A(?:include|extend|alias)\s+\S/ then return true
164
+ when /\A\#@/, BLANK_RE then nil
165
+ else in_header = false
166
+ end
167
+ end
168
+ end
169
+ false
170
+ end
171
+
172
+ def gate_condition(line)
173
+ return nil unless line =~ GATE_OPEN_RE
174
+ # Preprocessor は #@since "1.8.5" のクォート形式も受理する
175
+ IncludeGraph::Condition.new(($1 || raise).to_sym, ($2 || raise).strip.delete_prefix('"').delete_suffix('"'))
176
+ end
177
+
178
+ # i のゲート開始行から対応を取り、{body:, else_body:, next:} を返す。
179
+ # body/else_body は枝の行列、next は #@end の次の行 index。対応が取れなければ nil
180
+ def parse_block(lines, i)
181
+ depth = 0
182
+ body = [] #: Array[String]
183
+ else_body = [] #: Array[String]
184
+ current = body
185
+ j = i
186
+ while j < lines.length
187
+ line = lines[j]
188
+ case line
189
+ when BLOCK_OPEN_RE
190
+ depth += 1
191
+ current << line unless j == i
192
+ when /\A\#@else\b/
193
+ if depth == 1
194
+ current = else_body
195
+ else
196
+ current << line
197
+ end
198
+ when /\A\#@end\b/
199
+ depth -= 1
200
+ return { body: body, else_body: else_body, next: j + 1 } if depth.zero?
201
+ current << line
202
+ else
203
+ current << line
204
+ end
205
+ j += 1
206
+ end
207
+ nil
208
+ end
209
+
210
+ def first_content_is_h1?(branch_lines)
211
+ first = branch_lines.find { |l| l !~ BLANK_RE }
212
+ first =~ H1_RE ? true : false
213
+ end
214
+
215
+ # i 以降の最初の非空行が H1 ならその名前を返す
216
+ def first_h1_name(lines, i)
217
+ first = (lines[i..] || raise).find { |l| l !~ BLANK_RE }
218
+ first =~ H1_RE ? $1 : nil
219
+ end
220
+ end
221
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/entry.rb
3
4
  #
@@ -112,11 +113,11 @@ module BitClust
112
113
  when 'LibraryEntry' then "restore_library(h['#{@name}'])"
113
114
  when 'ClassEntry' then "restore_class(h['#{@name}'])"
114
115
  when 'MethodEntry' then "restore_method(h['#{@name}'])"
115
- when '[String]' then "h['#{@name}'].split(/,(?=.)/)"
116
+ when '[String]' then "(h['#{@name}'] || '').split(/,(?=.)/)"
116
117
  when '[LibraryEntry]' then "restore_libraries(h['#{@name}'])"
117
118
  when '[ClassEntry]' then "restore_classes(h['#{@name}'])"
118
119
  when '[MethodEntry]' then "restore_methods(h['#{@name}'])"
119
- when 'Location' then "h['#{@name}']&.tap { |loc| break if loc.empty?; break Location.new(*loc.split(?:)) }"
120
+ when 'Location' then "h['#{@name}']&.tap { |loc| break if loc.empty?; break Location.new(loc.split(?:).first, nil) }"
120
121
  else
121
122
  raise "must not happen: @type=#{@type.inspect}"
122
123
  end
@@ -134,7 +135,7 @@ module BitClust
134
135
  when '[LibraryEntry]' then "serialize_entries(@#{@name})"
135
136
  when '[ClassEntry]' then "serialize_entries(@#{@name})"
136
137
  when '[MethodEntry]' then "serialize_entries(@#{@name})"
137
- when 'Location' then "@#@name.to_s"
138
+ when 'Location' then "(@#{@name} && @#{@name}.file).to_s"
138
139
  else
139
140
  raise "must not happen: @type=#{@type.inspect}"
140
141
  end
@@ -149,6 +150,46 @@ module BitClust
149
150
  @db = db
150
151
  end
151
152
 
153
+ # description 等、コンパイラを通さない表示テキスト。
154
+ # md ソースの DB では旧経路と同じ表示形(rd インライン形式)へ戻す
155
+ def display_text(text)
156
+ return text unless text
157
+ if @db.properties['source_format'] == 'markdown'
158
+ # LibraryEntry#require(ライブラリ関係の登録)が Kernel#require を
159
+ # 隠蔽するため、ファイルロードは Kernel を明示する
160
+ Kernel.require 'bitclust/markdown_to_rrd'
161
+ ::BitClust::MarkdownToRRD.restore_description(text)
162
+ else
163
+ text
164
+ end
165
+ end
166
+ private :display_text
167
+
168
+ # BitClust::RDCompiler::BracketLink と同等の正規表現(/n なし)
169
+ BracketLink = /\[\[[\w-]+?:[!-~]+?(?:\[\] )?\]\]/
170
+
171
+ # meta description など、コンパイラを通さずマークアップも解釈されない
172
+ # 場所に使うテキスト。非 ASCII 文字間の改行は削除し(ブラウザでは
173
+ # 空白扱いになり日本語文中に不自然な空白が見えるため)、残りの改行は
174
+ # 空白に変換、ブラケットリンクはリンク先名のみにする
175
+ def description_text(text)
176
+ text = display_text(text)
177
+ return text unless text
178
+ # module function の ".#" は表示専用なので、DB バージョンが 4.0 以降なら
179
+ # "?." で表示する(RDCompiler#display_spec と同じ #250/#282 の規則。
180
+ # ここは可視ページを通さない meta description 用の経路なので、bracket_link
181
+ # と同じ変換を独立に適用する必要がある。spec・URL・アンカーキーは不変)
182
+ version = @db&.propget('version')
183
+ text = text.split("\n").map(&:strip).join("\n")
184
+ .gsub(/(\P{ascii})\n(?=\P{ascii})/) { $1 || raise }
185
+ .tr("\n", ' ')
186
+ text.gsub(BracketLink) {|link|
187
+ label = ((link[2..-3] || raise).split(':', 2).last || raise).rstrip
188
+ label.include?('.#') ? label.sub('.#', NameUtils.display_typemark('.#', version)) : label
189
+ }
190
+ end
191
+ private :description_text
192
+
152
193
  def type_id
153
194
  self.class.type_id
154
195
  end
@@ -188,11 +229,11 @@ module BitClust
188
229
  end
189
230
 
190
231
  def restore_library(id)
191
- LibraryEntry.load(@db, id)
232
+ LibraryEntry.load(@db, id) # steep:ignore
192
233
  end
193
234
 
194
235
  def restore_class(id)
195
- id.empty? ? nil : ClassEntry.load(@db, id)
236
+ id.empty? ? nil : ClassEntry.load(@db, id) # steep:ignore
196
237
  end
197
238
 
198
239
  def restore_libraries(str)
@@ -209,7 +250,7 @@ module BitClust
209
250
 
210
251
  def restore_entries(str, klass)
211
252
  return [] if str.nil?
212
- str.split(',').map {|id| klass.load(@db, id) }
253
+ str.split(',').map {|id| klass.load(@db, id) } # steep:ignore
213
254
  end
214
255
 
215
256
  def serialize_entry(x)
@@ -226,7 +267,7 @@ module BitClust
226
267
 
227
268
  def path_string(path)
228
269
  i = path.index(name())
229
- (path[i..-1] + [name()]).join(' -> ')
270
+ ((path[i..-1] || raise) + [name()]).join(' -> ')
230
271
  end
231
272
  private :path_string
232
273
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/exception.rb
3
4
  #
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/functiondatabase.rb
3
4
  #
@@ -52,6 +53,18 @@ module BitClust
52
53
  @dirty_functions.clear
53
54
  end
54
55
 
56
+ # C API の Markdown ツリー(manual/capi)を直接パースして更新する(M3)。
57
+ # filename は旧経路と同じ「eval.c」等(basename から .md を除いた形)
58
+ def update_by_markdowntree(md_root)
59
+ check_transaction
60
+ require 'bitclust/mdparser'
61
+ # 描画層(screen.rb)が MDCompiler を選択するためのマーカー
62
+ propset 'source_format', 'markdown'
63
+ Dir.glob(File.join(md_root, '*.md')).sort.each do |path|
64
+ MDFunctionParser.new(self).parse_file(path, File.basename(path, '.md'), properties())
65
+ end
66
+ end
67
+
55
68
  def update_by_file(path, filename)
56
69
  check_transaction
57
70
  FunctionReferenceParser.new(self).parse_file(path, filename, properties())
@@ -68,7 +81,7 @@ module BitClust
68
81
  def open_function(id)
69
82
  check_transaction
70
83
  if exist?("function/#{id}")
71
- f = load_function(id)
84
+ f = load_function(id) || raise
72
85
  f.clear
73
86
  else
74
87
  f = (@functionmap[id] ||= FunctionEntry.new(self, id))
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/functionentry.rb
3
4
  #
@@ -51,6 +52,10 @@ module BitClust
51
52
  remove_method :name
52
53
  alias name id
53
54
  alias label id
55
+ # bitclust#250: MethodEntry の display_label と同じインターフェースを
56
+ # 満たすためのエイリアス。関数には module function の概念(typemark)が
57
+ # ないので単に label と同じ(変換なし)
58
+ alias display_label label
54
59
 
55
60
  alias macro? macro
56
61
  alias private? private
@@ -78,7 +83,7 @@ module BitClust
78
83
  end
79
84
 
80
85
  def description
81
- source.split(/\n\n+/, 2)[0].strip
86
+ description_text(source.split(/\n\n+/, 2)[0].strip)
82
87
  end
83
88
  end
84
89
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/functionreferenceparser.rb
3
4
  #
@@ -60,7 +61,7 @@ module BitClust
60
61
  f.name = h.name
61
62
  f.params = h.params
62
63
  f.source = body.join('')
63
- f.source_location = body[0]&.location&.tap {|loc| break Location.new(@path, loc.line - 1) }
64
+ f.source_location = body[0]&.location && Location.new(@path, nil)
64
65
  }
65
66
  end
66
67
 
@@ -70,9 +71,9 @@ module BitClust
70
71
  raise ParseError, "syntax error: #{header.inspect}" unless m
71
72
  h.macro = m[1] ? true : false
72
73
  h.private = m[2] ? true : false
73
- h.type = m[3].strip
74
- h.name = m[4]
75
- h.params = m[5].strip if m[5]
74
+ h.type = m[3]&.strip || raise
75
+ h.name = m[4] || raise
76
+ h.params = m[5]&.strip if m[5]
76
77
  h
77
78
  end
78
79
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'fileutils'
2
3
  require 'tmpdir'
3
4
  require 'erb'
@@ -60,6 +61,7 @@ module BitClust
60
61
  ]
61
62
  argv << "--fs-casesensitive" if @fs_casesensitive
62
63
  argv << "--quiet" unless @verbose
64
+ # @type var options: Subcommand::options
63
65
  options = {
64
66
  :prefix => @prefix,
65
67
  :capi => @capi,
@@ -70,7 +72,7 @@ module BitClust
70
72
  end
71
73
 
72
74
  def generate_contents_opf(epub_directory)
73
- items = []
75
+ items = [] #: Array[{:id => String, :path => Pathname}]
74
76
  glob_relative_path(epub_directory, "#{CONTENTS_DIR_NAME}/class/*.xhtml").each do |path|
75
77
  items << {
76
78
  :id => decodename_package(path.basename(".*").to_s),
@@ -78,7 +80,13 @@ module BitClust
78
80
  }
79
81
  end
80
82
  items.sort_by!{|item| item[:path] }
81
- contents = ERB.new(File.read(@templatedir + "contents"), nil, "-").result(binding)
83
+ template = (@templatedir + "contents").read
84
+ if ::ERB.instance_method(:initialize).parameters.last.first == :key
85
+ erb = ::ERB.new(template, trim_mode: '-')
86
+ else
87
+ erb = ::ERB.new(template, nil, "-") # steep:ignore UnexpectedPositionalArgument
88
+ end
89
+ contents = erb.result(binding)
82
90
  File.open(epub_directory + "contents.opf", "w") do |f|
83
91
  f.write contents
84
92
  end
@@ -93,7 +101,7 @@ module BitClust
93
101
  end
94
102
 
95
103
  def glob_relative_path(path, pattern)
96
- relative_paths = []
104
+ relative_paths = [] #: Array[Pathname]
97
105
  absolute_path_to_search = Pathname.new(path).realpath
98
106
  Dir.glob(absolute_path_to_search + pattern) do |absolute_path|
99
107
  absolute_path = Pathname.new(absolute_path)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/htmlutils.rb
3
4
  #
@@ -20,7 +21,7 @@ module BitClust
20
21
 
21
22
  # make method anchor from MethodEntry
22
23
  def link_to_method(m, specp = false)
23
- label = specp ? m.label : m.short_label
24
+ label = specp ? m.display_label : m.display_short_label
24
25
  a_href(@urlmapper.method_url(methodid2specstring(m.id)), label)
25
26
  end
26
27