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
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/completion.rb
3
4
  #
@@ -9,7 +10,7 @@
9
10
 
10
11
  module BitClust
11
12
 
12
- # Provides completion search methods like _search_classes, _search_methods.
13
+ # Provides completion search methods like _search_classes, _search_methods.
13
14
  # Included by MethodDatabase and FunctionDatabase.
14
15
  module Completion
15
16
 
@@ -20,18 +21,20 @@ module BitClust
20
21
  #
21
22
 
22
23
  def _search_classes(pattern)
24
+ # @type self: MethodDatabase
23
25
  expand_ic(classes(), pattern)
24
26
  end
25
27
 
26
28
  def _search_methods(pattern)
29
+ # @type self: MethodDatabase
27
30
  case
28
31
  when pattern.empty?
29
32
  recordclass = SearchResult::Record
30
33
  SearchResult.new(self, pattern, classes(),
31
- methods().map {|m| s = m.spec; recordclass.new(s, s, m) })
34
+ methods().map {|m| s = m.spec; recordclass.new(self, s, s, m) })
32
35
  when pattern.special_variable?
33
36
  c = fetch_class('Kernel')
34
- SearchResult.new(self, pattern, [c], search_svar(c, pattern.method))
37
+ SearchResult.new(self, pattern, [c], search_svar(c, pattern.method || raise))
35
38
  when pattern.class?
36
39
  search_methods_from_cname(pattern)
37
40
  else
@@ -53,22 +56,25 @@ GC.enable; GC.start; x
53
56
  end
54
57
 
55
58
  def _search_functions(pattern)
59
+ # @type self: FunctionDatabase
56
60
  expand_ic(functions(), pattern)
57
61
  end
58
62
 
59
63
  def search_svar(c, pattern)
64
+ # @type self: MethodDatabase
60
65
  expand(c.special_variables, pattern)\
61
66
  .map {|m| SearchResult::Record.new(self, m.spec, m.spec, m) }
62
67
  end
63
68
 
64
69
  def search_methods_from_cname(pattern)
65
- cs = expand_ic(classes(), pattern.klass)
70
+ # @type self: MethodDatabase
71
+ cs = expand_ic(classes(), pattern.klass || raise)
66
72
  return SearchResult.new(self, pattern, [], []) if cs.empty?
