bitclust-core 0.5.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.
- data/ChangeLog +2907 -0
- data/Gemfile +7 -0
- data/README +21 -0
- data/Rakefile +20 -0
- data/bin/bitclust +14 -0
- data/bin/refe +36 -0
- data/bitclust-dev.gemspec +33 -0
- data/bitclust.gemspec +30 -0
- data/config.in +23 -0
- data/config.ru +48 -0
- data/config.ru.sample +31 -0
- data/data/bitclust/catalog/ja_JP.EUC-JP +78 -0
- data/data/bitclust/catalog/ja_JP.UTF-8 +78 -0
- data/data/bitclust/template.lillia/class +98 -0
- data/data/bitclust/template.lillia/class-index +28 -0
- data/data/bitclust/template.lillia/doc +48 -0
- data/data/bitclust/template.lillia/layout +19 -0
- data/data/bitclust/template.lillia/library +129 -0
- data/data/bitclust/template.lillia/library-index +32 -0
- data/data/bitclust/template.lillia/method +20 -0
- data/data/bitclust/template.lillia/rd_file +6 -0
- data/data/bitclust/template.offline/class +67 -0
- data/data/bitclust/template.offline/class-index +28 -0
- data/data/bitclust/template.offline/doc +13 -0
- data/data/bitclust/template.offline/function +22 -0
- data/data/bitclust/template.offline/function-index +24 -0
- data/data/bitclust/template.offline/layout +18 -0
- data/data/bitclust/template.offline/library +87 -0
- data/data/bitclust/template.offline/library-index +32 -0
- data/data/bitclust/template.offline/method +21 -0
- data/data/bitclust/template.offline/rd_file +6 -0
- data/data/bitclust/template/class +133 -0
- data/data/bitclust/template/class-index +30 -0
- data/data/bitclust/template/doc +14 -0
- data/data/bitclust/template/function +21 -0
- data/data/bitclust/template/function-index +25 -0
- data/data/bitclust/template/layout +19 -0
- data/data/bitclust/template/library +89 -0
- data/data/bitclust/template/library-index +35 -0
- data/data/bitclust/template/method +24 -0
- data/data/bitclust/template/opensearchdescription +10 -0
- data/data/bitclust/template/search +57 -0
- data/lib/bitclust.rb +9 -0
- data/lib/bitclust/app.rb +129 -0
- data/lib/bitclust/classentry.rb +425 -0
- data/lib/bitclust/compat.rb +39 -0
- data/lib/bitclust/completion.rb +531 -0
- data/lib/bitclust/crossrubyutils.rb +91 -0
- data/lib/bitclust/database.rb +181 -0
- data/lib/bitclust/docentry.rb +83 -0
- data/lib/bitclust/entry.rb +223 -0
- data/lib/bitclust/exception.rb +38 -0
- data/lib/bitclust/functiondatabase.rb +115 -0
- data/lib/bitclust/functionentry.rb +81 -0
- data/lib/bitclust/functionreferenceparser.rb +76 -0
- data/lib/bitclust/htmlutils.rb +80 -0
- data/lib/bitclust/interface.rb +87 -0
- data/lib/bitclust/libraryentry.rb +211 -0
- data/lib/bitclust/lineinput.rb +165 -0
- data/lib/bitclust/messagecatalog.rb +95 -0
- data/lib/bitclust/methoddatabase.rb +401 -0
- data/lib/bitclust/methodentry.rb +202 -0
- data/lib/bitclust/methodid.rb +209 -0
- data/lib/bitclust/methodsignature.rb +82 -0
- data/lib/bitclust/nameutils.rb +236 -0
- data/lib/bitclust/parseutils.rb +60 -0
- data/lib/bitclust/preprocessor.rb +273 -0
- data/lib/bitclust/rdcompiler.rb +507 -0
- data/lib/bitclust/refsdatabase.rb +66 -0
- data/lib/bitclust/requesthandler.rb +330 -0
- data/lib/bitclust/ridatabase.rb +349 -0
- data/lib/bitclust/rrdparser.rb +522 -0
- data/lib/bitclust/runner.rb +143 -0
- data/lib/bitclust/screen.rb +554 -0
- data/lib/bitclust/searcher.rb +518 -0
- data/lib/bitclust/server.rb +59 -0
- data/lib/bitclust/simplesearcher.rb +84 -0
- data/lib/bitclust/subcommand.rb +746 -0
- data/lib/bitclust/textutils.rb +51 -0
- data/lib/bitclust/version.rb +3 -0
- data/packer.rb +224 -0
- data/refe2.gemspec +29 -0
- data/server.exe +0 -0
- data/server.exy +159 -0
- data/server.rb +10 -0
- data/setup.rb +1596 -0
- data/standalone.rb +193 -0
- data/test/run_test.rb +15 -0
- data/test/test_bitclust.rb +81 -0
- data/test/test_entry.rb +39 -0
- data/test/test_functiondatabase.rb +55 -0
- data/test/test_libraryentry.rb +31 -0
- data/test/test_methoddatabase.rb +81 -0
- data/test/test_methodsignature.rb +14 -0
- data/test/test_nameutils.rb +324 -0
- data/test/test_preprocessor.rb +84 -0
- data/test/test_rdcompiler.rb +534 -0
- data/test/test_refsdatabase.rb +76 -0
- data/test/test_rrdparser.rb +26 -0
- data/test/test_runner.rb +102 -0
- data/test/test_simplesearcher.rb +48 -0
- data/theme/default/images/external.png +0 -0
- data/theme/default/rurema.png +0 -0
- data/theme/default/style.css +288 -0
- data/theme/default/test.css +254 -0
- data/theme/lillia/rurema.png +0 -0
- data/theme/lillia/style.css +331 -0
- data/theme/lillia/test.css +254 -0
- data/tools/bc-ancestors.rb +153 -0
- data/tools/bc-checkparams.rb +246 -0
- data/tools/bc-classes.rb +80 -0
- data/tools/bc-convert.rb +165 -0
- data/tools/bc-list.rb +63 -0
- data/tools/bc-methods.rb +171 -0
- data/tools/bc-preproc.rb +42 -0
- data/tools/bc-rdoc.rb +343 -0
- data/tools/bc-tochm.rb +301 -0
- data/tools/bc-tohtml.rb +125 -0
- data/tools/bc-tohtmlpackage.rb +241 -0
- data/tools/check-signature.rb +19 -0
- data/tools/forall-ruby.rb +20 -0
- data/tools/gencatalog.rb +69 -0
- data/tools/statrefm.rb +98 -0
- data/tools/stattodo.rb +150 -0
- data/tools/update-database.rb +146 -0
- data/view.cgi +6 -0
- metadata +222 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#
|
|
2
|
+
# bitclust/parseutils.rb
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2006-2007 Minero Aoki
|
|
5
|
+
#
|
|
6
|
+
# This program is free software.
|
|
7
|
+
# You can distribute/modify this program under the Ruby License.
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
require 'bitclust/exception'
|
|
11
|
+
|
|
12
|
+
class String # reopen
|
|
13
|
+
attr_accessor :location
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module BitClust
|
|
17
|
+
|
|
18
|
+
class LineStream
|
|
19
|
+
def initialize(f)
|
|
20
|
+
@f = f
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def gets
|
|
24
|
+
line = @f.gets
|
|
25
|
+
return nil unless line
|
|
26
|
+
if @f.respond_to?(:path)
|
|
27
|
+
path = @f.path
|
|
28
|
+
else
|
|
29
|
+
path = nil
|
|
30
|
+
end
|
|
31
|
+
line.location = Location.new(path, @f.lineno)
|
|
32
|
+
line
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class Location
|
|
37
|
+
def initialize(file, line)
|
|
38
|
+
@file = file
|
|
39
|
+
@line = line
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
attr_reader :file
|
|
43
|
+
attr_reader :line
|
|
44
|
+
|
|
45
|
+
def to_s
|
|
46
|
+
"#{@file}:#{@line}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def inspect
|
|
50
|
+
"\#<#{self.class} #{@file}:#{@line}>"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
module ParseUtils
|
|
55
|
+
def parse_error(msg, line)
|
|
56
|
+
raise ParseError, "#{line.location}: #{msg}: #{line.inspect}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
#
|
|
2
|
+
# bitclust/preprocessor.rb
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2006-2007 Minero Aoki
|
|
5
|
+
#
|
|
6
|
+
# This program is free software.
|
|
7
|
+
# You can distribute/modify this program under the Ruby License.
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
require 'bitclust/parseutils'
|
|
11
|
+
require 'strscan'
|
|
12
|
+
|
|
13
|
+
module BitClust
|
|
14
|
+
|
|
15
|
+
class LineFilter
|
|
16
|
+
|
|
17
|
+
include ParseUtils
|
|
18
|
+
include Enumerable
|
|
19
|
+
|
|
20
|
+
def initialize(f)
|
|
21
|
+
@f = f
|
|
22
|
+
@buf = []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def gets
|
|
26
|
+
@buf.shift || next_line(@f)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def each
|
|
30
|
+
while line = gets()
|
|
31
|
+
yield line
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# abstract next_line
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Preprocessor < LineFilter
|
|
41
|
+
|
|
42
|
+
def self.read(path, params = {})
|
|
43
|
+
if path.respond_to?(:gets)
|
|
44
|
+
io = wrap(path, params)
|
|
45
|
+
else
|
|
46
|
+
io = wrap(fopen(path, 'r:UTF-8'), params)
|
|
47
|
+
end
|
|
48
|
+
ret = ""
|
|
49
|
+
while s = io.gets
|
|
50
|
+
ret << s
|
|
51
|
+
end
|
|
52
|
+
ret
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def Preprocessor.process(path, params = {})
|
|
56
|
+
fopen(path, 'r:UTF-8') {|f|
|
|
57
|
+
return wrap(f, params).to_a
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def Preprocessor.wrap(f, params = {})
|
|
62
|
+
new(LineStream.new(f), params)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def initialize(f, params = {})
|
|
66
|
+
super f
|
|
67
|
+
@params = params
|
|
68
|
+
@last_if = nil
|
|
69
|
+
cond_init
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def next_line(f)
|
|
75
|
+
while line = f.gets
|
|
76
|
+
case line
|
|
77
|
+
when /\A\#@\#/ # preprocessor comment
|
|
78
|
+
;
|
|
79
|
+
when /\A\#@todo/i
|
|
80
|
+
@buf.push line.gsub(/\A#/, '') if current_cond
|
|
81
|
+
when /\A\#@include\s*\((.*?)\)/
|
|
82
|
+
next unless current_cond
|
|
83
|
+
begin
|
|
84
|
+
file = $1.strip
|
|
85
|
+
basedir = File.dirname(line.location.file)
|
|
86
|
+
@buf.concat Preprocessor.process("#{basedir}/#{file}", @params)
|
|
87
|
+
rescue Errno::ENOENT => err
|
|
88
|
+
raise WrongInclude, "#{line.location}: \#@include'ed file not exist: #{file}"
|
|
89
|
+
end
|
|
90
|
+
when /\A\#@since\b/
|
|
91
|
+
cond_stmt_begin line, build_cond_by_value(line, 'version >=')
|
|
92
|
+
when /\A\#@until\b/
|
|
93
|
+
cond_stmt_begin line, build_cond_by_value(line, 'version <')
|
|
94
|
+
when /\A\#@if\b/
|
|
95
|
+
cond_stmt_begin line, line.sub(/\A\#@if/, '').strip
|
|
96
|
+
when /\A\#@else\s*\z/
|
|
97
|
+
parse_error "no matching #@if", line if cond_toplevel?
|
|
98
|
+
cond_invert
|
|
99
|
+
when /\A\#@end\s*\z/
|
|
100
|
+
parse_error "no matching #@if", line if cond_toplevel?
|
|
101
|
+
cond_pop
|
|
102
|
+
when /\A\#@/
|
|
103
|
+
parse_error "unknown preprocessor directive", line
|
|
104
|
+
else
|
|
105
|
+
if current_cond
|
|
106
|
+
@buf.push line
|
|
107
|
+
break
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
if @buf.empty?
|
|
112
|
+
unless cond_toplevel?
|
|
113
|
+
parse_error "unterminated \#@if", @last_if
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
@buf.shift
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def cond_stmt_begin(line, cond)
|
|
120
|
+
@last_if = line
|
|
121
|
+
begin
|
|
122
|
+
cond_push eval_cond(cond)
|
|
123
|
+
rescue ScanError => err
|
|
124
|
+
parse_error err.message, line
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def build_cond_by_value(line, left)
|
|
129
|
+
case ver = line.sub(/\A\#@\w+/, '').strip
|
|
130
|
+
when /\A[\d\.]+\z/
|
|
131
|
+
%Q(#{left} "#{ver}")
|
|
132
|
+
when /\A"[\d\.]+"\z/
|
|
133
|
+
"#{left} #{ver}"
|
|
134
|
+
else
|
|
135
|
+
parse_error "wrong conditional expr", line
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def current_cond
|
|
140
|
+
@cond_stack.last
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def cond_init
|
|
144
|
+
@cond_stack = [true]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def cond_toplevel?
|
|
148
|
+
@cond_stack.size == 1
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def cond_push(bool)
|
|
152
|
+
@cond_stack.push(@cond_stack.last && bool)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def cond_invert
|
|
156
|
+
b = @cond_stack.pop
|
|
157
|
+
@cond_stack.push(!b && @cond_stack.last)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def cond_pop
|
|
161
|
+
@cond_stack.pop
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def eval_cond(str)
|
|
165
|
+
s = StringScanner.new(str)
|
|
166
|
+
result = eval_expr(s) ? true : false
|
|
167
|
+
unless s.eos?
|
|
168
|
+
scan_error "parse error at: #{s.inspect}"
|
|
169
|
+
end
|
|
170
|
+
result
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def eval_expr(s)
|
|
174
|
+
paren_open = s.scan(/\s*\(/)
|
|
175
|
+
val = eval_expr_p(s)
|
|
176
|
+
while conj = read_conj(s)
|
|
177
|
+
case conj
|
|
178
|
+
when 'and'
|
|
179
|
+
val = eval_expr_p(s) && val
|
|
180
|
+
when 'or'
|
|
181
|
+
val = eval_expr_p(s) || val
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
if paren_open
|
|
185
|
+
unless s.skip(/\s*\)/)
|
|
186
|
+
scan_error "paren opened but not closed"
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
val
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def eval_expr_p(s)
|
|
193
|
+
val = eval_primary(s)
|
|
194
|
+
while op = read_op(s)
|
|
195
|
+
if op == '!='
|
|
196
|
+
val = (val != eval_primary(s))
|
|
197
|
+
else
|
|
198
|
+
val = val.__send__(op, eval_primary(s))
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
val
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def read_conj(s)
|
|
205
|
+
s.skip(/\s+/)
|
|
206
|
+
s.scan(/and|or/)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def read_op(s)
|
|
210
|
+
s.skip(/\s+/)
|
|
211
|
+
s.scan(/>=|<=|==|<|>|!=/)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def eval_primary(s)
|
|
215
|
+
s.skip(/\s+/)
|
|
216
|
+
if t = s.scan(/\w+/)
|
|
217
|
+
unless @params.key?(t)
|
|
218
|
+
scan_error "database property `#{t}' not exist"
|
|
219
|
+
end
|
|
220
|
+
@params[t]
|
|
221
|
+
elsif t = s.scan(/".*?"/)
|
|
222
|
+
eval(t)
|
|
223
|
+
elsif t = s.scan(/'.*?'/)
|
|
224
|
+
eval(t)
|
|
225
|
+
elsif t = s.scan(/\d+/)
|
|
226
|
+
t.to_i
|
|
227
|
+
else
|
|
228
|
+
scan_error "parse error at: #{s.inspect}"
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def scan_error(msg)
|
|
233
|
+
raise ScanError, msg
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class LineCollector < LineFilter
|
|
240
|
+
|
|
241
|
+
def LineCollector.process(path)
|
|
242
|
+
fopen(path) {|f|
|
|
243
|
+
return wrap(f).to_a
|
|
244
|
+
}
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def LineCollector.wrap(f)
|
|
248
|
+
new(LineStream.new(f))
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
private
|
|
252
|
+
|
|
253
|
+
def next_line(f)
|
|
254
|
+
while line = f.gets
|
|
255
|
+
if /\A\#@include\s*\((.*?)\)/ =~ line
|
|
256
|
+
begin
|
|
257
|
+
file = $1.strip
|
|
258
|
+
basedir = File.dirname(line.location.file)
|
|
259
|
+
@buf.concat LineCollector.process("#{basedir}/#{file}")
|
|
260
|
+
rescue Errno::ENOENT => err
|
|
261
|
+
raise WrongInclude, "#{line.location}: \#@include'ed file not exist: #{file}"
|
|
262
|
+
end
|
|
263
|
+
else
|
|
264
|
+
@buf.push line
|
|
265
|
+
end
|
|
266
|
+
break unless @buf.empty?
|
|
267
|
+
end
|
|
268
|
+
@buf.shift
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
end
|
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
#
|
|
2
|
+
# bitclust/rdcompiler.rb
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2006-2008 Minero Aoki
|
|
5
|
+
#
|
|
6
|
+
# This program is free software.
|
|
7
|
+
# You can distribute/modify this program under the Ruby License.
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
require 'bitclust/methodsignature'
|
|
11
|
+
require 'bitclust/lineinput'
|
|
12
|
+
require 'bitclust/htmlutils'
|
|
13
|
+
require 'bitclust/textutils'
|
|
14
|
+
require 'stringio'
|
|
15
|
+
|
|
16
|
+
module BitClust
|
|
17
|
+
|
|
18
|
+
class RDCompiler
|
|
19
|
+
|
|
20
|
+
include HTMLUtils
|
|
21
|
+
include TextUtils
|
|
22
|
+
|
|
23
|
+
def initialize(urlmapper, hlevel = 1, opt = {})
|
|
24
|
+
@urlmapper = urlmapper
|
|
25
|
+
@catalog = opt[:catalog]
|
|
26
|
+
@hlevel = hlevel
|
|
27
|
+
@type = nil
|
|
28
|
+
@library = nil
|
|
29
|
+
@class = nil
|
|
30
|
+
@method = nil
|
|
31
|
+
@option = opt.dup
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def compile(src)
|
|
35
|
+
setup(src) {
|
|
36
|
+
library_file
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# FIXME
|
|
41
|
+
def compile_method(m, opt = nil)
|
|
42
|
+
@opt = opt
|
|
43
|
+
@type = :method
|
|
44
|
+
@method = m
|
|
45
|
+
setup(m.source) {
|
|
46
|
+
method_entry
|
|
47
|
+
}
|
|
48
|
+
ensure
|
|
49
|
+
@opt = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def setup(src)
|
|
55
|
+
@f = LineInput.new(StringIO.new(src))
|
|
56
|
+
@out = StringIO.new
|
|
57
|
+
yield
|
|
58
|
+
@out.string
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def library_file
|
|
62
|
+
while @f.next?
|
|
63
|
+
case @f.peek
|
|
64
|
+
when /\A---/
|
|
65
|
+
method_entry_chunk
|
|
66
|
+
when /\A=+/
|
|
67
|
+
headline @f.gets
|
|
68
|
+
when /\A\s+\*\s/
|
|
69
|
+
ulist
|
|
70
|
+
when /\A\s+\(\d+\)\s/
|
|
71
|
+
olist
|
|
72
|
+
when %r<\A//emlist\{>
|
|
73
|
+
emlist
|
|
74
|
+
when /\A:\s/
|
|
75
|
+
dlist
|
|
76
|
+
when /\A\s+\S/
|
|
77
|
+
list
|
|
78
|
+
else
|
|
79
|
+
if @f.peek.strip.empty?
|
|
80
|
+
@f.gets
|
|
81
|
+
else
|
|
82
|
+
paragraph
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def method_entry
|
|
89
|
+
while @f.next?
|
|
90
|
+
method_entry_chunk
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def method_entry_chunk
|
|
95
|
+
@out.puts '<dl>' if @option[:force]
|
|
96
|
+
@f.while_match(/\A---/) do |line|
|
|
97
|
+
method_signature line
|
|
98
|
+
end
|
|
99
|
+
props = {}
|
|
100
|
+
@f.while_match(/\A:/) do |line|
|
|
101
|
+
k, v = line.sub(/\A:/, '').split(':', 2)
|
|
102
|
+
props[k.strip] = v.strip
|
|
103
|
+
end
|
|
104
|
+
@out.puts '<dd class="method-description">'
|
|
105
|
+
while @f.next?
|
|
106
|
+
case @f.peek
|
|
107
|
+
when /\A===+/
|
|
108
|
+
headline @f.gets
|
|
109
|
+
when /\A==?/
|
|
110
|
+
if @option[:force]
|
|
111
|
+
break
|
|
112
|
+
else
|
|
113
|
+
raise "method entry includes headline: #{@f.peek.inspect}"
|
|
114
|
+
end
|
|
115
|
+
when /\A---/
|
|
116
|
+
break
|
|
117
|
+
when /\A\s+\*\s/
|
|
118
|
+
ulist
|
|
119
|
+
when /\A\s+\(\d+\)\s/
|
|
120
|
+
olist
|
|
121
|
+
when /\A:\s/
|
|
122
|
+
dlist
|
|
123
|
+
when %r<\A//emlist\{>
|
|
124
|
+
emlist
|
|
125
|
+
when /\A\s+\S/
|
|
126
|
+
list
|
|
127
|
+
when /@see/
|
|
128
|
+
see
|
|
129
|
+
when /@todo/
|
|
130
|
+
todo
|
|
131
|
+
when /\A@[a-z]/
|
|
132
|
+
method_info
|
|
133
|
+
else
|
|
134
|
+
if @f.peek.strip.empty?
|
|
135
|
+
@f.gets
|
|
136
|
+
else
|
|
137
|
+
method_entry_paragraph
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
@out.puts '</dd>'
|
|
142
|
+
@out.puts '</dl>' if @option[:force]
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def headline(line)
|
|
146
|
+
level = @hlevel + (line.slice(/\A=+/).size - 3)
|
|
147
|
+
label = line.sub(/\A=+(\[a:(.*?)\])?/, '').strip
|
|
148
|
+
frag = $2 if $2 and not $2.empty?
|
|
149
|
+
line h(level, escape_html(label), frag)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def h(level, label, frag = nil)
|
|
153
|
+
name = frag ? "id='#{escape_html(frag)}'" : ""
|
|
154
|
+
"<h#{level} #{name}>#{label}</h#{level}>"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def ulist
|
|
158
|
+
@out.puts '<ul>'
|
|
159
|
+
@f.while_match(/\A\s+\*\s/) do |line|
|
|
160
|
+
string '<li>'
|
|
161
|
+
string compile_text(line.sub(/\A\s+\*/, '').strip)
|
|
162
|
+
@f.while_match(/\A\s+[^\*\s]/) do |cont|
|
|
163
|
+
nl
|
|
164
|
+
string compile_text(cont.strip)
|
|
165
|
+
end
|
|
166
|
+
line '</li>'
|
|
167
|
+
end
|
|
168
|
+
line '</ul>'
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def olist
|
|
172
|
+
@out.puts '<ol>'
|
|
173
|
+
@f.while_match(/\A\s+\(\d+\)/) do |line|
|
|
174
|
+
string '<li>'
|
|
175
|
+
string compile_text(line.sub(/\A\s+\(\d+\)/, '').strip)
|
|
176
|
+
@f.while_match(/\A\s+(?!\(\d+\))\S/) do |cont|
|
|
177
|
+
string "\n"
|
|
178
|
+
string compile_text(cont.strip)
|
|
179
|
+
end
|
|
180
|
+
line '</li>'
|
|
181
|
+
end
|
|
182
|
+
line '</ol>'
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def dlist
|
|
186
|
+
line '<dl>'
|
|
187
|
+
while @f.next? and /\A:/ =~ @f.peek
|
|
188
|
+
@f.while_match(/\A:/) do |line|
|
|
189
|
+
line dt(compile_text(line.sub(/\A:/, '').strip))
|
|
190
|
+
end
|
|
191
|
+
dd_with_p
|
|
192
|
+
end
|
|
193
|
+
line '</dl>'
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# empty lines separate paragraphs.
|
|
197
|
+
def dd_with_p
|
|
198
|
+
line '<dd>'
|
|
199
|
+
while /\A(?:\s|\z)/ =~ @f.peek or %r!\A//emlist\{! =~ @f.peek
|
|
200
|
+
case @f.peek
|
|
201
|
+
when /\A$/
|
|
202
|
+
@f.gets
|
|
203
|
+
when /\A[ \t\z]/
|
|
204
|
+
line '<p>'
|
|
205
|
+
@f.while_match(/\A[ \t\z]/) do |line|
|
|
206
|
+
line compile_text(line.strip)
|
|
207
|
+
end
|
|
208
|
+
line '</p>'
|
|
209
|
+
when %r!\A//emlist\{!
|
|
210
|
+
emlist
|
|
211
|
+
else
|
|
212
|
+
raise 'must not happen'
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
line '</dd>'
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# empty lines do not separate paragraphs.
|
|
219
|
+
def dd_without_p
|
|
220
|
+
line '<dd>'
|
|
221
|
+
while /\A[ \t]/ =~ @f.peek or %r!\A//emlist\{! =~ @f.peek
|
|
222
|
+
case @f.peek
|
|
223
|
+
when /\A[ \t\z]/
|
|
224
|
+
@f.while_match(/\A[ \t\z]/) do |line|
|
|
225
|
+
line compile_text(line.strip)
|
|
226
|
+
end
|
|
227
|
+
when %r!\A//emlist\{!
|
|
228
|
+
emlist
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
line '</dd>'
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def dt(s)
|
|
235
|
+
"<dt>#{s}</dt>"
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def emlist
|
|
239
|
+
@f.gets # discard "//emlist{"
|
|
240
|
+
line '<pre>'
|
|
241
|
+
@f.until_terminator(%r<\A//\}>) do |line|
|
|
242
|
+
line escape_html(line.rstrip)
|
|
243
|
+
end
|
|
244
|
+
line '</pre>'
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def list
|
|
248
|
+
lines = unindent_block(canonicalize(@f.break(/\A\S/)))
|
|
249
|
+
while lines.last.empty?
|
|
250
|
+
lines.pop
|
|
251
|
+
end
|
|
252
|
+
line '<pre>'
|
|
253
|
+
lines.each do |line|
|
|
254
|
+
line escape_html(line)
|
|
255
|
+
end
|
|
256
|
+
line '</pre>'
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def canonicalize(lines)
|
|
260
|
+
lines.map {|line| detab(line.rstrip) }
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def paragraph
|
|
264
|
+
line '<p>'
|
|
265
|
+
read_paragraph(@f).each do |line|
|
|
266
|
+
line compile_text(line.strip)
|
|
267
|
+
end
|
|
268
|
+
line '</p>'
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def read_paragraph(f)
|
|
272
|
+
f.span(%r<\A(?!---|=|//emlist\{)\S>)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def see
|
|
276
|
+
header = @f.gets
|
|
277
|
+
cmd = header.slice!(/\A\@\w+/)
|
|
278
|
+
body = [header] + @f.span(/\A\s+\S/)
|
|
279
|
+
line '<p>'
|
|
280
|
+
line '[SEE_ALSO] ' + compile_text(body.join('').strip)
|
|
281
|
+
line '</p>'
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def todo
|
|
285
|
+
header = @f.gets
|
|
286
|
+
cmd = header.slice!(/\A\@\w+/)
|
|
287
|
+
body = header
|
|
288
|
+
line '<p class="todo">'
|
|
289
|
+
line '[TODO]' + body
|
|
290
|
+
line '</p>'
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def method_info
|
|
294
|
+
line '<dl>'
|
|
295
|
+
while @f.next? and /\A\@(?!see)\w+|\A$/ =~ @f.peek
|
|
296
|
+
header = @f.gets
|
|
297
|
+
next if /\A$/ =~ header
|
|
298
|
+
cmd = header.slice!(/\A\@\w+/)
|
|
299
|
+
@f.ungets(header)
|
|
300
|
+
case cmd
|
|
301
|
+
when '@param', '@arg'
|
|
302
|
+
name = header.slice!(/\A\s*\w+/) || '?'
|
|
303
|
+
line "<dt class='method-param'>[PARAM] #{escape_html(name.strip)}:</dt>"
|
|
304
|
+
when '@raise'
|
|
305
|
+
ex = header.slice!(/\A\s*[\w:]+/) || '?'
|
|
306
|
+
line "<dt>[EXCEPTION] #{escape_html(ex.strip)}:</dt>"
|
|
307
|
+
when '@return'
|
|
308
|
+
line "<dt>[RETURN]</dt>"
|
|
309
|
+
else
|
|
310
|
+
line "<dt>[UNKNOWN_META_INFO] #{escape_html(cmd)}:</dt>"
|
|
311
|
+
end
|
|
312
|
+
dd_without_p
|
|
313
|
+
end
|
|
314
|
+
line '</dl>'
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# FIXME: parse @param, @return, ...
|
|
318
|
+
def method_entry_paragraph
|
|
319
|
+
line '<p>'
|
|
320
|
+
read_method_entry_paragraph(@f).each do |line|
|
|
321
|
+
line compile_text(line.strip)
|
|
322
|
+
end
|
|
323
|
+
line '</p>'
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def read_method_entry_paragraph(f)
|
|
327
|
+
f.span(%r<\A(?!---|=|//emlist\{|@[a-z])\S>)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def method_signature(sig_line)
|
|
331
|
+
# FIXME: check parameters, types, etc.
|
|
332
|
+
sig = MethodSignature.parse(sig_line)
|
|
333
|
+
string '<dt class="method-heading"><code>'
|
|
334
|
+
string @method.klass.name + @method.typemark if @opt
|
|
335
|
+
string escape_html(sig.friendly_string)
|
|
336
|
+
string '</code>'
|
|
337
|
+
if @method and not @method.defined?
|
|
338
|
+
line %Q( <span class="kindinfo">[#{@method.kind} by #{library_link(@method.library.name)}]</span>)
|
|
339
|
+
end
|
|
340
|
+
line '</dt>'
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
BracketLink = /\[\[[\w-]+?:[!-~]+?(?:\[\] )?\]\]/n
|
|
344
|
+
NeedESC = /[&"<>]/
|
|
345
|
+
|
|
346
|
+
def compile_text(str)
|
|
347
|
+
escape_table = HTMLUtils::ESC
|
|
348
|
+
str.gsub(/(#{NeedESC})|(#{BracketLink})/o) {
|
|
349
|
+
if char = $1 then escape_table[char]
|
|
350
|
+
elsif tok = $2 then bracket_link(tok[2..-3])
|
|
351
|
+
elsif tok = $3 then seems_code(tok)
|
|
352
|
+
else
|
|
353
|
+
raise 'must not happen'
|
|
354
|
+
end
|
|
355
|
+
}
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def bracket_link(link, label = nil, frag = nil)
|
|
359
|
+
type, _arg = link.split(':', 2)
|
|
360
|
+
arg = _arg.rstrip
|
|
361
|
+
case type
|
|
362
|
+
when 'lib'
|
|
363
|
+
then protect(link) {
|
|
364
|
+
case arg
|
|
365
|
+
when '/', '_index'
|
|
366
|
+
label = 'All libraries'
|
|
367
|
+
when '_builtin'
|
|
368
|
+
label = 'Builtin libraries'
|
|
369
|
+
end
|
|
370
|
+
library_link(arg, label, frag)
|
|
371
|
+
}
|
|
372
|
+
when 'c' then protect(link) { class_link(arg, label, frag) }
|
|
373
|
+
when 'm' then protect(link) { method_link(complete_spec(arg), label || arg, frag) }
|
|
374
|
+
when 'f'
|
|
375
|
+
then protect(link) {
|
|
376
|
+
case arg
|
|
377
|
+
when '/', '_index'
|
|
378
|
+
arg, label = '', 'All C API'
|
|
379
|
+
end
|
|
380
|
+
function_link(arg, label || arg, frag)
|
|
381
|
+
}
|
|
382
|
+
when 'd' then protect(link) { document_link(arg, label, frag) }
|
|
383
|
+
when 'ref' then protect(link) { reference_link(arg) }
|
|
384
|
+
when 'url' then direct_url(arg)
|
|
385
|
+
when 'man' then man_link(arg)
|
|
386
|
+
when 'rfc', 'RFC'
|
|
387
|
+
rfc_link(arg)
|
|
388
|
+
when 'ruby-list', 'ruby-dev', 'ruby-ext', 'ruby-talk', 'ruby-core'
|
|
389
|
+
blade_link(type, arg)
|
|
390
|
+
else
|
|
391
|
+
"[[#{escape_html(link)}]]"
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
def protect(src)
|
|
396
|
+
yield
|
|
397
|
+
rescue => err
|
|
398
|
+
%Q(<span class="compileerror">[[compile error: #{escape_html(err.message)}: #{escape_html(src)}]]</span>)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def direct_url(url)
|
|
402
|
+
%Q(<a class="external" href="#{escape_html(url)}">#{escape_html(url)}</a>)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def reference_link(arg)
|
|
406
|
+
case arg
|
|
407
|
+
when /(\w+):(.*)\#(\w+)\z/
|
|
408
|
+
type, name, frag = $1, $2, $3
|
|
409
|
+
case type
|
|
410
|
+
when 'lib'
|
|
411
|
+
title, t, id = name, LibraryEntry.type_id.to_s, name
|
|
412
|
+
when 'c'
|
|
413
|
+
title, t, id = name, ClassEntry.type_id.to_s, name
|
|
414
|
+
when 'm'
|
|
415
|
+
title, t, id = name, MethodEntry.type_id.to_s, name
|
|
416
|
+
when 'd'
|
|
417
|
+
title, t, id = @option[:database].get_doc(name).title, DocEntry.type_id.to_s, name
|
|
418
|
+
else
|
|
419
|
+
raise "must not happen"
|
|
420
|
+
end
|
|
421
|
+
label = @option[:database].refs[t, id, frag]
|
|
422
|
+
label = title + '/' + label if label and name
|
|
423
|
+
bracket_link("#{type}:#{name}", label, frag)
|
|
424
|
+
when /\A(\w+)\z/
|
|
425
|
+
e = @option[:entry]
|
|
426
|
+
frag = $1
|
|
427
|
+
type = e.type_id.to_s
|
|
428
|
+
label = @option[:database].refs[type, e.name, frag] || frag
|
|
429
|
+
a_href('#' + frag, label)
|
|
430
|
+
else
|
|
431
|
+
raise "must not happen"
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
BLADE_URL = 'http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/%s/%s'
|
|
436
|
+
|
|
437
|
+
def blade_link(ml, num)
|
|
438
|
+
url = sprintf(BLADE_URL, ml, num)
|
|
439
|
+
%Q(<a class="external" href="#{escape_html(url)}">[#{escape_html("#{ml}:#{num}")}]</a>)
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
RFC_URL = 'http://www.ietf.org/rfc/rfc%s.txt'
|
|
443
|
+
|
|
444
|
+
def rfc_link(num)
|
|
445
|
+
url = sprintf(RFC_URL, num)
|
|
446
|
+
%Q(<a class="external" href="#{escape_html(url)}">[RFC#{escape_html(num)}]</a>)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
opengroup_url = 'http://www.opengroup.org/onlinepubs/009695399'
|
|
450
|
+
MAN_CMD_URL = "#{opengroup_url}/utilities/%s.html"
|
|
451
|
+
MAN_FCN_URL = "#{opengroup_url}/functions/%s.html"
|
|
452
|
+
MAN_HEADER_URL = "#{opengroup_url}/basedefs/%s.html"
|
|
453
|
+
MAN_LINUX_URL = "http://man7.org/linux/man-pages/man%1$s/%2$s.%1$s.html"
|
|
454
|
+
MAN_FREEBSD_URL = "http://www.freebsd.org/cgi/man.cgi?query=%2$s&sektion=%1$s&manpath=FreeBSD+9.0-RELEASE"
|
|
455
|
+
|
|
456
|
+
def man_url(section, page)
|
|
457
|
+
case section
|
|
458
|
+
when "1"
|
|
459
|
+
sprintf(MAN_CMD_URL, page)
|
|
460
|
+
when "2", "3"
|
|
461
|
+
sprintf(MAN_FCN_URL, page)
|
|
462
|
+
when "header"
|
|
463
|
+
sprintf(MAN_HEADER_URL, page)
|
|
464
|
+
when /\A([23457])linux\Z/
|
|
465
|
+
sprintf(MAN_LINUX_URL, $1, page)
|
|
466
|
+
when /\A([1-9])freebsd\Z/
|
|
467
|
+
sprintf(MAN_FREEBSD_URL, $1, page)
|
|
468
|
+
else
|
|
469
|
+
nil
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
def man_link(spec)
|
|
474
|
+
m = /([\w\.\/]+)\((\w+)\)/.match(spec) or return escape_html(spec)
|
|
475
|
+
url = man_url(m[2], escape_html(m[1])) or return escape_html(spec)
|
|
476
|
+
%Q(<a class="external" href="#{escape_html(url)}">#{escape_html("#{m[1]}(#{m[2]})")}</a>)
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def complete_spec(spec0)
|
|
480
|
+
case spec0
|
|
481
|
+
when /\A\$/
|
|
482
|
+
"Kernel#{spec0}"
|
|
483
|
+
else
|
|
484
|
+
spec0
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def seems_code(text)
|
|
489
|
+
# FIXME
|
|
490
|
+
escape_html(text)
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
def string(str)
|
|
494
|
+
@out.print str
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def line(str)
|
|
498
|
+
@out.puts str
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def nl
|
|
502
|
+
@out.puts
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
end
|