bitclust-core 1.6.1 → 1.7.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/Rakefile +1 -0
- data/data/bitclust/catalog/ja_JP.UTF-8 +4 -2
- data/data/bitclust/template/function-index +1 -0
- data/data/bitclust/template/layout +1 -0
- data/data/bitclust/template.offline/function-index +1 -0
- data/data/bitclust/template.offline/layout +3 -0
- data/lib/bitclust/classentry.rb +1 -1
- data/lib/bitclust/docentry.rb +1 -1
- data/lib/bitclust/functionentry.rb +1 -1
- data/lib/bitclust/irb.rb +68 -0
- data/lib/bitclust/markdown_exporter.rb +311 -0
- data/lib/bitclust/mdcompiler.rb +15 -1
- data/lib/bitclust/mdparser.rb +42 -1
- data/lib/bitclust/methodentry.rb +24 -0
- data/lib/bitclust/methodsignature.rb +1 -1
- data/lib/bitclust/preprocessor.rb +4 -1
- data/lib/bitclust/rbs_overload_matcher.rb +179 -0
- data/lib/bitclust/rbs_sig_importer.rb +276 -0
- data/lib/bitclust/rbs_signatures.rb +125 -0
- data/lib/bitclust/rdcompiler.rb +12 -1
- data/lib/bitclust/runner.rb +2 -0
- data/lib/bitclust/screen.rb +4 -0
- data/lib/bitclust/search_index_generator.rb +28 -10
- data/lib/bitclust/searcher.rb +12 -2
- data/lib/bitclust/subcommands/rbssig_command.rb +99 -0
- data/lib/bitclust/subcommands/setup_command.rb +4 -1
- data/lib/bitclust/subcommands/statichtml_command.rb +59 -0
- data/lib/bitclust/version.rb +1 -1
- data/lib/bitclust-irb.rb +2 -0
- data/test/test_irb_plugin.rb +118 -0
- data/test/test_link_checker.rb +1 -1
- data/test/test_markdown_exporter.rb +260 -0
- data/test/test_mdcompiler.rb +47 -5
- data/test/test_mdparser.rb +184 -4
- data/test/test_methodentry.rb +111 -0
- data/test/test_methodsignature.rb +3 -1
- data/test/test_preprocessor.rb +26 -0
- data/test/test_rbs_overload_matcher.rb +170 -0
- data/test/test_rbs_sig_importer.rb +237 -0
- data/test/test_rbssig_command.rb +186 -0
- data/test/test_rdcompiler.rb +99 -1
- data/test/test_search_index_generator.rb +81 -0
- data/test/test_setup_command.rb +21 -0
- data/test/test_statichtml_command.rb +137 -0
- data/theme/default/js/run.js +14 -0
- data/theme/default/js/search_init.js +3 -1
- data/theme/default/js/search_page.js +7 -1
- data/theme/default/js/version_switcher.js +147 -0
- data/theme/default/search.css +21 -0
- data/theme/default/style.css +83 -7
- data/theme/lillia/style.css +26 -0
- metadata +35 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9f02fb9cdddf44a8c30df3e0e9d2fa51159db37abb39220e090a5bc94b61c9cf
|
|
4
|
+
data.tar.gz: ceffcab8cd2c8bdd34d555e104cd8ac0d774f89b4e42296ff26b64f16570ccbd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 66e1b74b7651e3c12be4d9f55facd88ab6a29def01fae1deb67670191d861a070d95a05c21309e61edf7f43ee7a6f3a948aff410a3bc400eb4b96b5ec6822634
|
|
7
|
+
data.tar.gz: 680e2945c4225e31b0417495c72945a90824105a7af7d9151a006a30d690fc7b36bd04b9fd4427fad46ab6b1513517c7c052ce49c9ec7913ed3b155402f9fa20
|
data/Rakefile
CHANGED
|
@@ -7,7 +7,7 @@ Added/Redefined Methods
|
|
|
7
7
|
All Classes
|
|
8
8
|
クラス一覧
|
|
9
9
|
All Functions
|
|
10
|
-
関数一覧
|
|
10
|
+
C API 関数一覧
|
|
11
11
|
All Libraries
|
|
12
12
|
ライブラリ一覧
|
|
13
13
|
Ancestor Methods
|
|
@@ -51,7 +51,7 @@ File
|
|
|
51
51
|
FileFormat
|
|
52
52
|
ファイルフォーマット
|
|
53
53
|
Function Index
|
|
54
|
-
関数一覧
|
|
54
|
+
C API 関数一覧
|
|
55
55
|
Index
|
|
56
56
|
目次
|
|
57
57
|
I/O
|
|
@@ -112,6 +112,8 @@ Text
|
|
|
112
112
|
テキスト
|
|
113
113
|
Thread
|
|
114
114
|
スレッド
|
|
115
|
+
This is a list of functions provided by the Ruby C API for developing Ruby itself and C extension libraries. These functions cannot be called directly from Ruby programs.
|
|
116
|
+
Ruby の C API(C 言語 API)の関数の一覧です。Ruby 本体や拡張ライブラリの開発に使うもので、Ruby プログラムから直接呼び出す関数ではありません。
|
|
115
117
|
This reference manual is for a version of Ruby that is no longer maintained.
|
|
116
118
|
このマニュアルは既にメンテナンスが終了したバージョンの Ruby を対象としています。
|
|
117
119
|
Undefined Methods for Explanation
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
headline_init
|
|
9
9
|
%>
|
|
10
10
|
<%= headline(_("Function Index")) %>
|
|
11
|
+
<p><%= _('This is a list of functions provided by the Ruby C API for developing Ruby itself and C extension libraries. These functions cannot be called directly from Ruby programs.') %></p>
|
|
11
12
|
<table class="entries functions">
|
|
12
13
|
<%
|
|
13
14
|
headline_push
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<link rel="search" type="application/opensearchdescription+xml" title="<%= _('Ruby %s Reference Manual', ruby_version()) %>" href="<%=h opensearchdescription_url() %>">
|
|
14
14
|
<% if run_ruby_wasm_url %>
|
|
15
15
|
<meta name="rurema-run-ruby-wasm" content="<%=h run_ruby_wasm_url %>">
|
|
16
|
+
<meta name="rurema-run-help" content="<%=h document_url('help') %>#run">
|
|
16
17
|
<script type="module" src="<%=h custom_js_url('js/run.js') %>"></script>
|
|
17
18
|
<% end %>
|
|
18
19
|
</head>
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
</header>
|
|
37
37
|
|
|
38
38
|
<main>
|
|
39
|
+
<p><%= _('This is a list of functions provided by the Ruby C API for developing Ruby itself and C extension libraries. These functions cannot be called directly from Ruby programs.') %></p>
|
|
39
40
|
<table class="entries functions">
|
|
40
41
|
<%
|
|
41
42
|
headline_push
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
<script src="<%=h custom_js_url('js/search_ranker.js') %>"></script>
|
|
22
22
|
<script src="<%=h custom_js_url('js/search_controller.js') %>"></script>
|
|
23
23
|
<script src="<%=h custom_js_url('js/search_init.js') %>"></script>
|
|
24
|
+
<script defer src="<%=h custom_js_url('js/version_switcher.js') %>"></script>
|
|
24
25
|
<% if run_ruby_wasm_url %>
|
|
25
26
|
<meta name="rurema-run-ruby-wasm" content="<%=h run_ruby_wasm_url %>">
|
|
27
|
+
<meta name="rurema-run-help" content="<%=h document_url('help') %>#run">
|
|
26
28
|
<script type="module" src="<%=h custom_js_url('js/run.js') %>"></script>
|
|
27
29
|
<% end %>
|
|
28
30
|
</head>
|
|
@@ -35,6 +37,7 @@
|
|
|
35
37
|
<% end %>
|
|
36
38
|
<div id="rurema-topbar">
|
|
37
39
|
<div id="rurema-brand"><%= manual_home_link %></div>
|
|
40
|
+
<div id="version-switcher"></div>
|
|
38
41
|
<div id="search-section" role="search">
|
|
39
42
|
<input id="search-field" type="text" autocomplete="off" spellcheck="false"
|
|
40
43
|
placeholder="クラス・メソッドを検索 (/)"
|
data/lib/bitclust/classentry.rb
CHANGED
data/lib/bitclust/docentry.rb
CHANGED
data/lib/bitclust/irb.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# irb からるりま(Ruby リファレンスマニュアル)を引く refe コマンド。
|
|
4
|
+
# ~/.irbrc に `require "bitclust/irb"` と書くと irb に `refe` コマンドが
|
|
5
|
+
# 登録される。検索対象の DB は refe コマンドと同じ場所
|
|
6
|
+
# (bitclust setup が作る ~/.bitclust/config)から探す。
|
|
7
|
+
|
|
8
|
+
require 'stringio'
|
|
9
|
+
require 'bitclust'
|
|
10
|
+
require 'bitclust/searcher'
|
|
11
|
+
|
|
12
|
+
module BitClust
|
|
13
|
+
module Irb
|
|
14
|
+
USAGE = <<~USAGE
|
|
15
|
+
Usage: refe <pattern>
|
|
16
|
+
|
|
17
|
+
例:
|
|
18
|
+
refe String#gsub インスタンスメソッド
|
|
19
|
+
refe Array.new 特異メソッド
|
|
20
|
+
refe Comparable クラス・モジュール
|
|
21
|
+
refe printf 名前だけでの検索
|
|
22
|
+
|
|
23
|
+
DB が無い場合は `bitclust setup` で作成してください。
|
|
24
|
+
USAGE
|
|
25
|
+
|
|
26
|
+
# pattern を検索して整形済みテキストを io へ書く。db が nil なら
|
|
27
|
+
# 既定の場所から探す。検索の失敗は例外にせず io へメッセージを書く
|
|
28
|
+
# (irb セッションを止めないため)
|
|
29
|
+
def self.lookup(pattern, io: $stdout, db: nil)
|
|
30
|
+
words = pattern.to_s.split
|
|
31
|
+
if words.empty?
|
|
32
|
+
io.puts USAGE
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
view = TerminalView.new(Plain.new,
|
|
36
|
+
{ describe_all: false, line: false, encoding: nil },
|
|
37
|
+
io: io)
|
|
38
|
+
Searcher.new.run_query(db, words, view)
|
|
39
|
+
rescue BitClust::UserError => err
|
|
40
|
+
io.puts err.message
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
require 'irb/command'
|
|
45
|
+
rescue LoadError
|
|
46
|
+
# irb が無い(または irb < 1.13 で公開コマンド API が無い)環境では
|
|
47
|
+
# コマンド登録だけを諦め、Irb.lookup は使えるままにする
|
|
48
|
+
else
|
|
49
|
+
class RefeCommand < ::IRB::Command::Base
|
|
50
|
+
category 'Documentation'
|
|
51
|
+
description 'るりま(Ruby リファレンスマニュアル)を検索して表示します'
|
|
52
|
+
help_message USAGE
|
|
53
|
+
|
|
54
|
+
def execute(arg)
|
|
55
|
+
content = StringIO.new
|
|
56
|
+
BitClust::Irb.lookup(arg, io: content)
|
|
57
|
+
if ::IRB.const_defined?(:Pager)
|
|
58
|
+
::IRB::Pager.page_content(content.string)
|
|
59
|
+
else
|
|
60
|
+
$stdout.puts content.string
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
::IRB::Command.register(:refe, RefeCommand)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bitclust/nameutils'
|
|
4
|
+
|
|
5
|
+
module BitClust
|
|
6
|
+
|
|
7
|
+
# statichtml の --markdown-output 用に、HTML の各ページと対になる Markdown を
|
|
8
|
+
# エントリの前処理済みソース(Markdown ツリー由来の md)から組み立てる。
|
|
9
|
+
# 参照記法(単一ブラケットの [m:...] 等と、参照 scheme を宛先にした
|
|
10
|
+
# ラベル付きリンク)は相対 .md リンクへ解決する。解決できない参照
|
|
11
|
+
# (未対応の種別・不正な指定)はそのまま残し、エラーにしない。
|
|
12
|
+
# コードスパンとコードフェンスの中は変換しない。
|
|
13
|
+
class MarkdownExporter
|
|
14
|
+
|
|
15
|
+
# クラスページの メソッド種別 → セクション見出し(doctree の md と同じ名称)
|
|
16
|
+
CLASS_SECTIONS = [
|
|
17
|
+
["Class Methods", :public, :singleton_method],
|
|
18
|
+
["Instance Methods", :public, :instance_method],
|
|
19
|
+
["Private Class Methods", :private, :singleton_method],
|
|
20
|
+
["Private Instance Methods", :private, :instance_method],
|
|
21
|
+
["Protected Instance Methods", :protected, :instance_method],
|
|
22
|
+
["Module Functions", :public, :module_function],
|
|
23
|
+
["Constants", :public, :constant],
|
|
24
|
+
["Special Variables", :public, :special_variable],
|
|
25
|
+
].freeze
|
|
26
|
+
|
|
27
|
+
def initialize(urlmapper, html_suffix)
|
|
28
|
+
@urlmapper = urlmapper
|
|
29
|
+
@html_suffix = html_suffix
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def library_page(entry)
|
|
33
|
+
page("# library #{entry.name}", entry.source)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# クラスページは HTML と同じく本文+メソッドリンク一覧(本文は載せない)
|
|
37
|
+
def class_page(entry)
|
|
38
|
+
out = +""
|
|
39
|
+
CLASS_SECTIONS.each do |section, visibility, type|
|
|
40
|
+
methods = entry.entries.select { |m|
|
|
41
|
+
!m.undefined? && m.type == type && m.visibility == visibility
|
|
42
|
+
}
|
|
43
|
+
next if methods.empty?
|
|
44
|
+
out << "\n## #{section}\n\n"
|
|
45
|
+
methods.each do |m|
|
|
46
|
+
m.names.each do |name|
|
|
47
|
+
spec = m.klass.name + m.typemark + name
|
|
48
|
+
url = ref_url('m', spec)
|
|
49
|
+
out << (url ? "- [#{escape_label(name)}](#{url})\n" : "- #{escape_label(name)}\n")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
page(class_heading(entry), entry.source, out)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def method_page(method_name, entries)
|
|
57
|
+
out = +"# #{method_name.sub('.#', '?.')}\n"
|
|
58
|
+
entries.each do |m|
|
|
59
|
+
body = m.source.strip
|
|
60
|
+
out << "\n" << convert_text(body) << "\n" unless body.empty?
|
|
61
|
+
end
|
|
62
|
+
out
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def doc_page(entry)
|
|
66
|
+
page("# #{entry.title}", entry.source)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def function_page(entry)
|
|
70
|
+
page("# #{entry.name}", "### #{entry.header}\n#{entry.source}")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# 本文中の参照をコードスパン・コードフェンスを避けて相対 .md リンクへ
|
|
74
|
+
# 変換する
|
|
75
|
+
def convert_text(str)
|
|
76
|
+
out = +''
|
|
77
|
+
fence = nil
|
|
78
|
+
str.each_line do |line|
|
|
79
|
+
if fence
|
|
80
|
+
out << line
|
|
81
|
+
stripped = line.strip
|
|
82
|
+
fence = nil if stripped.match?(/\A`+\z/) && stripped.length >= (fence || 0)
|
|
83
|
+
elsif (m = /\A {0,3}(`{3,})/.match(line))
|
|
84
|
+
fence = (m[1] || raise).length
|
|
85
|
+
out << line
|
|
86
|
+
else
|
|
87
|
+
out << convert_line(line)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
out
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def page(heading, source, trailer = "")
|
|
96
|
+
out = +"#{heading}\n"
|
|
97
|
+
body = source.strip
|
|
98
|
+
out << "\n" << convert_text(body) << "\n" unless body.empty?
|
|
99
|
+
out << trailer
|
|
100
|
+
out
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def class_heading(entry)
|
|
104
|
+
case entry.type
|
|
105
|
+
when :class
|
|
106
|
+
sc = entry.superclass
|
|
107
|
+
sc ? "# class #{entry.name} < #{sc.name}" : "# class #{entry.name}"
|
|
108
|
+
when :module
|
|
109
|
+
"# module #{entry.name}"
|
|
110
|
+
when :object
|
|
111
|
+
"# object #{entry.name}"
|
|
112
|
+
else
|
|
113
|
+
"# #{entry.name}"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def convert_line(line)
|
|
118
|
+
spans = [] #: Array[String]
|
|
119
|
+
converted = convert_refs(extract_code_spans(line, spans))
|
|
120
|
+
converted.gsub(/\x00(\d+)\x00/) { spans[($1 || raise).to_i] || raise }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# インラインコードスパン(CommonMark 6.1、N 連バッククォートの同長
|
|
124
|
+
# ペアリング)を書かれたままプレースホルダへ退避する
|
|
125
|
+
def extract_code_spans(str, saved)
|
|
126
|
+
result = +''
|
|
127
|
+
i = 0
|
|
128
|
+
len = str.length
|
|
129
|
+
while i < len
|
|
130
|
+
c = str[i] or raise
|
|
131
|
+
if c == '\\' && i + 1 < len
|
|
132
|
+
result << (str[i, 2] || raise)
|
|
133
|
+
i += 2
|
|
134
|
+
next
|
|
135
|
+
end
|
|
136
|
+
if c == '`'
|
|
137
|
+
run = 1
|
|
138
|
+
run += 1 while str[i + run] == '`'
|
|
139
|
+
close = find_code_span_close(str, i + run, run)
|
|
140
|
+
if close
|
|
141
|
+
saved << (str[i...(close + run)] || raise)
|
|
142
|
+
result << "\x00#{saved.size - 1}\x00"
|
|
143
|
+
i = close + run
|
|
144
|
+
next
|
|
145
|
+
end
|
|
146
|
+
result << ('`' * run)
|
|
147
|
+
i += run
|
|
148
|
+
next
|
|
149
|
+
end
|
|
150
|
+
result << c
|
|
151
|
+
i += 1
|
|
152
|
+
end
|
|
153
|
+
result
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def find_code_span_close(str, from, run_len)
|
|
157
|
+
i = from
|
|
158
|
+
len = str.length
|
|
159
|
+
while i < len
|
|
160
|
+
case str[i]
|
|
161
|
+
when "\n"
|
|
162
|
+
return nil
|
|
163
|
+
when '`'
|
|
164
|
+
j = i
|
|
165
|
+
j += 1 while str[j] == '`'
|
|
166
|
+
return i if j - i == run_len
|
|
167
|
+
i = j
|
|
168
|
+
else
|
|
169
|
+
i += 1
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
nil
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
REF_SCHEME_RE = /\A([a-zA-Z][a-zA-Z-]*):(.*)\z/m
|
|
176
|
+
|
|
177
|
+
def convert_refs(str)
|
|
178
|
+
result = +''
|
|
179
|
+
i = 0
|
|
180
|
+
while i < str.length
|
|
181
|
+
if str[i] == '\\' && i + 1 < str.length
|
|
182
|
+
result << (str[i, 2] || raise)
|
|
183
|
+
i += 2
|
|
184
|
+
next
|
|
185
|
+
end
|
|
186
|
+
if str[i] == '['
|
|
187
|
+
close = matching_delimiter(str, i, '[', ']')
|
|
188
|
+
if close
|
|
189
|
+
if str[close + 1] == '(' &&
|
|
190
|
+
(dest_end = matching_delimiter(str, close + 1, '(', ')', space_ends: true)) &&
|
|
191
|
+
(dest = str[(close + 2)...dest_end])
|
|
192
|
+
# ラベル付きリンク [text](dest)
|
|
193
|
+
if (m = REF_SCHEME_RE.match(dest)) && (url = ref_url(m[1] || raise, m[2] || raise))
|
|
194
|
+
result << "[#{str[(i + 1)...close]}](#{url})"
|
|
195
|
+
i = dest_end + 1
|
|
196
|
+
next
|
|
197
|
+
end
|
|
198
|
+
if dest.start_with?('#') || dest.match?(%r{\Ahttps?://})
|
|
199
|
+
# 通常の Markdown リンクはそのまま(ラベル内は再解釈しない)
|
|
200
|
+
result << (str[i..dest_end] || raise)
|
|
201
|
+
i = dest_end + 1
|
|
202
|
+
next
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
# 単一ブラケット参照 [type:target]([[ は除外)
|
|
206
|
+
inner = str[(i + 1)...close] || raise
|
|
207
|
+
if str[i + 1] != '[' && (m = REF_SCHEME_RE.match(inner)) &&
|
|
208
|
+
(converted = bare_ref(m[1] || raise, m[2] || raise, inner))
|
|
209
|
+
result << converted
|
|
210
|
+
i = close + 1
|
|
211
|
+
next
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
result << (str[i] || raise)
|
|
216
|
+
i += 1
|
|
217
|
+
end
|
|
218
|
+
result
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# open 位置の括弧に対応する閉じ括弧の位置(\ エスケープ対応・ネスト可)。
|
|
222
|
+
# space_ends: リンク宛先用。空白が現れたらリンクではない(nil)
|
|
223
|
+
def matching_delimiter(str, open, open_char, close_char, space_ends: false)
|
|
224
|
+
depth = 0
|
|
225
|
+
i = open
|
|
226
|
+
while i < str.length
|
|
227
|
+
c = str[i]
|
|
228
|
+
if c == '\\'
|
|
229
|
+
i += 1
|
|
230
|
+
elsif space_ends && c =~ /\s/
|
|
231
|
+
return nil
|
|
232
|
+
elsif c == open_char
|
|
233
|
+
depth += 1
|
|
234
|
+
elsif c == close_char
|
|
235
|
+
depth -= 1
|
|
236
|
+
return i if depth == 0
|
|
237
|
+
end
|
|
238
|
+
i += 1
|
|
239
|
+
end
|
|
240
|
+
nil
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# 単一ブラケット参照 1 個を Markdown リンクにする。ラベルは書かれた
|
|
244
|
+
# ままの形(エスケープ込み)から type: を落としたもの
|
|
245
|
+
def bare_ref(type, arg, written)
|
|
246
|
+
label =
|
|
247
|
+
case type
|
|
248
|
+
when 'm', 'c', 'lib', 'd', 'f'
|
|
249
|
+
written.split(':', 2)[1]
|
|
250
|
+
when 'url'
|
|
251
|
+
arg
|
|
252
|
+
when 'ref'
|
|
253
|
+
case arg
|
|
254
|
+
when /\A(\w+):(.*)\#([-\w]+)\z/
|
|
255
|
+
"#{$2}##{$3}"
|
|
256
|
+
when /\A[-\w]+\z/
|
|
257
|
+
arg
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
return nil unless label
|
|
261
|
+
url = ref_url(type, arg)
|
|
262
|
+
return nil unless url
|
|
263
|
+
"[#{label}](#{url})"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# 参照 scheme の宛先 URL(.md への相対リンク)。解決できなければ nil
|
|
267
|
+
def ref_url(type, arg)
|
|
268
|
+
arg = unescape_md_brackets(arg)
|
|
269
|
+
case type
|
|
270
|
+
when 'm'
|
|
271
|
+
# md 表記の module function ?. は内部表記 .# に正規化して引く
|
|
272
|
+
md_suffix(@urlmapper.method_url(arg.sub('?.', '.#')))
|
|
273
|
+
when 'c'
|
|
274
|
+
md_suffix(@urlmapper.class_url(arg))
|
|
275
|
+
when 'lib'
|
|
276
|
+
md_suffix(@urlmapper.library_url(arg))
|
|
277
|
+
when 'd'
|
|
278
|
+
md_suffix(@urlmapper.document_url(arg))
|
|
279
|
+
when 'f'
|
|
280
|
+
md_suffix(@urlmapper.function_url(arg))
|
|
281
|
+
when 'url'
|
|
282
|
+
arg
|
|
283
|
+
when 'ref'
|
|
284
|
+
case arg
|
|
285
|
+
when /\A(\w+):(.*)\#([-\w]+)\z/
|
|
286
|
+
url = ref_url($1 || raise, $2 || raise)
|
|
287
|
+
url ? "#{url}##{$3}" : nil
|
|
288
|
+
when /\A[-\w]+\z/
|
|
289
|
+
"##{arg}"
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
rescue StandardError
|
|
293
|
+
nil
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def md_suffix(html_url)
|
|
297
|
+
return html_url unless html_url.end_with?(@html_suffix)
|
|
298
|
+
"#{html_url[0, html_url.length - @html_suffix.length]}.md"
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def unescape_md_brackets(str)
|
|
302
|
+
str.gsub(/\\([\[\]\\])/, '\1')
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def escape_label(text)
|
|
306
|
+
text.gsub(/[\\\[\]]/) { "\\#{$&}" }
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
end
|
data/lib/bitclust/mdcompiler.rb
CHANGED
|
@@ -126,6 +126,12 @@ module BitClust
|
|
|
126
126
|
break
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
|
+
# RBS シグネチャは見出し <dt> 群の直後・説明 <dd> の直前に、この
|
|
130
|
+
# チャンクへ振り分けられたぶんだけ <dt> 行として出す(rd 側
|
|
131
|
+
# entry_chunk と同じ。rbs_sig property が無ければ何も出ない)
|
|
132
|
+
if (rbs_dts = rbs_signature_dts_for_chunk())
|
|
133
|
+
@out.puts rbs_dts
|
|
134
|
+
end
|
|
129
135
|
@out.puts %Q(<dd class="#{@type.to_s}-description">)
|
|
130
136
|
undef_message if attrs.include?('undef')
|
|
131
137
|
while @f.next?
|
|
@@ -184,6 +190,12 @@ module BitClust
|
|
|
184
190
|
super(sig_line.sub(signature_re, '--- '), first)
|
|
185
191
|
end
|
|
186
192
|
|
|
193
|
+
# RBS シグネチャのチャンク走査(RbsSignatures)用: md のシグネチャ行を
|
|
194
|
+
# rd の正規形にして返す(method_signature と同じ変換)
|
|
195
|
+
def rbs_signature_line(line)
|
|
196
|
+
line.sub(signature_re, '--- ') if signature_re =~ line
|
|
197
|
+
end
|
|
198
|
+
|
|
187
199
|
def headline(line)
|
|
188
200
|
hashes = line[/\A#+/] || raise
|
|
189
201
|
label = line.sub(/\A#+\s*/, '').strip
|
|
@@ -405,11 +417,13 @@ module BitClust
|
|
|
405
417
|
}
|
|
406
418
|
end
|
|
407
419
|
|
|
420
|
+
# 列揃えはインラインスタイルで出す。align 属性は presentational hint
|
|
421
|
+
# としての扱いになり、テーマ CSS の text-align 指定に負けて効かない
|
|
408
422
|
def table_row(row, tag, aligns)
|
|
409
423
|
cells = split_table_row(row)
|
|
410
424
|
string '<tr>'
|
|
411
425
|
cells.each_with_index do |cell, i|
|
|
412
|
-
align = aligns[i] ? %Q(
|
|
426
|
+
align = aligns[i] ? %Q( style="text-align:#{aligns[i]}") : ''
|
|
413
427
|
string "<#{tag}#{align}>#{compile_text(cell)}</#{tag}>"
|
|
414
428
|
end
|
|
415
429
|
line '</tr>'
|
data/lib/bitclust/mdparser.rb
CHANGED
|
@@ -314,11 +314,50 @@ module BitClust
|
|
|
314
314
|
src = (header + body).join('')
|
|
315
315
|
src.location = sig_lines[0].location
|
|
316
316
|
sigs = sig_lines.map {|line| method_signature(line) }
|
|
317
|
+
# キーワード不一致はより具体的なメッセージになるよう
|
|
318
|
+
# check_chunk_signatures(signature crash)より先に検査する
|
|
319
|
+
check_entry_style(sig_lines, sigs)
|
|
317
320
|
mainsig = check_chunk_signatures(sigs, sig_lines[0])
|
|
318
321
|
names = sigs.map {|s| s.name }.compact.uniq.sort
|
|
319
322
|
Chunk.new(mainsig, names, src)
|
|
320
323
|
end
|
|
321
324
|
|
|
325
|
+
# セクション(h2)の型ごとに期待するエントリキーワード。
|
|
326
|
+
# キーワードは型決定には使われない(型はセクションで決まる)ため、
|
|
327
|
+
# 食い違ったまま書けてしまう分類間違い(rurema/doctree#3291 の
|
|
328
|
+
# 「Class Methods 配下の const」等)をパース時に検出する
|
|
329
|
+
ENTRY_KEYWORD_RE = /\A### (module_function def|def|const|gvar) /
|
|
330
|
+
EXPECTED_ENTRY_KEYWORD = {
|
|
331
|
+
'#' => 'def',
|
|
332
|
+
'.' => 'def',
|
|
333
|
+
'.#' => 'module_function def',
|
|
334
|
+
'::' => 'const',
|
|
335
|
+
'$' => 'gvar',
|
|
336
|
+
}.freeze
|
|
337
|
+
|
|
338
|
+
# エントリの書式とセクションの一致検査。
|
|
339
|
+
# - キーワードがセクションの種別と一致すること
|
|
340
|
+
# - 特異メソッドは `def Klass.name` / `def self.name` のプレフィクス
|
|
341
|
+
# 必須(MARKUP_SPEC §3.1。def 行だけでメソッド種別が分かるようにする)
|
|
342
|
+
def check_entry_style(sig_lines, sigs)
|
|
343
|
+
cxt = @context.signature
|
|
344
|
+
return unless cxt && cxt.type
|
|
345
|
+
expected = EXPECTED_ENTRY_KEYWORD[cxt.type] or return
|
|
346
|
+
sig_lines.zip(sigs).each do |line, sig|
|
|
347
|
+
keyword = (line || raise)[ENTRY_KEYWORD_RE, 1]
|
|
348
|
+
unless keyword == expected
|
|
349
|
+
parse_error "entry keyword `#{keyword}' does not match this section (expected `#{expected}')", line
|
|
350
|
+
end
|
|
351
|
+
if cxt.type == '.' && sig && sig.type.nil?
|
|
352
|
+
parse_error "singleton method entry must be written as `def #{cxt.klass || 'Klass'}.name' or `def self.name'", line
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# `def self.name` 形式。type は singleton に確定し、klass は
|
|
358
|
+
# 見出しコンテキスト(H1/H2)から補完される
|
|
359
|
+
SELF_SIGNATURE = /\A---\s*self\.(#{METHOD_NAME_RE})/
|
|
360
|
+
|
|
322
361
|
# md シグネチャ行を rd 形式(--- ...)へ落とし、既存の
|
|
323
362
|
# Signature パースを継承する。エラー時は元の行を報告する
|
|
324
363
|
def method_signature(line)
|
|
@@ -326,12 +365,14 @@ module BitClust
|
|
|
326
365
|
begin
|
|
327
366
|
# 描画(MethodSignature.parse)が受理できないシグネチャは
|
|
328
367
|
# statichtml まで進んでから落ちる(か、誤った名前で DB に入る)ので
|
|
329
|
-
# パース時に拒否する。RBS 形式(def name
|
|
368
|
+
# パース時に拒否する。RBS 形式(def name:)が該当
|
|
330
369
|
MethodSignature.parse(rd_line)
|
|
331
370
|
rescue ParseError
|
|
332
371
|
parse_error "unsupported method signature", line
|
|
333
372
|
end
|
|
334
373
|
case
|
|
374
|
+
when m = SELF_SIGNATURE.match(rd_line)
|
|
375
|
+
Signature.new(nil, '.', m[1])
|
|
335
376
|
when m = SIGNATURE.match(rd_line)
|
|
336
377
|
klass, typemark_, name = m.captures
|
|
337
378
|
typemark = _ = typemark_
|
data/lib/bitclust/methodentry.rb
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
require 'bitclust/entry'
|
|
12
12
|
require 'bitclust/exception'
|
|
13
|
+
require 'json'
|
|
13
14
|
|
|
14
15
|
module BitClust
|
|
15
16
|
|
|
@@ -118,6 +119,11 @@ module BitClust
|
|
|
118
119
|
# 現れない前提。fill_since/fill_until で検査する)
|
|
119
120
|
property :since_by_name, '[String]'
|
|
120
121
|
property :until_by_name, '[String]'
|
|
122
|
+
# RBS シグネチャ表示。オーバーロード配列(RbsSigImporter 参照)の
|
|
123
|
+
# JSON 1 行を持つ。型シグネチャは ',' を普通に含むので [String] 型
|
|
124
|
+
# (',' 区切り)は使えない。JSON は改行を含まず、property ファイルの
|
|
125
|
+
# key=value 1 行形式は値中の '=' を許す(split('=', 2))ので安全
|
|
126
|
+
property :rbs_sig, 'String'
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
def inspect
|
|
@@ -166,6 +172,24 @@ module BitClust
|
|
|
166
172
|
"#{methodid2typechar(@id)}_#{encodename_fs(name).gsub(/=/, '--')}".upcase
|
|
167
173
|
end
|
|
168
174
|
|
|
175
|
+
# rbs_sig(JSON)をオーバーロード配列に戻す。現行形式は
|
|
176
|
+
# {"overloads":[{"segments":..., "params":..., "arity":..., "block":...}]}
|
|
177
|
+
# で、セグメント行列そのものの配列だった旧形式の DB は segments だけの
|
|
178
|
+
# オーバーロード列に読み替える。property が無い古い DB(nil)・
|
|
179
|
+
# シグネチャ無しで保存された空文字列・未保存エントリの "(uninitialized)"
|
|
180
|
+
# センチネル・壊れた JSON はすべて nil(= 表示しない)に落として
|
|
181
|
+
# 描画側を守る
|
|
182
|
+
def rbs_signature_overloads
|
|
183
|
+
json = rbs_sig()
|
|
184
|
+
return nil unless json && (json.start_with?('{') || json.start_with?('['))
|
|
185
|
+
data = JSON.parse(json)
|
|
186
|
+
overloads = data.is_a?(Hash) ? data['overloads']
|
|
187
|
+
: data.map {|segments| {'segments' => segments} }
|
|
188
|
+
overloads.is_a?(Array) && !overloads.empty? ? overloads : nil
|
|
189
|
+
rescue JSON::ParserError
|
|
190
|
+
nil
|
|
191
|
+
end
|
|
192
|
+
|
|
169
193
|
def labels
|
|
170
194
|
c, t, _m, _lib = methodid2specparts(@id)
|
|
171
195
|
names().map {|name| "#{c}#{t}#{name}" }
|
|
@@ -21,7 +21,7 @@ module BitClust
|
|
|
21
21
|
|
|
22
22
|
METHOD_SIGNATURE_RE = /\A
|
|
23
23
|
--- \s*
|
|
24
|
-
(?: (?:#{CLASS_PATH_RE} #{TYPEMARK_RE})? (#{METHOD_NAME_RE})
|
|
24
|
+
(?: (?:#{CLASS_PATH_RE} #{TYPEMARK_RE} | self\.)? (#{METHOD_NAME_RE})
|
|
25
25
|
| (#{GVAR_RE})
|
|
26
26
|
) \s* # method name ($1) or gvar name ($2)
|
|
27
27
|
(?: \( (.*?) \) \s* )? # parameters (optional); $3=parameter_list
|