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,66 @@
|
|
|
1
|
+
#
|
|
2
|
+
# bitclust/refsdatabase.rb
|
|
3
|
+
#
|
|
4
|
+
# This program is free software.
|
|
5
|
+
# You can distribute this program under the Ruby License.
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
module BitClust
|
|
9
|
+
class RefsDatabase
|
|
10
|
+
def self.load(src)
|
|
11
|
+
if src.respond_to?(:to_str)
|
|
12
|
+
buf = fopen(src.to_str, 'r:UTF-8'){|f| f.read}
|
|
13
|
+
elsif src.respond_to?(:to_io)
|
|
14
|
+
buf = src.to_io.read
|
|
15
|
+
else
|
|
16
|
+
buf = src.read
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
refs = self.new
|
|
20
|
+
buf.each_line{|l|
|
|
21
|
+
if /((?:\\,|[^,])+),((?:\\,|[^,])+),((?:\\,|[^,])+),((?:\\,|[^,])+)\n/ =~ l
|
|
22
|
+
type, id, linkid, desc = [$1, $2, $3, $4].map{|e| e.gsub(/\\(.)/){|s| $1 == ',' ? ',' : s } }
|
|
23
|
+
refs[type, id, linkid] = desc
|
|
24
|
+
end
|
|
25
|
+
}
|
|
26
|
+
refs
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize
|
|
30
|
+
@h = {}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def []=(type, mid, linkid, desc)
|
|
34
|
+
@h[[type.to_s, mid, linkid]] = desc
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def [](type, mid, linkid)
|
|
38
|
+
@h[[type.to_s, mid, linkid]]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def save(s)
|
|
42
|
+
if s.respond_to?(:to_str)
|
|
43
|
+
path = s.to_str
|
|
44
|
+
io = fopen(path, 'w:UTF-8')
|
|
45
|
+
elsif s.respond_to?(:to_io)
|
|
46
|
+
io = s.to_io
|
|
47
|
+
else
|
|
48
|
+
io = s
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
@h.each{|k, v|
|
|
52
|
+
io.write( [k, v].flatten.map{|e| e.gsub(/,/, '\\,') }.join(',') + "\n" )
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def extract(entry)
|
|
57
|
+
entry.source.each_line{|l|
|
|
58
|
+
if /\A={1,6}\[a:(\w+)\] *(.*)/ =~ l
|
|
59
|
+
entry.labels.each{|name|
|
|
60
|
+
self[entry.class.type_id, name, $1] = $2
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
#
|
|
2
|
+
# bitclust/requesthandler.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/compat'
|
|
11
|
+
require 'bitclust/screen'
|
|
12
|
+
require 'bitclust/methodid'
|
|
13
|
+
require 'bitclust/nameutils'
|
|
14
|
+
require 'bitclust/simplesearcher'
|
|
15
|
+
|
|
16
|
+
module BitClust
|
|
17
|
+
|
|
18
|
+
class RequestHandler
|
|
19
|
+
|
|
20
|
+
def initialize(db, manager)
|
|
21
|
+
if db.is_a? Array
|
|
22
|
+
@db, @cdb = db
|
|
23
|
+
else
|
|
24
|
+
@db = db
|
|
25
|
+
end
|
|
26
|
+
@screenmanager = manager
|
|
27
|
+
@conf = { :database => @db }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def handle(webrick_req)
|
|
31
|
+
_handle(Request.new(webrick_req))
|
|
32
|
+
rescue WEBrick::HTTPStatus::Status
|
|
33
|
+
raise
|
|
34
|
+
rescue BitClust::NotFoundError => err
|
|
35
|
+
return not_found_response(err)
|
|
36
|
+
rescue => err
|
|
37
|
+
return error_response(err)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def _handle(req)
|
|
43
|
+
return handle_doc(req) unless req.defined_type?
|
|
44
|
+
mid = "handle_#{req.type_id}"
|
|
45
|
+
unless respond_to?(mid, true)
|
|
46
|
+
raise RequestError, "wrong request: type_id=#{req.type_id}"
|
|
47
|
+
end
|
|
48
|
+
funcall(mid, req)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def error_response(err)
|
|
52
|
+
ErrorScreen.new(err).response
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def not_found_response(err)
|
|
56
|
+
NotFoundScreen.new(err).response
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def handle_library(req)
|
|
60
|
+
return library_index() unless req.library_name
|
|
61
|
+
lib = @db.fetch_library(req.library_name)
|
|
62
|
+
@screenmanager.library_screen(lib, @conf).response
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def handle_class(req)
|
|
66
|
+
return class_index() unless req.class_name
|
|
67
|
+
c = @db.fetch_class(req.class_name)
|
|
68
|
+
h = @conf.dup
|
|
69
|
+
h[:level] = req.ancestors_level
|
|
70
|
+
@screenmanager.class_screen(c, h).response
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def handle_method(req)
|
|
74
|
+
ms = @db.fetch_methods(req.method_spec)
|
|
75
|
+
raise MethodNotFound.new(req.method_spec.to_s) if ms.nil? || ms.empty?
|
|
76
|
+
@screenmanager.method_screen(ms, @conf).response
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def library_index
|
|
80
|
+
@screenmanager.library_index_screen(@db.libraries.sort, @conf).response
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def class_index
|
|
84
|
+
@screenmanager.class_index_screen(@db.classes.sort, @conf).response
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def handle_opensearchdescription(req)
|
|
88
|
+
@screenmanager.opensearchdescription_screen(req.full_uri, @conf).response
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def handle_search(req)
|
|
92
|
+
ret = []
|
|
93
|
+
q0 = req.query['q'] || ''
|
|
94
|
+
q = URI.unescape(q0)
|
|
95
|
+
start = Time.now.to_i
|
|
96
|
+
ret = SimpleSearcher.search_pattern(@db, q)
|
|
97
|
+
elapsed_time = Time.now.to_f - start.to_f
|
|
98
|
+
c = @conf.dup
|
|
99
|
+
c[:q] = q0
|
|
100
|
+
c[:elapsed_time] = elapsed_time
|
|
101
|
+
@screenmanager.search_screen(ret, c).response
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def handle_doc(req)
|
|
105
|
+
d = @db.fetch_doc(req.doc_name || 'index' )
|
|
106
|
+
@screenmanager.doc_screen(d, @conf).response
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def handle_function(req)
|
|
110
|
+
return function_index() unless req.function_name
|
|
111
|
+
f = @cdb.fetch_function(req.function_name)
|
|
112
|
+
@screenmanager.function_screen(f, @conf).response
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def function_index
|
|
116
|
+
@screenmanager.function_index_screen(@cdb.functions.sort, @conf).response
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class RackRequestHandler < RequestHandler
|
|
122
|
+
def handle(rack_req)
|
|
123
|
+
_handle(RackRequest.new(rack_req))
|
|
124
|
+
rescue BitClust::NotFoundError => err
|
|
125
|
+
return not_found_response(err)
|
|
126
|
+
rescue => err
|
|
127
|
+
return error_response(err)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class Request
|
|
132
|
+
|
|
133
|
+
include NameUtils
|
|
134
|
+
|
|
135
|
+
def initialize(wreq)
|
|
136
|
+
@wreq = wreq
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def library?
|
|
140
|
+
type_id() == :library
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def class?
|
|
144
|
+
type_id() == :class
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def method?
|
|
148
|
+
type_id() == :method
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def doc_name
|
|
152
|
+
name = path_info.sub(%r!\A/!, '')
|
|
153
|
+
name unless name.empty?
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def library_name
|
|
157
|
+
raise '#library_name called but not library request' unless library?
|
|
158
|
+
id = type_param()
|
|
159
|
+
return nil unless id
|
|
160
|
+
name = libid2name(id)
|
|
161
|
+
unless libname?(name)
|
|
162
|
+
raise InvalidKey, "invalid library name: #{name.inspect}"
|
|
163
|
+
end
|
|
164
|
+
name
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def class_name
|
|
168
|
+
raise '#class_name called but not class request' unless class?
|
|
169
|
+
id = type_param()
|
|
170
|
+
return nil unless id
|
|
171
|
+
name = classid2name(id)
|
|
172
|
+
unless classname?(name)
|
|
173
|
+
raise InvalidKey, "invalid class name: #{name.inspect}"
|
|
174
|
+
end
|
|
175
|
+
name
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def method_spec
|
|
179
|
+
return nil unless method?
|
|
180
|
+
param = type_param()
|
|
181
|
+
return nil unless param
|
|
182
|
+
cid, typechar, mencoded = param.split('/', 3)
|
|
183
|
+
raise InvalidKey, 'missing class name' unless cid
|
|
184
|
+
raise InvalidKey, 'missing type name' unless typechar
|
|
185
|
+
raise InvalidKey, 'missing method name' unless mencoded
|
|
186
|
+
unless typechar?(typechar)
|
|
187
|
+
raise InvalidKey, "invalid method-type ID: #{typechar.inspect}"
|
|
188
|
+
end
|
|
189
|
+
cname = classid2name(cid)
|
|
190
|
+
tmark = typechar2mark(typechar)
|
|
191
|
+
mname = decodename_url(mencoded)
|
|
192
|
+
unless classname?(cname)
|
|
193
|
+
raise InvalidKey, "invalid class name: #{cname.inspect}"
|
|
194
|
+
end
|
|
195
|
+
case tmark
|
|
196
|
+
when '$'
|
|
197
|
+
unless gvarname?('$' + mname)
|
|
198
|
+
raise InvalidKey, "invalid variable name: #{('$' + mname).inspect}"
|
|
199
|
+
end
|
|
200
|
+
when '.', '#', '.#', '::'
|
|
201
|
+
unless methodname?(mname)
|
|
202
|
+
raise InvalidKey, "invalid method name: #{mname.inspect}"
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
MethodSpec.new(cname, tmark, mname)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def defined_type?
|
|
209
|
+
type, param = parse_path_info()
|
|
210
|
+
case type
|
|
211
|
+
when 'library', 'class', 'method', 'function', 'search', 'opensearchdescription'
|
|
212
|
+
true
|
|
213
|
+
else
|
|
214
|
+
false
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def type_id
|
|
219
|
+
type, param = parse_path_info()
|
|
220
|
+
type.intern if type
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def function?
|
|
224
|
+
type_id() == :function
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def function_name
|
|
228
|
+
raise '#function_name called but not function request' unless function?
|
|
229
|
+
id = type_param()
|
|
230
|
+
return nil unless id
|
|
231
|
+
name = id
|
|
232
|
+
unless functionname?(name)
|
|
233
|
+
raise InvalidKey, "invalid function name: #{name.inspect}"
|
|
234
|
+
end
|
|
235
|
+
name
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def ancestors_level
|
|
239
|
+
ret = query['a'].to_i
|
|
240
|
+
if ret < 0
|
|
241
|
+
0
|
|
242
|
+
else
|
|
243
|
+
ret
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def query
|
|
248
|
+
@wreq.query
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def full_uri
|
|
252
|
+
@wreq.request_uri
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
private
|
|
256
|
+
|
|
257
|
+
def type_param
|
|
258
|
+
type, param = parse_path_info()
|
|
259
|
+
return nil unless param
|
|
260
|
+
return nil if param.empty?
|
|
261
|
+
param
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def parse_path_info
|
|
265
|
+
return nil unless path_info
|
|
266
|
+
_, type, param = path_info.split('/', 3)
|
|
267
|
+
param = nil if not param or param.empty?
|
|
268
|
+
return type, param
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def path_info
|
|
272
|
+
@wreq.path_info
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
class RackRequest < Request
|
|
278
|
+
|
|
279
|
+
def initialize(rack_req)
|
|
280
|
+
@rack_req = rack_req
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def query
|
|
284
|
+
@rack_req.params
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def path_info
|
|
288
|
+
@rack_req.env["PATH_INFO"]
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def full_uri
|
|
292
|
+
URI.parse(@rack_req.url)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
class Screen # reopen
|
|
297
|
+
def response
|
|
298
|
+
Response.new(self)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class Response
|
|
304
|
+
|
|
305
|
+
def initialize(screen)
|
|
306
|
+
@screen = screen
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def update(webrick_res)
|
|
310
|
+
webrick_res.status = @screen.status if @screen.status
|
|
311
|
+
webrick_res['Content-Type'] = @screen.content_type
|
|
312
|
+
# webrick_res['Last-Modified'] = @screen.last_modified
|
|
313
|
+
body = @screen.body
|
|
314
|
+
webrick_res['Content-Length'] = body.bytesize
|
|
315
|
+
webrick_res.body = body
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def rack_finish
|
|
319
|
+
[
|
|
320
|
+
@screen.status || 200,
|
|
321
|
+
{
|
|
322
|
+
'Content-Type' => @screen.content_type,
|
|
323
|
+
},
|
|
324
|
+
@screen.body
|
|
325
|
+
]
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
end
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
require 'rdoc/ri/ri_reader'
|
|
2
|
+
require 'rdoc/ri/ri_cache'
|
|
3
|
+
require 'rdoc/ri/ri_paths'
|
|
4
|
+
|
|
5
|
+
class ApplicationError < StandardError; end
|
|
6
|
+
class RiClassNotFound < ApplicationError; end
|
|
7
|
+
|
|
8
|
+
class RiDatabase
|
|
9
|
+
def RiDatabase.open_system_db
|
|
10
|
+
new(RI::Paths.path(true, false, false, false), RUBY_VERSION)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def RiDatabase.open(dir, version)
|
|
14
|
+
new(RI::Paths.path(false, false, false, false, dir), version)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize(ripath, version)
|
|
18
|
+
@ripath = ripath
|
|
19
|
+
@reader = RI::RiReader.new(RI::RiCache.new(@ripath))
|
|
20
|
+
@version = version
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :version
|
|
24
|
+
|
|
25
|
+
def get_method(m)
|
|
26
|
+
@reader.get_method(m)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def current_class=(name)
|
|
30
|
+
@klass = lookup_class(name)
|
|
31
|
+
@singleton_methods = wrap_entries(@reader.singleton_methods(@klass))
|
|
32
|
+
@instance_methods = wrap_entries(@reader.instance_methods(@klass))
|
|
33
|
+
rescue RiClassNotFound
|
|
34
|
+
@klass = nil
|
|
35
|
+
@singleton_methods = []
|
|
36
|
+
@instance_methods = []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
attr_reader :class
|
|
40
|
+
attr_reader :singleton_methods
|
|
41
|
+
attr_reader :instance_methods
|
|
42
|
+
|
|
43
|
+
def lookup_class(name)
|
|
44
|
+
ns = @reader.top_level_namespace.first
|
|
45
|
+
name.split('::').each do |const|
|
|
46
|
+
ns = ns.contained_class_named(const) or
|
|
47
|
+
raise RiClassNotFound, "no such class in RDoc database: #{name}"
|
|
48
|
+
end
|
|
49
|
+
ns
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def wrap_entries(ents)
|
|
55
|
+
ents.map {|m|
|
|
56
|
+
[RiMethodEntry.new(m.name, m)] +
|
|
57
|
+
m.aliases.map {|a| RiMethodEntry.new(a.name, m) }
|
|
58
|
+
}.flatten.uniq
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class Ent
|
|
63
|
+
def initialize(name, ent)
|
|
64
|
+
@name = name
|
|
65
|
+
@entry = ent
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
attr_reader :name
|
|
69
|
+
attr_reader :entry
|
|
70
|
+
|
|
71
|
+
def ==(other)
|
|
72
|
+
@name == other.name
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
alias eql? ==
|
|
76
|
+
|
|
77
|
+
def hash
|
|
78
|
+
@name.hash
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def <=>(other)
|
|
82
|
+
@name <=> other.name
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class BCMethodEntry < Ent
|
|
87
|
+
def bitclust?
|
|
88
|
+
true
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def inspect
|
|
92
|
+
"\#<BitClust #{@name} #{@entry.inspect}>"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def fullname
|
|
96
|
+
"#{@entry.klass.name}#{@entry.typemark}#{@name}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def id
|
|
100
|
+
if @entry.defined?
|
|
101
|
+
fullname()
|
|
102
|
+
else
|
|
103
|
+
"#{fullname()}.#{@entry.library.name}"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class RiMethodEntry < Ent
|
|
109
|
+
def bitclust?
|
|
110
|
+
false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def inspect
|
|
114
|
+
"\#<RDoc #{@name} #{@entry.fullname}>"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def singleton_method?
|
|
118
|
+
@entry.singleton_method?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def fullname
|
|
122
|
+
c, t, m = @entry.fullname.split(/([\.\#])/, 2)
|
|
123
|
+
"#{c}#{t}#{@name}"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
module RI
|
|
129
|
+
|
|
130
|
+
class RiReader # reopen
|
|
131
|
+
def singleton_methods(c)
|
|
132
|
+
c.singleton_methods.map {|ent| get_method(ent) }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def instance_methods(c)
|
|
136
|
+
c.instance_methods.map {|ent| get_method(ent) }
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class ClassEntry # reopen
|
|
141
|
+
def singleton_methods
|
|
142
|
+
@class_methods
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
attr_reader :instance_methods
|
|
146
|
+
|
|
147
|
+
def method_entries
|
|
148
|
+
@class_methods.sort_by {|m| m.name } +
|
|
149
|
+
@instance_methods.sort_by {|m| m.name }
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
class MethodEntry # reopen
|
|
154
|
+
def fullname
|
|
155
|
+
"#{@in_class.full_name}#{@is_class_method ? '.' : '#'}#{@name}"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def singleton_method?
|
|
159
|
+
@is_class_method
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
class MethodDescription # reopen
|
|
164
|
+
def fullname
|
|
165
|
+
name = full_name()
|
|
166
|
+
unless /\#/ =~ name
|
|
167
|
+
components = name.split('::')
|
|
168
|
+
m = components.pop
|
|
169
|
+
components.join('::') + '.' + m
|
|
170
|
+
else
|
|
171
|
+
name
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def singleton_method?
|
|
176
|
+
@is_class_method ||= false
|
|
177
|
+
@is_class_method
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
module HTMLUtils
|
|
185
|
+
|
|
186
|
+
ESC = {
|
|
187
|
+
'&' => '&',
|
|
188
|
+
'<' => '<',
|
|
189
|
+
'>' => '>',
|
|
190
|
+
'"' => '"'
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
def escape(str)
|
|
194
|
+
t = ESC
|
|
195
|
+
str.gsub(/[&"<>]/) {|s| t[s] }
|
|
196
|
+
end
|
|
197
|
+
module_function :escape
|
|
198
|
+
|
|
199
|
+
UNESC = ESC.invert
|
|
200
|
+
UNESC[' '] = ' '
|
|
201
|
+
|
|
202
|
+
def unescape(str)
|
|
203
|
+
t = UNESC
|
|
204
|
+
str.gsub(/&\w+;/) {|s| t[s] || s }
|
|
205
|
+
end
|
|
206
|
+
module_function :unescape
|
|
207
|
+
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
class Formatter
|
|
212
|
+
|
|
213
|
+
include HTMLUtils
|
|
214
|
+
|
|
215
|
+
def method_info(m)
|
|
216
|
+
@f = StringIO.new
|
|
217
|
+
describe_method m
|
|
218
|
+
@f.string
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
private
|
|
222
|
+
|
|
223
|
+
def line(s = nil)
|
|
224
|
+
if s
|
|
225
|
+
@f.puts s
|
|
226
|
+
else
|
|
227
|
+
@f.puts
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def describe_method(m)
|
|
232
|
+
if m.params[0,1] == '('
|
|
233
|
+
line "--- #{m.full_name}#{trim_space(m.params)}"
|
|
234
|
+
else
|
|
235
|
+
m.params.lines.each do |sig|
|
|
236
|
+
line "--- #{trim_sig(sig)}\#@todo\n"
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
unless m.aliases.empty?
|
|
240
|
+
m.aliases.each do |a|
|
|
241
|
+
line "alias #{a.name}"
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
#line "\#@TODO rewrite me"
|
|
245
|
+
line
|
|
246
|
+
@f.puts format_elements(m.comment)
|
|
247
|
+
line
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def trim_space(s)
|
|
251
|
+
s.sub(/\(\s+/, '(').sub(/\s+\)/, ')').sub(/\(\)/, '')
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def trim_sig(s)
|
|
255
|
+
s = trim_space(s)
|
|
256
|
+
s.sub!(/\A[a-z]\w+\./, '')
|
|
257
|
+
s.sub!(/=>/, '->')
|
|
258
|
+
s.sub!(/(->.*)\bstr(ing)?\b/){ $1 + 'String' }
|
|
259
|
+
s.sub!(/(->.*)\bint(eger)?\b/){ $1 + 'Integer' }
|
|
260
|
+
s.sub!(/(->.*)\b(an_)?obj\b/){ $1 + 'object' }
|
|
261
|
+
s.sub!(/(->.*)\b(a_)?hash\b/){ $1 + 'Hash' }
|
|
262
|
+
s.sub!(/(->.*)\b(an_)?array\b/){ $1 + 'Array' }
|
|
263
|
+
s.sub!(/ or /, ' | ')
|
|
264
|
+
s
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def format_elements(elems)
|
|
268
|
+
return "" unless elems
|
|
269
|
+
return "" if elems.empty?
|
|
270
|
+
elems.map {|elem| format_element(elem) }.join("\n\n")
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def format_element(e)
|
|
274
|
+
case e
|
|
275
|
+
when SM::Flow::P, SM::Flow::LI
|
|
276
|
+
paragraph(e)
|
|
277
|
+
when SM::Flow::LIST
|
|
278
|
+
list(e)
|
|
279
|
+
when SM::Flow::VERB
|
|
280
|
+
verbatim(e)
|
|
281
|
+
when SM::Flow::H
|
|
282
|
+
headline(e)
|
|
283
|
+
when SM::Flow::RULE
|
|
284
|
+
;
|
|
285
|
+
else
|
|
286
|
+
raise "unkwnown markup: #{e.class}"
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def headline(e)
|
|
291
|
+
h = '==' + ('=' * e.level)
|
|
292
|
+
text = unescape(e.text)
|
|
293
|
+
"#{h} #{text}"
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def paragraph(e)
|
|
297
|
+
wrap(unescape(remove_inline(e.body)))
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def verbatim(e)
|
|
301
|
+
unescape(e.body.rstrip) #.gsub(/^/, ' ')
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def list(e)
|
|
305
|
+
case e.type
|
|
306
|
+
when SM::ListBase::BULLET
|
|
307
|
+
e.contents.map {|item| "* #{format_element(e)}" }.join("\n")
|
|
308
|
+
when SM::ListBase::NUMBER,
|
|
309
|
+
SM::ListBase::LOWERALPHA,
|
|
310
|
+
SM::ListBase::UPPERALPHA
|
|
311
|
+
num = case e.type
|
|
312
|
+
when SM::ListBase::NUMBER then '1'
|
|
313
|
+
when SM::ListBase::LOWERALPHA then 'a'
|
|
314
|
+
when SM::ListBase::UPPERALPHA then 'A'
|
|
315
|
+
end
|
|
316
|
+
e.contents.map {|item|
|
|
317
|
+
str = "#{num}. #{format_element(e)}"
|
|
318
|
+
num = num.succ
|
|
319
|
+
str
|
|
320
|
+
}.join("\n")
|
|
321
|
+
when SM::ListBase::LABELED
|
|
322
|
+
e.contents.map {|item| "#{item.label} #{format_element(e)}" }.join("\n")
|
|
323
|
+
when SM::ListBase::NOTE
|
|
324
|
+
e.contents.map {|item| "#{item.label}\t#{format_element(e)}" }.join("\n")
|
|
325
|
+
else
|
|
326
|
+
raise "unknown list type: #{e.type.inspect}"
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def remove_inline(str)
|
|
331
|
+
str.gsub(/<\/?\w+>/, '')
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def wrap(str)
|
|
335
|
+
width = 60
|
|
336
|
+
buf = ''
|
|
337
|
+
line = ''
|
|
338
|
+
str.split.each do |chunk|
|
|
339
|
+
line << chunk << ' '
|
|
340
|
+
if line.size > width
|
|
341
|
+
buf << line.strip << "\n"
|
|
342
|
+
line = ''
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
buf << line
|
|
346
|
+
buf.strip
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
end
|