67
73
  recs = cs.map {|c|
68
74
  c.entries.map {|m|
69
75
  if not pattern.type or m.typemark == pattern.type
70
76
  s = m.spec
71
- SearchResult::Record.new(s, s, m)
77
+ SearchResult::Record.new(self, s, s, m)
72
78
  else
73
79
  nil
74
80
  end
@@ -78,13 +84,16 @@ GC.enable; GC.start; x
78
84
  end
79
85
 
80
86
  def mspec_from_cref_mname(cref, name)
87
+ # @type self: MethodDatabase
81
88
  m = /\A(#{NameUtils::CLASS_PATH_RE})(#{NameUtils::TYPEMARK_RE})\Z/.match(cref)
82
- MethodSpec.new(m[1], m[2], name)
89
+ m || raise
90
+ MethodSpec.new(m[1] || raise, _ = m[2], name)
83
91
  end
84
92
 
85
93
  def search_methods_from_mname(pattern)
94
+ # @type self: MethodDatabase
86
95
  #timer_init
87
- names = expand_name_narrow(method_names(), pattern.method)
96
+ names = expand_name_narrow(method_names(), pattern.method || raise)
88
97
  #split_time "m expandN (#{names.size})"
89
98
  records = names.map {|name|
90
99
  crefs = mname2crefs_narrow(name)
@@ -98,14 +107,16 @@ GC.enable; GC.start; x
98
107
  end
99
108
 
100
109
  def search_methods_from_cname_mname(pattern)
110
+ # @type self: MethodDatabase
101
111
  #timer_init
102
112
  recs = try(typechars(pattern.type, pattern.method)) {|ts|
103
- expand_method_name(pattern.klass, ts, pattern.method)
113
+ expand_method_name(pattern.klass || raise, ts, pattern.method || raise)
104
114
  }
105
- SearchResult.new(self, pattern, recs.map {|rec| rec.class_name }, recs)
115
+ SearchResult.new(self, pattern, recs.map {|rec| rec.class_name }, recs) # steep:ignore
106
116
  end
107
117
 
108
118
  def expand_method_name(c, ts, m)
119
+ # @type self: MethodDatabase
109
120
  names_w = expand_name_wide(method_names(), m)
110
121
  return [] if names_w.empty?
111
122
  #split_time "m expandW (#{names_w.size})"
@@ -141,18 +152,20 @@ GC.enable; GC.start; x
141
152
  end
142
153
 
143
154
  def count_class(recs)
155
+ # @type self: MethodDatabase
144
156
  recs.map {|rec| rec.class_name }.uniq.size
145
157
  end
146
158
 
147
159
  def make_cm_combination(cpat, ts, mnames)
148
- result = []
160
+ # @type self: MethodDatabase
161
+ result = [] #: Array[SearchResult::Record]
149
162
  $cm_comb_m = 0
150
163
  mnames.each do |m|
151
164
  crefs = expand_name_narrow(mname2crefs_wide(m), cpat, ts)
152
165
  next if crefs.empty?
153
166
  $cm_comb_m += 1
154
167
  crefs.each do |ref|
155
- spec = MethodSpec.new(classid2name(ref.chop), ref[-1,1], m)
168
+ spec = MethodSpec.new(classid2name(ref.chop), _ = ref[-1,1], m)
156
169
  result.push SearchResult::Record.new(self, spec)
157
170
  end
158
171
  end
@@ -175,7 +188,7 @@ $cm_comb_m += 1
175
188
  end
176
189
 
177
190
  def unify_entries(ents)
178
- h = {}
191
+ h = {} #: Hash[SearchResult::Record, SearchResult::Record]
179
192
  ents.each do |ent|
180
193
  if ent0 = h[ent]
181
194
  ent0.merge ent
@@ -188,6 +201,7 @@ $cm_comb_m += 1
188
201
 
189
202
  # Case-insensitive search. Optimized for constant search.
190
203
  def expand_ic(xs, pattern)
204
+ # @type self: MethodDatabase | FunctionDatabase
191
205
  re1 = /\A#{Regexp.quote(pattern)}/i
192
206
  result1 = xs.select {|x| x.name_match?(re1) }
193
207
  return [] if result1.empty?
@@ -200,6 +214,7 @@ $cm_comb_m += 1
200
214
  end
201
215
 
202
216
  def expand(xs, pattern)
217
+ # @type self: MethodDatabase
203
218
  re1 = /\A#{Regexp.quote(pattern)}/i
204
219
  result1 = xs.select {|x| x.name_match?(re1) }
205
220
  return [] if result1.empty?
@@ -216,12 +231,14 @@ $cm_comb_m += 1
216
231
 
217
232
  # list up all matched items (without squeezing)
218
233
  def expand_name_wide(names, pattern)
234
+ # @type self: MethodDatabase
219
235
  re1 = /\A#{Regexp.quote(pattern)}/i
220
236
  names.grep(re1)
221
237
  end
222
238
 
223
239
  # list up matched items (with squeezing)
224
240
  def expand_name_narrow(names, pattern, suffixes = nil)
241
+ # @type self: MethodDatabase
225
242
  re1 = /\A#{Regexp.quote(pattern)}/i
226
243
  result1 = names.grep(re1)
227
244
  return [] if result1.empty?
@@ -231,6 +248,7 @@ $cm_comb_m += 1
231
248
 
232
249
  # squeeze result of #expand_name_wide
233
250
  def squeeze_names(result1, pattern, suffixes = nil)
251
+ # @type self: MethodDatabase
234
252
  regexps =
235
253
  [
236
254
  /\A#{Regexp.quote(pattern)}.*#{suffix_pattern(suffixes)}\z/i,
@@ -257,6 +275,7 @@ $cm_comb_m += 1
257
275
  #
258
276
 
259
277
  def save_completion_index
278
+ # @type self: MethodDatabase
260
279
  save_class_index
261
280
  save_method_index
262
281
  save_method_index_narrow
@@ -267,9 +286,9 @@ $cm_comb_m += 1
267
286
  end
268
287
 
269
288
  def intern_table
270
- @intern_table ||=
289
+ @intern_table ||=
271
290
  begin
272
- h = {}
291
+ h = {} #: Hash[String, String]
273
292
  classnametable().each do |id, names|
274
293
  names.each do |n|
275
294
  h[n] = id
@@ -280,6 +299,7 @@ $cm_comb_m += 1
280
299
  end
281
300
 
282
301
  def save_class_index
302
+ # @type self: MethodDatabase
283
303
  atomic_write_open('class/=index') {|f|
284
304
  classes().each do |c|
285
305
  #f.puts "#{c.id}\t#{c.names.join(' ')}" # FIXME: support class alias
@@ -289,11 +309,13 @@ $cm_comb_m += 1
289
309
  end
290
310
 
291
311
  def classnametable
312
+ # @type self: MethodDatabase
292
313
  @classnametable ||=
293
314
  begin
294
- h = {}
315
+ h = {} #: Hash[String, Array[String]]
295
316
  foreach_line('class/=index') do |line|
296
317
  id, *names = line.split
318
+ id || raise
297
319
  h[id] = names
298
320
  end
299
321
  h
@@ -303,9 +325,10 @@ $cm_comb_m += 1
303
325
  end
304
326
 
305
327
  def save_method_index_narrow
328
+ # @type self: MethodDatabase
306
329
  index =
307
330
  begin
308
- h = {}
331
+ h = {} #: Hash[String, Array[String]]
309
332
  classes().each do |c|
310
333
  c.entries.each do |m|
311
334
  ref = c.id + m.typemark
@@ -324,11 +347,13 @@ $cm_comb_m += 1
324
347
  end
325
348
 
326
349
  def method_index_small
350
+ # @type self: MethodDatabase
327
351
  @method_index_small ||=
328
352
  begin
329
- h = {}
353
+ h = {} #: Hash[String, Array[String]]
330
354
  foreach_line('method/=sindex') do |line|
331
355
  name, *crefs = line.split(nil)
356
+ name || raise
332
357
  h[name] = crefs
333
358
  end
334
359
  h
@@ -341,13 +366,16 @@ $cm_comb_m += 1
341
366
  end
342
367
 
343
368
  def save_method_index
369
+ # @type self: MethodDatabase
344
370
  index =
345
371
  begin
346
- h = {}
372
+ h = {} #: Hash[String, Array[String]]
347
373
  classes().each do |c|
348
374
  [ ['#', c._imap.keys],
349
375
  ['.', c._smap.keys],
350
376
  [':', c._cmap.keys] ].each do |t, names|
377
+ # @type var t: String
378
+ # @type var names: Array[String]
351
379
  ref = c.id + t
352
380
  names.each do |name|
353
381
  (h[name] ||= []).push ref
@@ -370,24 +398,27 @@ $cm_comb_m += 1
370
398
  # includes class aliases, includes inherited methods
371
399
  def mname2crefs_wide(name)
372
400
  tbl = classnametable()
373
- mname2crefs_0(name).map {|ref|
374
- tbl[ref.chop].map {|c| c + ref[-1,1] }
401
+ (mname2crefs_0(name) || raise).map {|ref|
402
+ tbl[ref.chop].map {|c| c + ref[-1,1] } # steep:ignore
375
403
  }.flatten
376
404
  end
377
405
 
378
406
  def mname2crefs_0(name)
379
- crefs = (@method_index ||= {})[name]
407
+ crefs = (@method_index ||= {})[name] # steep:ignore
380
408
  return crefs if crefs
381
409
  crefsstr = method_index_0()[name] or return nil
382
410
  @method_index[name] = crefsstr.split(nil)
383
411
  end
384
412
 
385
413
  def method_index_0
414
+ # @type self: MethodDatabase
386
415
  @method_index_0 ||=
387
416
  begin
388
- h = {}
417
+ h = {} #: Hash[String, String]
389
418
  foreach_line('method/=index') do |line|
390
419
  name, cnames = line.split(nil, 2)
420
+ name || raise
421
+ cnames.is_a?(String) || raise
391
422
  h[name] = cnames
392
423
  end
393
424
  h
@@ -466,7 +497,7 @@ $cm_comb_m += 1
466
497
  begin
467
498
  spec = @specs.first
468
499
  c = @db.fetch_class(spec.klass)
469
- MethodSpec.parse(c.match_entry(spec.type, spec.method))
500
+ MethodSpec.parse(c.match_entry(spec.type, spec.method) || raise)
470
501
  end
471
502
  end
472
503
 
@@ -475,7 +506,7 @@ $cm_comb_m += 1
475
506
  end
476
507
 
477
508
  def entry
478
- @entry ||= @db.get_method(origin())
509
+ @entry ||= @db.get_method(origin()) || raise
479
510
  end
480
511
 
481
512
  def name
@@ -483,7 +514,8 @@ $cm_comb_m += 1
483
514
  end
484
515
 
485
516
  def names
486
- @specs.map {|spec| spec.display_name }
517
+ version = @db && @db.properties["version"]
518
+ @specs.map {|spec| spec.display_name(version) }
487
519
  end
488
520
 
489
521
  def class_name
@@ -521,9 +553,9 @@ $cm_comb_m += 1
521
553
  def owned_method?
522
554
  @specs.any? {|spec| spec.klass == origin().klass }
523
555
  end
524
-
556
+
525
557
  def method_of_alias_class?
526
- @entry.klass.aliases.any?{|aliasclass| aliasclass.name?(class_name())}
558
+ entry.klass.aliases.any?{|aliasclass| aliasclass.name?(class_name())}
527
559
  end
528
560
 
529
561
  def inherited_method?
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/crossrubyutils.rb
3
4
  #
@@ -13,7 +14,8 @@ module BitClust
13
14
  private
14
15
 
15
16
  def print_crossruby_table(&block)
16
- print_table(*build_crossruby_table(&block))
17
+ vers, table = build_crossruby_table(&block)
18
+ print_table(vers, table)
17
19
  end
18
20
 
19
21
  def print_table(vers, table)
@@ -43,7 +45,7 @@ module BitClust
43
45
  end
44
46
 
45
47
  def get_ruby(version)
46
- forall_ruby(ENV['PATH']) do |ruby, |
48
+ forall_ruby(ENV.fetch('PATH')) do |ruby, |
47
49
  v = `#{ruby} -e 'print RUBY_VERSION'`
48
50
  patch = `#{ruby} -e 'print RUBY_PATCHLEVEL if defined? RUBY_PATCHLEVEL'`
49
51
  if version == v or ( version == v.succ and patch == '5000')
@@ -57,9 +59,9 @@ module BitClust
57
59
  ENV.delete 'RUBYOPT'
58
60
  ENV.delete 'RUBYLIB'
59
61
  ENV.delete 'GEM_HOME'
60
- vers = []
61
- table = {}
62
- forall_ruby(ENV['PATH']) do |ruby, ver|
62
+ vers = [] #: Array[String]
63
+ table = {} #: table_type
64
+ forall_ruby(ENV.fetch('PATH')) do |ruby, ver|
63
65
  puts "#{version_id(ver)}: #{ver}" if @verbose
64
66
  vers.push ver
65
67
  yield(ruby).each do |c|
@@ -70,11 +72,13 @@ module BitClust
70
72
  end
71
73
 
72
74
  def forall_ruby(path, &block)
75
+ # steep:ignore:start
73
76
  rubys(path)\
74
77
  .map {|ruby| [ruby, `#{ruby} --version`] }\
75
78
  .reject {|ruby, verstr| `which #{ruby}`.include?('@') }\
76
79
  .sort_by {|ruby, verstr| verstr }\
77
80
  .each(&block)
81
+ # steep:ignore:end
78
82
  end
79
83
 
80
84
  def rubys(path)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/database.rb
3
4
  #
@@ -27,9 +28,10 @@ module BitClust
27
28
  def Database.connect(uri)
28
29
  case uri.scheme
29
30
  when 'file'
30
- new(uri.path)
31
+ new(uri.path || raise)
31
32
  when 'druby'
32
- DRbObject.new_with_uri(uri.to_s)
33
+ require 'drb'
34
+ _ = DRbObject.new_with_uri(uri.to_s) #: ::BitClust::Database
33
35
  else
34
36
  raise InvalidScheme, "unknown database scheme: #{uri.scheme}"
35
37
  end
@@ -61,14 +63,32 @@ module BitClust
61
63
  yield
62
64
  return if dummy?
63
65
  if @properties_dirty
64
- save_properties 'properties', @properties
66
+ save_properties 'properties', (@properties || raise)
65
67
  @properties_dirty = false
66
68
  end
67
- commit if dirty?
69
+ if dirty?
70
+ commit
71
+ # 更新完了の合図として properties の mtime を進める(bitclust#275)。
72
+ # server の自動リロード(ReloadableRequestHandler)は properties の
73
+ # mtime で新鮮さを判定するため、init 直後〜update 完了前の途中状態を
74
+ # 読んでしまったプロセスも、ここで mtime が進むことで次のリクエスト
75
+ # から完成した DB を読み直して収束できる
76
+ touch_properties
77
+ end
68
78
  ensure
69
79
  @in_transaction = false
70
80
  end
71
81
 
82
+ # properties の内容は変えず mtime だけ現在時刻に進める。
83
+ # ファイルが無い場合(異常系)は何もしない
84
+ def touch_properties
85
+ path = realpath('properties')
86
+ now = Time.now
87
+ File.utime(now, now, path)
88
+ rescue Errno::ENOENT
89
+ end
90
+ private :touch_properties
91
+
72
92
  # abstract dirty?
73
93
  # abstract clear_dirty
74
94
  # abstract commit
@@ -99,12 +119,12 @@ module BitClust
99
119
  end
100
120
 
101
121
  def propget(key)
102
- properties()[key]
122
+ properties()[key] # steep:ignore
103
123
  end
104
124
 
105
125
  def propset(key, value)
106
126
  check_transaction
107
- properties()[key] = value
127
+ properties()[key] = value # steep:ignore
108
128
  @properties_dirty = true
109
129
  end
110
130
 
@@ -125,6 +145,7 @@ module BitClust
125
145
  Dir.entries(realpath(rel))\
126
146
  .reject {|ent| /\A[\.=]/ =~ ent }\
127
147
  .map {|ent| decodeid(ent) }
148
+ .sort
128
149
  rescue Errno::ENOENT
129
150
  return []
130
151
  end
@@ -134,12 +155,12 @@ module BitClust
134
155
  end
135
156
 
136
157
  def load_properties(rel)
137
- h = {}
158
+ h = {} #: Hash[String, String]
138
159
  fopen(realpath(rel), 'r:UTF-8') {|f|
139
160
  while line = f.gets
140
161
  k, v = line.strip.split('=', 2)
141
162
  break unless k
142
- h[k] = v
163
+ h[k] = v || raise
143
164
  end
144
165
  h['source'] = f.read
145
166
  }
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bitclust/rrd_to_markdown'
4
+
5
+ module BitClust
6
+ # refm/doc(散文ページ)の Markdown 変換。
7
+ #
8
+ # doc ページにはクロスファイル情報(library 所属等)が無いため、
9
+ # オーケストレータは不要で、reduce(正規化)+ 単一ファイル変換のみ。
10
+ # タイトルは H1 が担い、front matter は使わない。
11
+ #
12
+ # reduce は意味を変えない表記ゆれを md→rd の再生成形に合わせる正規化と、
13
+ # クロスツリー include(api 断片の transclude)の manual レイアウトへの
14
+ # 書き換えを行う。md→rd 変換は reduce の結果を復元する(検証の期待値)。
15
+ module DocConverter
16
+ module_function
17
+
18
+ def reduce(rrd)
19
+ RRDToMarkdown.normalize_dlist_colon_spacing(rrd.lines.map { |line|
20
+ case line
21
+ when /\A\#@samplecode[ \t]+\n\z/
22
+ "\#@samplecode\n" # ラベル無しの末尾スペース
23
+ when %r{\A//\}[ \t]+\n\z}
24
+ "//}\n"
25
+ when /\A:\s{2,}(.*)/m
26
+ ": #{$1}" # 定義リスト term の余分なスペース
27
+ when /\A(={1,4}\[a:[^\]]+\])\s{2,}(.*)/m
28
+ "#{$1} #{$2}" # アンカー見出しの余分なスペース
29
+ when /\A\t+/
30
+ line.sub(/\A\t+/) { ' ' * ($& || raise).length } # 行頭タブ(doc の散文1行のみ)
31
+ when /\A\#@include\((?:\.\.\/)+api\/src\//
32
+ # 旧レイアウト ../api/src/X → 新レイアウト ../api/X
33
+ # (manual/ 配下では src 階層が無い。ブリッジが逆変換する)
34
+ line.sub(%r{((?:\.\./)+)api/src/}, '\1api/')
35
+ else
36
+ line
37
+ end
38
+ }.join)
39
+ end
40
+
41
+ def convert(rrd)
42
+ RRDToMarkdown.convert(reduce(rrd))
43
+ end
44
+
45
+ # 変換対象ファイルの一覧(doc ルート相対)。
46
+ # 旧パイプライン(copy_doc)は **/*.rd だけをページとして読むため、
47
+ # .rd 以外は doc 内 include から参照される断片のみを対象にし、
48
+ # 参照されない死にファイル(news/1.8.0.rd-2 等)は凍結側に残す
49
+ def files(doc_root)
50
+ all = Dir.glob('**/*', base: doc_root)
51
+ .select { |f| File.file?(File.join(doc_root, f)) }.sort
52
+ pages = all.select { |f| f.end_with?('.rd') }
53
+ referenced = pages.flat_map { |f|
54
+ base = File.dirname(f)
55
+ File.read(File.join(doc_root, f))
56
+ .scan(/^\#@include\((?!(?:\.\.\/)+api\/)(.*?)\)/)
57
+ .map { |t| File.expand_path(base == '.' ? (t[0] || raise) : File.join(base, t[0] || raise), '/')
58
+ .delete_prefix('/') }
59
+ }
60
+ (pages + (all & referenced)).sort
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # bitclust/docentry.rb
3
4
  #
@@ -83,7 +84,7 @@ module BitClust
83
84
  end
84
85
 
85
86
  def description
86
- source.split(/\n\n/, 2)[0].strip
87
+ description_text(source.split(/\n\n/, 2)[0].strip)
87
88
  end
88
89
  end
89
90
  end