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
|
@@ -134,7 +134,7 @@ EOS
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
def method_url(spec)
|
|
137
|
-
cname, tmark, mname =
|
|
137
|
+
cname, tmark, mname = split_method_spec(spec)
|
|
138
138
|
"/method/#{encodename_fs(cname)}/#{typemark2char(tmark)}/#{encodename_fs(mname)}.html"
|
|
139
139
|
end
|
|
140
140
|
|
|
@@ -170,6 +170,7 @@ EOS
|
|
|
170
170
|
manager = ScreenManager.new(@manager_config)
|
|
171
171
|
@html_files = []
|
|
172
172
|
db.transaction do
|
|
173
|
+
# @type var methods: Hash[String, Array[MethodEntry]]
|
|
173
174
|
methods = {}
|
|
174
175
|
db.methods.each do |entry|
|
|
175
176
|
method_name = entry.klass.name + entry.typemark + entry.name
|
|
@@ -184,6 +185,7 @@ EOS
|
|
|
184
185
|
e = c.is_a?(Array) ? c.sort.first : c
|
|
185
186
|
case e.type_id
|
|
186
187
|
when :library
|
|
188
|
+
# @type var e: LibraryEntry
|
|
187
189
|
content = Sitemap::Content.new(e.name.to_s, filename)
|
|
188
190
|
if e.name.to_s != '_builtin'
|
|
189
191
|
@sitemap[:library][1] << content
|
|
@@ -191,6 +193,7 @@ EOS
|
|
|
191
193
|
end
|
|
192
194
|
@index_contents << Sitemap::Content.new(e.name.to_s, filename)
|
|
193
195
|
when :class
|
|
196
|
+
# @type var e: ClassEntry
|
|
194
197
|
content = Sitemap::Content.new(e.name.to_s, filename)
|
|
195
198
|
if e.library.name.to_s == '_builtin'
|
|
196
199
|
@sitemap[:library][0] << content
|
|
@@ -199,12 +202,15 @@ EOS
|
|
|
199
202
|
end
|
|
200
203
|
@index_contents << Sitemap::Content.new("#{e.name} (#{e.library.name})", filename)
|
|
201
204
|
when :method
|
|
205
|
+
# @type var e: MethodEntry
|
|
202
206
|
e.names.each do |e_name|
|
|
203
207
|
name = e.typename == :special_variable ? "$#{e_name}" : e_name
|
|
204
208
|
@index_contents <<
|
|
205
209
|
Sitemap::Content.new("#{name} (#{e.library.name} - #{e.klass.name})", filename)
|
|
210
|
+
# bitclust#250: CHM の索引(.hhk)に出る表示ラベル。4.0 以降の
|
|
211
|
+
# ドキュメントでは module function を "?." で表示する
|
|
206
212
|
@index_contents <<
|
|
207
|
-
Sitemap::Content.new("#{e.klass.name}#{e.
|
|
213
|
+
Sitemap::Content.new("#{e.klass.name}#{e.display_typemark}#{name} (#{e.library.name})", filename)
|
|
208
214
|
end
|
|
209
215
|
end
|
|
210
216
|
pb.title = align_progress_bar_title(e.name)
|
|
@@ -219,7 +225,7 @@ EOS
|
|
|
219
225
|
create_file(@outputdir + 'library/index.html', manager.library_index_screen(db.libraries.sort, {:database => db}).body)
|
|
220
226
|
create_file(@outputdir + 'class/index.html', manager.class_index_screen(db.classes.sort, {:database => db}).body)
|
|
221
227
|
FileUtils.cp(@manager_config[:themedir] + @manager_config[:css_url],
|
|
222
|
-
@outputdir.to_s,
|
|
228
|
+
@outputdir.to_s, verbose: true, preserve: true)
|
|
223
229
|
end
|
|
224
230
|
|
|
225
231
|
private
|
|
@@ -243,15 +249,17 @@ EOS
|
|
|
243
249
|
"\u0308" => "\u2025",
|
|
244
250
|
"\u2014" => "\u2015",
|
|
245
251
|
"\u2212" => "\uff0d",
|
|
246
|
-
"\u301c" => "\uff5e" }
|
|
252
|
+
"\u301c" => "\uff5e" }
|
|
247
253
|
|
|
248
254
|
def create_html_file(entry, manager, outputdir, db)
|
|
249
255
|
html = manager.entry_screen(entry, {:database => db}).body
|
|
250
256
|
e = entry.is_a?(Array) ? entry.sort.first : entry
|
|
251
257
|
path = case e.type_id
|
|
252
258
|
when :library, :class, :doc
|
|
253
|
-
|
|
259
|
+
# @type var e: LibraryEntry | ClassEntry | DocEntry
|
|
260
|
+
outputdir + e.type_id.to_s + (NameUtils.encodename_fs(e.name) + '.html')
|
|
254
261
|
when :method
|
|
262
|
+
# @type var e: MethodEntry
|
|
255
263
|
outputdir + e.type_id.to_s + NameUtils.encodename_fs(e.klass.name) +
|
|
256
264
|
e.typechar + (NameUtils.encodename_fs(e.name) + '.html')
|
|
257
265
|
else
|
|
@@ -261,7 +269,7 @@ EOS
|
|
|
261
269
|
|
|
262
270
|
begin
|
|
263
271
|
new_html = html.gsub(/charset=utf-8/i, 'charset=Windows-31J').
|
|
264
|
-
encode('windows-31j',
|
|
272
|
+
encode('windows-31j', fallback: FIX_UNDEF)
|
|
265
273
|
mode = 'w:windows-31j'
|
|
266
274
|
rescue
|
|
267
275
|
new_html = html # write file as it is, utf-8
|
|
@@ -277,7 +285,7 @@ EOS
|
|
|
277
285
|
$stderr.print("creating #{path} ...")
|
|
278
286
|
str = ERB.new(skel).result(binding).
|
|
279
287
|
gsub(/charset=utf-8/i, 'charset=Windows-31J').
|
|
280
|
-
encode('windows-31j',
|
|
288
|
+
encode('windows-31j', fallback: FIX_UNDEF)
|
|
281
289
|
path.open('w:windows-31j') do |f|
|
|
282
290
|
f.write(str)
|
|
283
291
|
end
|
|
@@ -27,6 +27,11 @@ module BitClust
|
|
|
27
27
|
option_error('wrong number of arguments') unless argv.size == 1
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# システムの ruby を調べるだけで DB を使わない
|
|
31
|
+
def needs_database?
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
|
|
30
35
|
def exec(argv, options)
|
|
31
36
|
lib = argv[0]
|
|
32
37
|
print_crossruby_table {|ruby| defined_classes(ruby, lib, @rejects) }
|
|
@@ -16,13 +16,13 @@ module BitClust
|
|
|
16
16
|
@target = nil
|
|
17
17
|
@templatedir = srcdir_root + "data/bitclust/template.offline"
|
|
18
18
|
@baseurl = "file://" + srcdir_root.to_s
|
|
19
|
-
@version =
|
|
19
|
+
@version = RUBY_VERSION
|
|
20
20
|
@parser.banner = "Usage: #{File.basename($0, '.*')} htmlfile [options] rdfile"
|
|
21
21
|
@parser.on('--target=NAME', 'Compile NAME to HTML.') {|name|
|
|
22
22
|
@target = name
|
|
23
23
|
}
|
|
24
|
-
@parser.on('--force', '-f', 'Force to use rd_file template.') {|
|
|
25
|
-
@rd_file =
|
|
24
|
+
@parser.on('--[no-]force', '-f', 'Force to use rd_file template.') {|bool|
|
|
25
|
+
@rd_file = bool
|
|
26
26
|
}
|
|
27
27
|
@parser.on('--ruby_version=VER', '--ruby=VER', 'Set Ruby version') {|version|
|
|
28
28
|
@version = version
|
|
@@ -35,6 +35,11 @@ module BitClust
|
|
|
35
35
|
}
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
# DB は与えられれば使うが必須ではない (--database は任意)
|
|
39
|
+
def needs_database?
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
|
|
38
43
|
def exec(argv, options)
|
|
39
44
|
db = MethodDatabase.dummy({'version' => @version})
|
|
40
45
|
if options[:prefix]
|
|
@@ -42,7 +47,10 @@ module BitClust
|
|
|
42
47
|
end
|
|
43
48
|
@capi = options[:capi]
|
|
44
49
|
target_file = argv[0]
|
|
45
|
-
|
|
50
|
+
if /refm\/doc\// =~ target_file
|
|
51
|
+
@rd_file = true if @rd_file.nil?
|
|
52
|
+
end
|
|
53
|
+
options = { 'version' => @version } #: Database::database_properties
|
|
46
54
|
manager = ScreenManager.new(:templatedir => @templatedir,
|
|
47
55
|
:base_url => @baseurl,
|
|
48
56
|
:cgi_url => @baseurl,
|
|
@@ -59,11 +67,11 @@ module BitClust
|
|
|
59
67
|
lib = RRDParser.parse_stdlib_file(target_file, options)
|
|
60
68
|
end
|
|
61
69
|
entry = @target ? lookup(lib, @target) : lib
|
|
62
|
-
puts manager.entry_screen(entry, { :database => db }).body
|
|
70
|
+
puts manager.entry_screen(entry, { :database => db, :target_version => @version }).body
|
|
63
71
|
return
|
|
64
72
|
rescue ParseError => ex
|
|
65
73
|
$stderr.puts ex.message
|
|
66
|
-
$stderr.puts ex.backtrace[0], ex.backtrace[1..-1]
|
|
74
|
+
$stderr.puts ex.backtrace[0], ex.backtrace[1..-1]&.map{|s| "\tfrom " + s}
|
|
67
75
|
end
|
|
68
76
|
end
|
|
69
77
|
|
|
@@ -83,8 +91,12 @@ module BitClust
|
|
|
83
91
|
def lookup(lib, key)
|
|
84
92
|
case
|
|
85
93
|
when @capi && NameUtils.functionname?(key)
|
|
86
|
-
|
|
94
|
+
# @type var lib: Array[FunctionEntry]
|
|
95
|
+
lib.is_a?(Array) or raise
|
|
96
|
+
lib.find {|func| func.name == key} or raise
|
|
87
97
|
when NameUtils.method_spec?(key)
|
|
98
|
+
# @type var lib: LibraryEntry
|
|
99
|
+
lib.is_a?(LibraryEntry) or raise
|
|
88
100
|
spec = MethodSpec.parse(key)
|
|
89
101
|
if spec.constant?
|
|
90
102
|
begin
|
|
@@ -96,6 +108,8 @@ module BitClust
|
|
|
96
108
|
lib.fetch_methods(spec)
|
|
97
109
|
end
|
|
98
110
|
when NameUtils.classname?(key)
|
|
111
|
+
# @type var lib: LibraryEntry
|
|
112
|
+
lib.is_a?(LibraryEntry) or raise
|
|
99
113
|
lib.fetch_class(key)
|
|
100
114
|
else
|
|
101
115
|
raise InvalidKey, "wrong search key: #{key.inspect}"
|
|
@@ -20,12 +20,15 @@ module BitClust
|
|
|
20
20
|
STANDARD_PROPERTIES = %w( encoding version )
|
|
21
21
|
|
|
22
22
|
def exec(argv, options)
|
|
23
|
-
prefix = options[:prefix]
|
|
23
|
+
prefix = options[:prefix] || raise
|
|
24
24
|
db = MethodDatabase.new(prefix)
|
|
25
25
|
db.init
|
|
26
26
|
db.transaction {
|
|
27
27
|
argv.each do |kv|
|
|
28
28
|
k, v = kv.split('=', 2)
|
|
29
|
+
if k.nil? || v.nil?
|
|
30
|
+
raise "argument must be KEY=VALUE, but #{kv.inspect}"
|
|
31
|
+
end
|
|
29
32
|
db.propset k, v
|
|
30
33
|
end
|
|
31
34
|
}
|
|
@@ -41,21 +41,29 @@ module BitClust
|
|
|
41
41
|
super
|
|
42
42
|
case @mode
|
|
43
43
|
when :library
|
|
44
|
-
|
|
44
|
+
db = @db
|
|
45
|
+
db.is_a?(MethodDatabase) or raise "invalid database given. Use without --capi option"
|
|
46
|
+
db.libraries.map {|lib| lib.name }.sort.each do |name|
|
|
45
47
|
puts name
|
|
46
48
|
end
|
|
47
49
|
when :class
|
|
48
|
-
|
|
50
|
+
db = @db
|
|
51
|
+
db.is_a?(MethodDatabase) or raise "invalid database given. Use without --capi option"
|
|
52
|
+
db.classes.map {|c| c.name }.sort.each do |name|
|
|
49
53
|
puts name
|
|
50
54
|
end
|
|
51
55
|
when :method
|
|
52
|
-
|
|
56
|
+
db = @db
|
|
57
|
+
db.is_a?(MethodDatabase) or raise "invalid database given. Use without --capi option"
|
|
58
|
+
db.classes.sort_by {|c| c.name }.each do |c|
|
|
53
59
|
c.entries.sort_by {|m| m.id }.each do |m|
|
|
54
60
|
puts m.label
|
|
55
61
|
end
|
|
56
62
|
end
|
|
57
63
|
when :function
|
|
58
|
-
|
|
64
|
+
db = @db
|
|
65
|
+
db.is_a?(FunctionDatabase) or raise "invalid database given. Use with --capi option"
|
|
66
|
+
db.functions.sort_by {|f| f.name }.each do |f|
|
|
59
67
|
puts f.name
|
|
60
68
|
end
|
|
61
69
|
else
|
|
@@ -51,19 +51,23 @@ module BitClust
|
|
|
51
51
|
|
|
52
52
|
def exec(argv, options)
|
|
53
53
|
super
|
|
54
|
-
entry = fetch_entry(@db, @type, @key)
|
|
55
|
-
puts fill_template(get_template(@type, @format), entry)
|
|
54
|
+
entry = fetch_entry(@db, @type, @key || raise)
|
|
55
|
+
puts fill_template(get_template(@type || raise, @format || raise), entry)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def fetch_entry(db, type, key)
|
|
59
59
|
case type
|
|
60
60
|
when :library
|
|
61
|
+
# @type var db: MethodDatabase
|
|
61
62
|
db.fetch_library(key)
|
|
62
63
|
when :class
|
|
64
|
+
# @type var db: MethodDatabase
|
|
63
65
|
db.fetch_class(key)
|
|
64
66
|
when :method
|
|
67
|
+
# @type var db: MethodDatabase
|
|
65
68
|
db.fetch_method(MethodSpec.parse(key))
|
|
66
69
|
when :function
|
|
70
|
+
# @type var db: FunctionDatabase
|
|
67
71
|
db.fetch_function(key)
|
|
68
72
|
else
|
|
69
73
|
raise "must not happen: #{type.inspect}"
|
|
@@ -96,7 +100,7 @@ module BitClust
|
|
|
96
100
|
<dt>classes</dt><dd><%= entry.classes.map {|c| c.name }.sort.join(', ') %></dd>
|
|
97
101
|
<dt>methods</dt><dd><%= entry.methods.map {|m| m.name }.sort.join(', ') %></dd>
|
|
98
102
|
</dl>
|
|
99
|
-
<%= compile_rd(entry
|
|
103
|
+
<%= compile_rd(entry) %>
|
|
100
104
|
End
|
|
101
105
|
},
|
|
102
106
|
:class => {
|
|
@@ -119,7 +123,7 @@ module BitClust
|
|
|
119
123
|
<dt>singleton_methods</dt><dd><%= entry.singleton_methods.map {|m| m.name }.sort.join(', ') %></dd>
|
|
120
124
|
<dt>instance_methods</dt><dd><%= entry.instance_methods.map {|m| m.name }.sort.join(', ') %></dd>
|
|
121
125
|
</dl>
|
|
122
|
-
<%= compile_rd(entry
|
|
126
|
+
<%= compile_rd(entry) %>
|
|
123
127
|
End
|
|
124
128
|
},
|
|
125
129
|
:method => {
|
|
@@ -142,7 +146,7 @@ module BitClust
|
|
|
142
146
|
<dt>kind</dt><dd><%= entry.kind %></dd>
|
|
143
147
|
<dt>library</dt><dd><%= entry.library.name %></dd>
|
|
144
148
|
</dl>
|
|
145
|
-
<%= compile_rd(entry
|
|
149
|
+
<%= compile_rd(entry) %>
|
|
146
150
|
End
|
|
147
151
|
},
|
|
148
152
|
:function => {
|
|
@@ -159,16 +163,31 @@ module BitClust
|
|
|
159
163
|
<dt>header</dt><dd><%= entry.header %></dd>
|
|
160
164
|
<dt>filename</dt><dd><%= entry.filename %></dd>
|
|
161
165
|
</dl>
|
|
162
|
-
<%= compile_rd(entry
|
|
166
|
+
<%= compile_rd(entry) %>
|
|
163
167
|
End
|
|
164
168
|
}
|
|
165
169
|
}
|
|
166
170
|
|
|
167
|
-
def compile_rd(
|
|
171
|
+
def compile_rd(entry)
|
|
168
172
|
umap = URLMapper.new(:base_url => 'http://example.com',
|
|
169
173
|
:cgi_url => 'http://example.com/view')
|
|
170
|
-
|
|
171
|
-
|
|
174
|
+
if @db.properties['source_format'] == 'markdown'
|
|
175
|
+
# md ソースの DB は screen.rb と同じく MDCompiler(GFM)で描画する
|
|
176
|
+
Kernel.require 'bitclust/mdcompiler'
|
|
177
|
+
compiler = MDCompiler.new(umap, 2, { :gfm => true, :database => @db })
|
|
178
|
+
else
|
|
179
|
+
compiler = RDCompiler.new(umap, 2, { :database => @db })
|
|
180
|
+
end
|
|
181
|
+
# シグネチャ行の描画(permalink の id 等)はエントリ文脈を要求する
|
|
182
|
+
# ので、compile ではなくエントリ種別ごとの compile_* を使う
|
|
183
|
+
case entry
|
|
184
|
+
when MethodEntry
|
|
185
|
+
compiler.compile_method(entry)
|
|
186
|
+
when FunctionEntry
|
|
187
|
+
compiler.compile_function(entry)
|
|
188
|
+
else
|
|
189
|
+
compiler.compile(entry.source)
|
|
190
|
+
end
|
|
172
191
|
end
|
|
173
192
|
end
|
|
174
193
|
end
|
|
@@ -46,6 +46,11 @@ module BitClust
|
|
|
46
46
|
option_error("wrong number of arguments") unless argv.size == 1
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
# システムの ruby とリファレンスファイルを比較するだけで DB を使わない
|
|
50
|
+
def needs_database?
|
|
51
|
+
false
|
|
52
|
+
end
|
|
53
|
+
|
|
49
54
|
def exec(argv, options)
|
|
50
55
|
classname = argv[0]
|
|
51
56
|
case @mode
|
|
@@ -60,6 +65,7 @@ module BitClust
|
|
|
60
65
|
c = lib.fetch_class(classname)
|
|
61
66
|
list0 = lib.classes.find_all{|c0| /\A#{classname}\b/o =~ c0.name }
|
|
62
67
|
list0 = c.entries + list0
|
|
68
|
+
# @type var list: Array[String]
|
|
63
69
|
list = list0.map {|ent| ent.labels.map {|n| expand_mf(n) } }.flatten
|
|
64
70
|
if @content
|
|
65
71
|
ri = @ri_path ? RiDatabase.open(@ri_path, nil) : RiDatabase.open_system_db
|
|
@@ -72,7 +78,7 @@ module BitClust
|
|
|
72
78
|
puts fmt.method_info(mthd.entry)
|
|
73
79
|
else
|
|
74
80
|
name = name.sub(/\A\w+#/, '')
|
|
75
|
-
puts "--- #{name}\n
|
|
81
|
+
puts "--- #{name}\n#%todo\n\n"
|
|
76
82
|
end
|
|
77
83
|
end
|
|
78
84
|
else
|
|
@@ -84,7 +90,7 @@ module BitClust
|
|
|
84
90
|
end
|
|
85
91
|
end
|
|
86
92
|
else
|
|
87
|
-
raise "must not happen: #{mode.inspect}"
|
|
93
|
+
raise "must not happen: #{@mode.inspect}"
|
|
88
94
|
end
|
|
89
95
|
end
|
|
90
96
|
|
|
@@ -104,6 +110,8 @@ module BitClust
|
|
|
104
110
|
|
|
105
111
|
def m_order(m)
|
|
106
112
|
m, t = *m.reverse.split(/(\#|\.|::)/, 2)
|
|
113
|
+
m or raise
|
|
114
|
+
t or raise
|
|
107
115
|
[ORDER[t] || 0, m.reverse]
|
|
108
116
|
end
|
|
109
117
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# bitclust/subcommands/methodsince_command.rb
|
|
4
|
+
#
|
|
5
|
+
# Fills per-name since/until into method entries by scanning a version
|
|
6
|
+
# ladder of databases:
|
|
7
|
+
#
|
|
8
|
+
# bitclust methodsince --update=db-3.4 db-1.8.7 db-1.9.3 ... db-3.3 db-3.4
|
|
9
|
+
#
|
|
10
|
+
# Every positional argument and every --update path together form the
|
|
11
|
+
# version ladder used to compute presence; --update paths are additionally
|
|
12
|
+
# written back to (see bitclust/method_since_calculator.rb, bitclust#132 P2).
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
require 'bitclust'
|
|
16
|
+
require 'bitclust/subcommand'
|
|
17
|
+
require 'bitclust/method_since_calculator'
|
|
18
|
+
require 'tmpdir'
|
|
19
|
+
require 'fileutils'
|
|
20
|
+
|
|
21
|
+
module BitClust
|
|
22
|
+
module Subcommands
|
|
23
|
+
class MethodsinceCommand < Subcommand
|
|
24
|
+
def initialize
|
|
25
|
+
super
|
|
26
|
+
@updates = []
|
|
27
|
+
@dry_run = false
|
|
28
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} methodsince [options] <dbpath>..."
|
|
29
|
+
@parser.on('--update=PATH', 'Writable target database to fill in-place (repeatable).') {|path|
|
|
30
|
+
@updates.push path
|
|
31
|
+
}
|
|
32
|
+
@parser.on('--dry-run', 'Compute and print stats without saving.') {
|
|
33
|
+
@dry_run = true
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# DB パスは自前の引数(位置引数 + --update)で受けるので、
|
|
38
|
+
# グローバル --database は不要
|
|
39
|
+
def needs_database?
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def exec(argv, options)
|
|
44
|
+
error("no --update given (nothing to write to)") if @updates.empty?
|
|
45
|
+
|
|
46
|
+
ladder_paths = (argv + @updates).uniq {|path| File.expand_path(path) }
|
|
47
|
+
calculator = MethodSinceCalculator.new(ladder_paths.map {|path| MethodDatabase.new(path) })
|
|
48
|
+
calculator.scan
|
|
49
|
+
|
|
50
|
+
@updates.each do |path|
|
|
51
|
+
stats, version = @dry_run ? apply_dry_run(calculator, path) : apply_and_save(calculator, path)
|
|
52
|
+
puts "#{File.basename(path)} (version #{version}): " \
|
|
53
|
+
"entries_updated=#{stats[:entries_updated]} since_filled=#{stats[:since_filled]} " \
|
|
54
|
+
"until_filled=#{stats[:until_filled]} floor_skipped=#{stats[:floor_skipped]}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def apply_and_save(calculator, path)
|
|
61
|
+
target = MethodDatabase.new(path)
|
|
62
|
+
version = target.propget('version') or
|
|
63
|
+
error("#{path}: no version property (not a bitclust database?)")
|
|
64
|
+
[calculator.apply(target), version]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# --dry-run: 実際のデータベースには一切書き込まず、複製に対して
|
|
68
|
+
# apply した結果の統計だけを見せる
|
|
69
|
+
def apply_dry_run(calculator, path)
|
|
70
|
+
version = MethodDatabase.new(path).propget('version') or
|
|
71
|
+
error("#{path}: no version property (not a bitclust database?)")
|
|
72
|
+
Dir.mktmpdir do |tmp|
|
|
73
|
+
copy = File.join(tmp, 'db')
|
|
74
|
+
FileUtils.cp_r(path, copy)
|
|
75
|
+
[calculator.apply(MethodDatabase.new(copy)), version]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -49,7 +49,7 @@ module BitClust
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def exec(argv, options)
|
|
52
|
-
prefix = options[:prefix]
|
|
52
|
+
prefix = options[:prefix] || raise
|
|
53
53
|
db = MethodDatabase.new(prefix)
|
|
54
54
|
case @mode
|
|
55
55
|
when :list
|
|
@@ -62,6 +62,7 @@ module BitClust
|
|
|
62
62
|
end
|
|
63
63
|
when :set
|
|
64
64
|
key, val = *argv
|
|
65
|
+
key || raise; val || raise
|
|
65
66
|
db.transaction {
|
|
66
67
|
db.propset key, val
|
|
67
68
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# bitclust/subcommands/searchpage_command.rb
|
|
4
|
+
#
|
|
5
|
+
# Generates a standalone, cross-version, client-side search page from
|
|
6
|
+
# multiple version databases:
|
|
7
|
+
#
|
|
8
|
+
# bitclust searchpage --outputdir=DIR db-3.0 db-3.1 ... db-4.1
|
|
9
|
+
#
|
|
10
|
+
# The output (index.html + js/search_data.js + assets) is fully static and
|
|
11
|
+
# replaces the server-backed rurema-search app at docs.ruby-lang.org/ja/search/.
|
|
12
|
+
# Each database's version is read from its own properties, and the merged
|
|
13
|
+
# index tags every entry with the versions it appears in.
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
require 'pathname'
|
|
17
|
+
require 'fileutils'
|
|
18
|
+
require 'json'
|
|
19
|
+
require 'optparse'
|
|
20
|
+
|
|
21
|
+
require 'bitclust'
|
|
22
|
+
require 'bitclust/subcommand'
|
|
23
|
+
require 'bitclust/search_index_generator'
|
|
24
|
+
|
|
25
|
+
module BitClust
|
|
26
|
+
module Subcommands
|
|
27
|
+
class SearchpageCommand < Subcommand
|
|
28
|
+
# search_init.js is the in-page dropdown wiring used by statichtml
|
|
29
|
+
# layouts; this page ships its own wiring (search_page.js) instead.
|
|
30
|
+
VENDORED_JS_FILES = %w[
|
|
31
|
+
search_navigation.js search_ranker.js search_controller.js
|
|
32
|
+
].freeze
|
|
33
|
+
|
|
34
|
+
def initialize
|
|
35
|
+
super
|
|
36
|
+
@outputdir = nil
|
|
37
|
+
@themedir = srcdir_root + "theme/default"
|
|
38
|
+
@templatedir = srcdir_root + "data/bitclust/searchpage"
|
|
39
|
+
@suffix = ".html"
|
|
40
|
+
@fs_casesensitive = false
|
|
41
|
+
@verbose = false
|
|
42
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} searchpage [options] <dbpath>..."
|
|
43
|
+
@parser.on('-o', '--outputdir=PATH', 'Output directory.') {|path|
|
|
44
|
+
@outputdir = Pathname.new(path)
|
|
45
|
+
}
|
|
46
|
+
@parser.on('--themedir=PATH', 'Theme directory.') {|path|
|
|
47
|
+
@themedir = Pathname.new(path)
|
|
48
|
+
}
|
|
49
|
+
@parser.on('--fs-casesensitive', 'Filesystem is case-sensitive.') {
|
|
50
|
+
@fs_casesensitive = true
|
|
51
|
+
}
|
|
52
|
+
@parser.on('--verbose', 'Show progress.') {
|
|
53
|
+
@verbose = true
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# DB paths are taken as positional arguments (one per version), so the
|
|
58
|
+
# global --database option is not required.
|
|
59
|
+
def needs_database?
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def exec(argv, options)
|
|
64
|
+
outputdir = @outputdir or error("no --outputdir given")
|
|
65
|
+
error("no database given (pass one path per version)") if argv.empty?
|
|
66
|
+
|
|
67
|
+
generator = SearchIndexGenerator.new(suffix: @suffix,
|
|
68
|
+
fs_casesensitive: @fs_casesensitive)
|
|
69
|
+
version_indexes = argv.map {|path|
|
|
70
|
+
db = MethodDatabase.new(path)
|
|
71
|
+
fdb = FunctionDatabase.new(path) if File.directory?(File.join(path, 'function'))
|
|
72
|
+
version = db.properties['version'] or
|
|
73
|
+
error("#{path}: no version property (not a bitclust database?)")
|
|
74
|
+
$stderr.puts "indexing #{path} (#{version})" if @verbose
|
|
75
|
+
[version, generator.build_index(db, fdb)] #: [String, Array[SearchIndexGenerator::entry]]
|
|
76
|
+
}
|
|
77
|
+
versions = version_indexes.map {|version, _| version }
|
|
78
|
+
.sort_by {|v| Gem::Version.new(v) }
|
|
79
|
+
|
|
80
|
+
jsdir = outputdir + "js"
|
|
81
|
+
FileUtils.mkdir_p(jsdir)
|
|
82
|
+
(jsdir + "search_data.js").write(SearchIndexGenerator.merged_js(version_indexes))
|
|
83
|
+
VENDORED_JS_FILES.each do |js|
|
|
84
|
+
FileUtils.cp(@themedir + "js" + js, jsdir.to_s, :preserve => true)
|
|
85
|
+
end
|
|
86
|
+
# Ship the MIT notice for the vendored Aliki files alongside them.
|
|
87
|
+
FileUtils.cp(@themedir + "js" + "NOTICE", jsdir.to_s, :preserve => true)
|
|
88
|
+
FileUtils.cp(@themedir + "js" + "search_page.js", jsdir.to_s, :preserve => true)
|
|
89
|
+
FileUtils.cp(@themedir + "search.css", outputdir.to_s, :preserve => true)
|
|
90
|
+
(outputdir + "index.html").write(render_page(versions))
|
|
91
|
+
$stderr.puts "generated search page for #{versions.join(', ')}" if @verbose
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def render_page(versions)
|
|
97
|
+
template = (@templatedir + "index.html").read
|
|
98
|
+
template.sub('%%SEARCH_VERSIONS%%', JSON.generate(versions))
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -107,11 +107,11 @@ module BitClust
|
|
|
107
107
|
exit 1
|
|
108
108
|
end
|
|
109
109
|
if @pid_file
|
|
110
|
-
if File.exist?(@pid_file)
|
|
110
|
+
if File.exist?(@pid_file || raise)
|
|
111
111
|
$stderr.puts "There is still #{@pid_file}. Is another process running?"
|
|
112
112
|
exit 1
|
|
113
113
|
end
|
|
114
|
-
@pid_file = File.expand_path(@pid_file)
|
|
114
|
+
@pid_file = File.expand_path(@pid_file || raise)
|
|
115
115
|
end
|
|
116
116
|
end
|
|
117
117
|
|
|
@@ -133,7 +133,7 @@ module BitClust
|
|
|
133
133
|
@params[:Logger] = WEBrick::Log.new($stderr, WEBrick::Log::INFO)
|
|
134
134
|
@params[:AccessLog] = []
|
|
135
135
|
end
|
|
136
|
-
basepath = URI.parse(@baseurl).path
|
|
136
|
+
basepath = URI.parse(@baseurl || raise).path or raise
|
|
137
137
|
server = WEBrick::HTTPServer.new(@params)
|
|
138
138
|
|
|
139
139
|
if @autop
|
|
@@ -172,17 +172,19 @@ module BitClust
|
|
|
172
172
|
server.mount File.join(basepath, 'theme/'), WEBrick::HTTPServlet::FileHandler, @themedir
|
|
173
173
|
|
|
174
174
|
if @debugp
|
|
175
|
-
trap(:INT) { server.shutdown }
|
|
175
|
+
Signal.trap(:INT) { server.shutdown }
|
|
176
176
|
else
|
|
177
177
|
WEBrick::Daemon.start do
|
|
178
|
-
trap(:TERM) {
|
|
178
|
+
Signal.trap(:TERM) {
|
|
179
179
|
server.shutdown
|
|
180
180
|
begin
|
|
181
|
-
|
|
181
|
+
pid_file = @pid_file
|
|
182
|
+
File.unlink pid_file if pid_file
|
|
182
183
|
rescue Errno::ENOENT
|
|
183
184
|
end
|
|
184
185
|
}
|
|
185
|
-
|
|
186
|
+
pid_file = @pid_file
|
|
187
|
+
File.open(pid_file, 'w') {|f| f.write Process.pid } if pid_file
|
|
186
188
|
end
|
|
187
189
|
end
|
|
188
190
|
exit if $".include?("exerb/mkexy.rb")
|
|
@@ -209,7 +211,7 @@ module BitClust
|
|
|
209
211
|
end
|
|
210
212
|
|
|
211
213
|
def load_config_file
|
|
212
|
-
home_directory = Pathname(ENV
|
|
214
|
+
home_directory = Pathname(ENV.fetch('HOME'))
|
|
213
215
|
config_path = home_directory + ".bitclust/config"
|
|
214
216
|
if config_path.exist?
|
|
215
217
|
config = YAML.load_file(config_path)
|