rdoc 2.4.3 → 2.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rdoc might be problematic. Click here for more details.
- data.tar.gz.sig +0 -0
- data/.autotest +3 -1
- data/History.txt +68 -0
- data/LICENSE.txt +57 -0
- data/Manifest.txt +37 -19
- data/README.txt +2 -12
- data/Rakefile +12 -12
- data/bin/rdoc +4 -4
- data/lib/rdoc.rb +32 -9
- data/lib/rdoc/alias.rb +2 -2
- data/lib/rdoc/any_method.rb +108 -16
- data/lib/rdoc/attr.rb +87 -1
- data/lib/rdoc/class_module.rb +131 -5
- data/lib/rdoc/code_object.rb +28 -5
- data/lib/rdoc/constant.rb +22 -0
- data/lib/rdoc/context.rb +80 -37
- data/lib/rdoc/gauntlet.rb +48 -0
- data/lib/rdoc/generator/darkfish.rb +25 -23
- data/lib/rdoc/generator/markup.rb +6 -29
- data/lib/rdoc/generator/ri.rb +39 -189
- data/lib/rdoc/generator/template/darkfish/classpage.rhtml +17 -1
- data/lib/rdoc/generator/template/darkfish/filepage.rhtml +10 -0
- data/lib/rdoc/generator/template/darkfish/images/brick.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/brick_link.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_black.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/date.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/find.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/package.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_green.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_white_text.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_white_width.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/plugin.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/ruby.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/tag_green.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/wrench.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/wrench_orange.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/zoom.png +0 -0
- data/lib/rdoc/generator/template/darkfish/index.rhtml +2 -2
- data/lib/rdoc/generator/template/darkfish/rdoc.css +38 -33
- data/lib/rdoc/include.rb +22 -0
- data/lib/rdoc/markup.rb +10 -262
- data/lib/rdoc/markup/attribute_manager.rb +57 -50
- data/lib/rdoc/markup/blank_line.rb +19 -0
- data/lib/rdoc/markup/document.rb +72 -0
- data/lib/rdoc/markup/formatter.rb +118 -0
- data/lib/rdoc/markup/formatter_test_case.rb +341 -0
- data/lib/rdoc/markup/heading.rb +17 -0
- data/lib/rdoc/markup/inline.rb +6 -5
- data/lib/rdoc/markup/list.rb +78 -0
- data/lib/rdoc/markup/list_item.rb +83 -0
- data/lib/rdoc/markup/paragraph.rb +66 -0
- data/lib/rdoc/markup/parser.rb +528 -0
- data/lib/rdoc/markup/rule.rb +17 -0
- data/lib/rdoc/markup/to_ansi.rb +72 -0
- data/lib/rdoc/markup/to_bs.rb +74 -0
- data/lib/rdoc/markup/to_html.rb +106 -172
- data/lib/rdoc/markup/to_html_crossref.rb +10 -4
- data/lib/rdoc/markup/to_rdoc.rb +243 -0
- data/lib/rdoc/markup/to_test.rb +27 -16
- data/lib/rdoc/markup/verbatim.rb +42 -0
- data/lib/rdoc/normal_class.rb +38 -1
- data/lib/rdoc/normal_module.rb +38 -8
- data/lib/rdoc/options.rb +39 -151
- data/lib/rdoc/parser.rb +36 -18
- data/lib/rdoc/parser/c.rb +102 -109
- data/lib/rdoc/parser/ruby.rb +359 -1662
- data/lib/rdoc/parser/ruby_tools.rb +157 -0
- data/lib/rdoc/parser/simple.rb +0 -2
- data/lib/rdoc/rdoc.rb +142 -82
- data/lib/rdoc/ri.rb +10 -0
- data/lib/rdoc/ri/driver.rb +674 -444
- data/lib/rdoc/ri/formatter.rb +2 -651
- data/lib/rdoc/ri/paths.rb +70 -45
- data/lib/rdoc/ri/store.rb +248 -0
- data/lib/rdoc/ruby_lex.rb +1284 -0
- data/lib/rdoc/ruby_token.rb +416 -0
- data/lib/rdoc/single_class.rb +5 -0
- data/lib/rdoc/stats.rb +152 -83
- data/lib/rdoc/task.rb +27 -49
- data/lib/rdoc/text.rb +130 -0
- data/lib/rdoc/tokenstream.rb +28 -9
- data/lib/rdoc/top_level.rb +49 -43
- data/test/hidden.zip.txt +1 -0
- data/test/test_attribute_manager.rb +9 -16
- data/test/test_rdoc_any_method.rb +23 -0
- data/test/test_rdoc_attr.rb +40 -0
- data/test/test_rdoc_class_module.rb +100 -0
- data/test/test_rdoc_code_object.rb +18 -2
- data/test/test_rdoc_context.rb +41 -0
- data/test/test_rdoc_generator_ri.rb +56 -0
- data/test/test_rdoc_markup.rb +21 -610
- data/test/test_rdoc_markup_attribute_manager.rb +14 -17
- data/test/test_rdoc_markup_document.rb +51 -0
- data/test/test_rdoc_markup_paragraph.rb +27 -0
- data/test/test_rdoc_markup_parser.rb +1327 -0
- data/test/test_rdoc_markup_to_ansi.rb +426 -0
- data/test/test_rdoc_markup_to_bs.rb +443 -0
- data/test/test_rdoc_markup_to_html.rb +183 -18
- data/test/test_rdoc_markup_to_html_crossref.rb +1 -3
- data/test/test_rdoc_markup_to_rdoc.rb +426 -0
- data/test/test_rdoc_normal_class.rb +17 -0
- data/test/test_rdoc_normal_module.rb +6 -6
- data/test/test_rdoc_options.rb +41 -0
- data/test/test_rdoc_parser.rb +66 -13
- data/test/test_rdoc_parser_c.rb +93 -38
- data/test/test_rdoc_parser_perl.rb +2 -3
- data/test/test_rdoc_parser_ruby.rb +291 -28
- data/test/test_rdoc_parser_simple.rb +48 -0
- data/test/test_rdoc_rdoc.rb +66 -0
- data/test/test_rdoc_ri_driver.rb +752 -38
- data/test/test_rdoc_ri_paths.rb +39 -0
- data/test/test_rdoc_ri_store.rb +309 -0
- data/test/test_rdoc_text.rb +157 -0
- data/test/test_rdoc_top_level.rb +35 -9
- data/test/xref_data.rb +9 -1
- data/test/xref_test_case.rb +8 -3
- metadata +110 -38
- metadata.gz.sig +0 -0
- data/lib/rdoc/cache.rb +0 -41
- data/lib/rdoc/diagram.rb +0 -340
- data/lib/rdoc/dot.rb +0 -249
- data/lib/rdoc/markup/fragments.rb +0 -377
- data/lib/rdoc/markup/lines.rb +0 -156
- data/lib/rdoc/markup/to_flow.rb +0 -211
- data/lib/rdoc/markup/to_latex.rb +0 -328
- data/lib/rdoc/markup/to_texinfo.rb +0 -73
- data/lib/rdoc/ri/cache.rb +0 -187
- data/lib/rdoc/ri/descriptions.rb +0 -156
- data/lib/rdoc/ri/display.rb +0 -340
- data/lib/rdoc/ri/reader.rb +0 -106
- data/lib/rdoc/ri/util.rb +0 -79
- data/lib/rdoc/ri/writer.rb +0 -68
- data/test/test_rdoc_ri_attribute_formatter.rb +0 -44
- data/test/test_rdoc_ri_default_display.rb +0 -302
- data/test/test_rdoc_ri_formatter.rb +0 -320
- data/test/test_rdoc_ri_html_formatter.rb +0 -141
- data/test/test_rdoc_ri_overstrike_formatter.rb +0 -71
data/lib/rdoc/ri.rb
CHANGED
@@ -1,8 +1,18 @@
|
|
1
1
|
require 'rdoc'
|
2
2
|
|
3
|
+
##
|
4
|
+
# Namespace for the ri command line tool's implementation.
|
5
|
+
#
|
6
|
+
# See <tt>ri --help</tt> for details.
|
7
|
+
|
3
8
|
module RDoc::RI
|
4
9
|
|
10
|
+
##
|
11
|
+
# Base RI error class
|
12
|
+
|
5
13
|
class Error < RDoc::Error; end
|
6
14
|
|
7
15
|
end
|
8
16
|
|
17
|
+
require 'rdoc/ri/store'
|
18
|
+
|
data/lib/rdoc/ri/driver.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'abbrev'
|
2
2
|
require 'optparse'
|
3
|
-
require 'yaml'
|
4
3
|
|
5
4
|
begin
|
6
5
|
require 'readline'
|
@@ -9,79 +8,59 @@ end
|
|
9
8
|
|
10
9
|
require 'rdoc/ri'
|
11
10
|
require 'rdoc/ri/paths'
|
12
|
-
require 'rdoc/ri/formatter'
|
13
|
-
require 'rdoc/ri/display'
|
14
|
-
require 'fileutils'
|
15
11
|
require 'rdoc/markup'
|
16
|
-
require 'rdoc/markup/
|
12
|
+
require 'rdoc/markup/formatter'
|
13
|
+
require 'rdoc/text'
|
14
|
+
|
15
|
+
##
|
16
|
+
# For RubyGems backwards compatibility
|
17
|
+
|
18
|
+
require 'rdoc/ri/formatter'
|
19
|
+
|
20
|
+
##
|
21
|
+
# The RI driver implements the command-line ri tool.
|
22
|
+
#
|
23
|
+
# The driver supports:
|
24
|
+
# * loading RI data from:
|
25
|
+
# * Ruby's standard library
|
26
|
+
# * RubyGems
|
27
|
+
# * ~/.rdoc
|
28
|
+
# * A user-supplied directory
|
29
|
+
# * Paging output (uses RI_PAGER environment variable, PAGER environment
|
30
|
+
# variable or the less, more and pager programs)
|
31
|
+
# * Interactive mode with tab-completion
|
32
|
+
# * Abbreviated names (ri Zl shows Zlib documentation)
|
33
|
+
# * Colorized output
|
34
|
+
# * Merging output from multiple RI data sources
|
17
35
|
|
18
36
|
class RDoc::RI::Driver
|
19
37
|
|
20
38
|
##
|
21
|
-
#
|
22
|
-
# the Core Hash to this before calling any of the display methods, in order
|
23
|
-
# to give the display methods a cleaner API for accessing the data.
|
39
|
+
# Base Driver error class
|
24
40
|
|
25
|
-
class
|
41
|
+
class Error < RDoc::RI::Error; end
|
26
42
|
|
27
|
-
|
28
|
-
|
43
|
+
##
|
44
|
+
# Raised when a name isn't found in the ri data stores
|
29
45
|
|
30
|
-
|
31
|
-
case object
|
32
|
-
when Hash then
|
33
|
-
new_hash = new # Convert Hash -> OpenStructHash
|
46
|
+
class NotFoundError < Error
|
34
47
|
|
35
|
-
|
36
|
-
|
37
|
-
end
|
48
|
+
##
|
49
|
+
# Name that wasn't found
|
38
50
|
|
39
|
-
|
40
|
-
when Array then
|
41
|
-
object.map do |element|
|
42
|
-
convert element
|
43
|
-
end
|
44
|
-
else
|
45
|
-
object
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def merge_enums(other)
|
50
|
-
other.each do |k, v|
|
51
|
-
if self[k] then
|
52
|
-
case v
|
53
|
-
when Array then
|
54
|
-
# HACK dunno
|
55
|
-
if String === self[k] and self[k].empty? then
|
56
|
-
self[k] = v
|
57
|
-
else
|
58
|
-
self[k] += v
|
59
|
-
end
|
60
|
-
when Hash then
|
61
|
-
self[k].update v
|
62
|
-
else
|
63
|
-
# do nothing
|
64
|
-
end
|
65
|
-
else
|
66
|
-
self[k] = v
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
51
|
+
alias name message
|
70
52
|
|
71
|
-
def
|
72
|
-
|
53
|
+
def message # :nodoc:
|
54
|
+
"Nothing known about #{super}"
|
73
55
|
end
|
74
56
|
end
|
75
57
|
|
76
|
-
|
58
|
+
attr_accessor :stores
|
77
59
|
|
78
|
-
|
79
|
-
|
80
|
-
"Nothing known about #{super}"
|
81
|
-
end
|
82
|
-
end
|
60
|
+
##
|
61
|
+
# Controls the user of the pager vs $stdout
|
83
62
|
|
84
|
-
attr_accessor :
|
63
|
+
attr_accessor :use_stdout
|
85
64
|
|
86
65
|
##
|
87
66
|
# Default options for ri
|
@@ -90,9 +69,9 @@ class RDoc::RI::Driver
|
|
90
69
|
options = {}
|
91
70
|
options[:use_stdout] = !$stdout.tty?
|
92
71
|
options[:width] = 72
|
93
|
-
options[:formatter] = RDoc::RI::Formatter.for 'plain'
|
94
72
|
options[:interactive] = false
|
95
73
|
options[:use_cache] = true
|
74
|
+
options[:profile] = false
|
96
75
|
|
97
76
|
# By default all standard paths are used.
|
98
77
|
options[:use_system] = true
|
@@ -104,30 +83,33 @@ class RDoc::RI::Driver
|
|
104
83
|
return options
|
105
84
|
end
|
106
85
|
|
86
|
+
##
|
87
|
+
# Dump +data_path+ using pp
|
88
|
+
|
89
|
+
def self.dump data_path
|
90
|
+
require 'pp'
|
91
|
+
|
92
|
+
open data_path, 'rb' do |io|
|
93
|
+
pp Marshal.load(io.read)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
107
97
|
##
|
108
98
|
# Parses +argv+ and returns a Hash of options
|
109
99
|
|
110
|
-
def self.process_args
|
100
|
+
def self.process_args argv
|
111
101
|
options = default_options
|
112
102
|
|
113
103
|
opts = OptionParser.new do |opt|
|
104
|
+
opt.accept File do |file,|
|
105
|
+
File.readable?(file) and not File.directory?(file) and file
|
106
|
+
end
|
107
|
+
|
114
108
|
opt.program_name = File.basename $0
|
115
109
|
opt.version = RDoc::VERSION
|
116
110
|
opt.release = nil
|
117
111
|
opt.summary_indent = ' ' * 4
|
118
112
|
|
119
|
-
directories = [
|
120
|
-
RDoc::RI::Paths::SYSDIR,
|
121
|
-
RDoc::RI::Paths::SITEDIR,
|
122
|
-
RDoc::RI::Paths::HOMEDIR
|
123
|
-
]
|
124
|
-
|
125
|
-
if RDoc::RI::Paths::GEMDIRS then
|
126
|
-
Gem.path.each do |dir|
|
127
|
-
directories << "#{dir}/doc/*/ri"
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
113
|
opt.banner = <<-EOT
|
132
114
|
Usage: #{opt.program_name} [options] [names...]
|
133
115
|
|
@@ -154,9 +136,9 @@ punctuation:
|
|
154
136
|
#{opt.program_name} 'Array.[]'
|
155
137
|
#{opt.program_name} compact\\!
|
156
138
|
|
157
|
-
|
139
|
+
To see the default directories ri will search, run:
|
158
140
|
|
159
|
-
#{
|
141
|
+
#{opt.program_name} --list-doc-dirs
|
160
142
|
|
161
143
|
Specifying the --system, --site, --home, --gems or --doc-dir options will
|
162
144
|
limit ri to searching only the specified directories.
|
@@ -166,17 +148,60 @@ Options may also be set in the 'RI' environment variable.
|
|
166
148
|
|
167
149
|
opt.separator nil
|
168
150
|
opt.separator "Options:"
|
151
|
+
|
152
|
+
opt.separator nil
|
153
|
+
|
154
|
+
formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort
|
155
|
+
formatters = formatters.sort.map do |formatter|
|
156
|
+
formatter.to_s.sub('To', '').downcase
|
157
|
+
end
|
158
|
+
|
159
|
+
opt.on("--format=NAME", "-f",
|
160
|
+
"Uses the selected formatter. The default",
|
161
|
+
"formatter is bs for paged output and ansi",
|
162
|
+
"otherwise. Valid formatters are:",
|
163
|
+
formatters.join(' '), formatters) do |value|
|
164
|
+
options[:formatter] = RDoc::Markup.const_get "To#{value.capitalize}"
|
165
|
+
end
|
166
|
+
|
167
|
+
opt.separator nil
|
168
|
+
|
169
|
+
opt.on("--no-pager", "-T",
|
170
|
+
"Send output directly to stdout,",
|
171
|
+
"rather than to a pager.") do
|
172
|
+
options[:use_stdout] = true
|
173
|
+
end
|
174
|
+
|
175
|
+
opt.separator nil
|
176
|
+
|
177
|
+
opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
|
178
|
+
"Set the width of the output.") do |value|
|
179
|
+
options[:width] = value
|
180
|
+
end
|
181
|
+
|
182
|
+
opt.separator nil
|
183
|
+
|
184
|
+
opt.on("--interactive", "-i",
|
185
|
+
"In interactive mode you can repeatedly",
|
186
|
+
"look up methods with autocomplete.") do
|
187
|
+
options[:interactive] = true
|
188
|
+
end
|
189
|
+
|
190
|
+
opt.separator nil
|
191
|
+
|
192
|
+
opt.on("--[no-]profile",
|
193
|
+
"Run with the ruby profiler") do |value|
|
194
|
+
options[:profile] = value
|
195
|
+
end
|
196
|
+
|
197
|
+
opt.separator nil
|
198
|
+
opt.separator "Data source options:"
|
169
199
|
opt.separator nil
|
170
200
|
|
171
|
-
opt.on("--
|
172
|
-
|
173
|
-
"
|
174
|
-
|
175
|
-
"Use 'bs' (backspace) with most pager",
|
176
|
-
"programs. To use ANSI, either disable the",
|
177
|
-
"pager or tell the pager to allow control",
|
178
|
-
"characters.") do |value|
|
179
|
-
options[:formatter] = RDoc::RI::Formatter.for value
|
201
|
+
opt.on("--list-doc-dirs",
|
202
|
+
"List the directories from which ri will",
|
203
|
+
"source documentation on stdout and exit.") do
|
204
|
+
options[:list_doc_dirs] = true
|
180
205
|
end
|
181
206
|
|
182
207
|
opt.separator nil
|
@@ -196,21 +221,11 @@ Options may also be set in the 'RI' environment variable.
|
|
196
221
|
|
197
222
|
opt.separator nil
|
198
223
|
|
199
|
-
opt.on("--[no-]use-cache",
|
200
|
-
"Whether or not to use ri's cache.",
|
201
|
-
"True by default.") do |value|
|
202
|
-
options[:use_cache] = value
|
203
|
-
end
|
204
|
-
|
205
|
-
opt.separator nil
|
206
|
-
|
207
224
|
opt.on("--no-standard-docs",
|
208
225
|
"Do not include documentation from",
|
209
226
|
"the Ruby standard library, site_lib,",
|
210
227
|
"installed gems, or ~/.rdoc.",
|
211
|
-
"
|
212
|
-
"the options --no-system, --no-site, --no-gems,",
|
213
|
-
"and --no-home") do
|
228
|
+
"Use with --doc-dir") do
|
214
229
|
options[:use_system] = false
|
215
230
|
options[:use_site] = false
|
216
231
|
options[:use_gems] = false
|
@@ -251,38 +266,12 @@ Options may also be set in the 'RI' environment variable.
|
|
251
266
|
end
|
252
267
|
|
253
268
|
opt.separator nil
|
254
|
-
|
255
|
-
opt.on("--list-doc-dirs",
|
256
|
-
"List the directories from which ri will",
|
257
|
-
"source documentation on stdout and exit.") do
|
258
|
-
options[:list_doc_dirs] = true
|
259
|
-
end
|
260
|
-
|
261
|
-
opt.separator nil
|
262
|
-
|
263
|
-
opt.on("--no-pager", "-T",
|
264
|
-
"Send output directly to stdout,",
|
265
|
-
"rather than to a pager.") do
|
266
|
-
options[:use_stdout] = true
|
267
|
-
end
|
268
|
-
|
269
|
-
opt.on("--interactive", "-i",
|
270
|
-
"This makes ri go into interactive mode.",
|
271
|
-
"When ri is in interactive mode it will",
|
272
|
-
"allow the user to disambiguate lists of",
|
273
|
-
"methods in case multiple methods match",
|
274
|
-
"against a method search string. It also",
|
275
|
-
"will allow the user to enter in a method",
|
276
|
-
"name (with auto-completion, if readline",
|
277
|
-
"is supported) when viewing a class.") do
|
278
|
-
options[:interactive] = true
|
279
|
-
end
|
280
|
-
|
269
|
+
opt.separator "Debug options:"
|
281
270
|
opt.separator nil
|
282
271
|
|
283
|
-
opt.on("--
|
284
|
-
"
|
285
|
-
options[:
|
272
|
+
opt.on("--dump=CACHE", File,
|
273
|
+
"Dumps data from an ri cache or data file") do |value|
|
274
|
+
options[:dump_path] = value
|
286
275
|
end
|
287
276
|
end
|
288
277
|
|
@@ -292,7 +281,6 @@ Options may also be set in the 'RI' environment variable.
|
|
292
281
|
|
293
282
|
options[:names] = argv
|
294
283
|
|
295
|
-
options[:formatter] ||= RDoc::RI::Formatter.for('plain')
|
296
284
|
options[:use_stdout] ||= !$stdout.tty?
|
297
285
|
options[:use_stdout] ||= options[:interactive]
|
298
286
|
options[:width] ||= 72
|
@@ -309,308 +297,438 @@ Options may also be set in the 'RI' environment variable.
|
|
309
297
|
##
|
310
298
|
# Runs the ri command line executable using +argv+
|
311
299
|
|
312
|
-
def self.run
|
300
|
+
def self.run argv = ARGV
|
313
301
|
options = process_args argv
|
302
|
+
|
303
|
+
if options[:dump_path] then
|
304
|
+
dump options[:dump_path]
|
305
|
+
return
|
306
|
+
end
|
307
|
+
|
314
308
|
ri = new options
|
315
309
|
ri.run
|
316
310
|
end
|
317
311
|
|
318
|
-
|
312
|
+
##
|
313
|
+
# Creates a new driver using +initial_options+ from ::process_args
|
314
|
+
|
315
|
+
def initialize initial_options = {}
|
316
|
+
@paging = false
|
317
|
+
@classes = nil
|
318
|
+
|
319
319
|
options = self.class.default_options.update(initial_options)
|
320
320
|
|
321
|
+
@formatter_klass = options[:formatter]
|
322
|
+
|
323
|
+
require 'profile' if options[:profile]
|
324
|
+
|
321
325
|
@names = options[:names]
|
322
|
-
@class_cache_name = 'classes'
|
323
326
|
|
324
|
-
@doc_dirs =
|
325
|
-
|
326
|
-
options[:use_home],
|
327
|
-
options[:use_gems],
|
328
|
-
options[:extra_doc_dirs])
|
327
|
+
@doc_dirs = []
|
328
|
+
@stores = []
|
329
329
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
330
|
+
RDoc::RI::Paths.each(options[:use_system], options[:use_site],
|
331
|
+
options[:use_home], options[:use_gems],
|
332
|
+
*options[:extra_doc_dirs]) do |path, type|
|
333
|
+
@doc_dirs << path
|
334
334
|
|
335
|
-
|
336
|
-
|
335
|
+
store = RDoc::RI::Store.new path, type
|
336
|
+
store.load_cache
|
337
|
+
@stores << store
|
338
|
+
end
|
337
339
|
|
338
|
-
@
|
339
|
-
@class_cache = nil
|
340
|
+
@list_doc_dirs = options[:list_doc_dirs]
|
340
341
|
|
341
342
|
@interactive = options[:interactive]
|
342
|
-
@
|
343
|
-
options[:width],
|
344
|
-
options[:use_stdout])
|
343
|
+
@use_stdout = options[:use_stdout]
|
345
344
|
end
|
346
345
|
|
347
346
|
##
|
348
|
-
#
|
347
|
+
# Adds paths for undocumented classes +also_in+ to +out+
|
349
348
|
|
350
|
-
def
|
351
|
-
return
|
349
|
+
def add_also_in out, also_in
|
350
|
+
return if also_in.empty?
|
352
351
|
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
end
|
360
|
-
|
361
|
-
newest = map_dirs('created.rid') do |f|
|
362
|
-
File.mtime f if test ?f, f
|
363
|
-
end.max
|
364
|
-
|
365
|
-
# An up to date cache file must have been created more recently than
|
366
|
-
# the last modification of any of the documentation directories. It also
|
367
|
-
# must have been created with the same documentation directories
|
368
|
-
# as those from which ri currently is sourcing documentation.
|
369
|
-
up_to_date = (File.exist?(class_cache_file_path) and
|
370
|
-
newest and newest < File.mtime(class_cache_file_path) and
|
371
|
-
(cache_doc_dirs == @doc_dirs))
|
372
|
-
|
373
|
-
if up_to_date and @use_cache then
|
374
|
-
open class_cache_file_path, 'rb' do |fp|
|
375
|
-
begin
|
376
|
-
@class_cache = Marshal.load fp.read
|
377
|
-
rescue
|
378
|
-
#
|
379
|
-
# This shouldn't be necessary, since the up_to_date logic above
|
380
|
-
# should force the cache to be recreated when a new version of
|
381
|
-
# rdoc is installed. This seems like a worthwhile enhancement
|
382
|
-
# to ri's robustness, however.
|
383
|
-
#
|
384
|
-
$stderr.puts "Error reading the class cache; recreating the class cache!"
|
385
|
-
@class_cache = create_class_cache
|
386
|
-
end
|
387
|
-
end
|
388
|
-
else
|
389
|
-
@class_cache = create_class_cache
|
352
|
+
out << RDoc::Markup::Rule.new(1)
|
353
|
+
out << RDoc::Markup::Paragraph.new("Also found in:")
|
354
|
+
|
355
|
+
paths = RDoc::Markup::Verbatim.new
|
356
|
+
also_in.each do |store|
|
357
|
+
paths.parts.push ' ', store.friendly_path, "\n"
|
390
358
|
end
|
359
|
+
out << paths
|
360
|
+
end
|
391
361
|
|
392
|
-
|
362
|
+
##
|
363
|
+
# Adds a class header to +out+ for class +name+ which is described in
|
364
|
+
# +classes+.
|
365
|
+
|
366
|
+
def add_class out, name, classes
|
367
|
+
heading = if classes.all? { |klass| klass.module? } then
|
368
|
+
name
|
369
|
+
else
|
370
|
+
superclass = classes.map do |klass|
|
371
|
+
klass.superclass unless klass.module?
|
372
|
+
end.compact.shift || 'Object'
|
373
|
+
|
374
|
+
"#{name} < #{superclass}"
|
375
|
+
end
|
376
|
+
|
377
|
+
out << RDoc::Markup::Heading.new(1, heading)
|
378
|
+
out << RDoc::Markup::BlankLine.new
|
393
379
|
end
|
394
380
|
|
395
381
|
##
|
396
|
-
#
|
382
|
+
# Adds "(from ...)" to +out+ for +store+
|
397
383
|
|
398
|
-
def
|
399
|
-
|
384
|
+
def add_from out, store
|
385
|
+
out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
|
386
|
+
end
|
400
387
|
|
401
|
-
|
402
|
-
|
403
|
-
# we only will use the cache for future instantiations with identical
|
404
|
-
# documentation directories.
|
405
|
-
File.open @cache_doc_dirs_path, "wb" do |fp|
|
406
|
-
fp << @doc_dirs.join("\n")
|
407
|
-
end
|
408
|
-
end
|
388
|
+
##
|
389
|
+
# Adds +includes+ to +out+
|
409
390
|
|
410
|
-
|
411
|
-
|
412
|
-
populate_class_cache class_cache, classes
|
391
|
+
def add_includes out, includes
|
392
|
+
return if includes.empty?
|
413
393
|
|
414
|
-
|
394
|
+
out << RDoc::Markup::Rule.new(1)
|
395
|
+
out << RDoc::Markup::Heading.new(1, "Includes:")
|
415
396
|
|
416
|
-
|
417
|
-
|
397
|
+
includes.each do |modules, store|
|
398
|
+
if modules.length == 1 then
|
399
|
+
include = modules.first
|
400
|
+
name = include.name
|
401
|
+
path = store.friendly_path
|
402
|
+
out << RDoc::Markup::Paragraph.new("#{name} (from #{path})")
|
418
403
|
|
419
|
-
|
420
|
-
|
421
|
-
|
404
|
+
if include.comment then
|
405
|
+
out << RDoc::Markup::BlankLine.new
|
406
|
+
out << include.comment
|
407
|
+
end
|
408
|
+
else
|
409
|
+
out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
|
422
410
|
|
423
|
-
|
424
|
-
classes.each do |cdesc|
|
425
|
-
desc = read_yaml cdesc
|
426
|
-
klassname = desc["full_name"]
|
411
|
+
wout, with = modules.partition { |incl| incl.comment.empty? }
|
427
412
|
|
428
|
-
|
429
|
-
desc["display_name"] = "Class"
|
430
|
-
desc["sources"] = [cdesc]
|
431
|
-
desc["instance_method_extensions"] = []
|
432
|
-
desc["class_method_extensions"] = []
|
433
|
-
class_cache[klassname] = desc
|
434
|
-
else
|
435
|
-
klass = class_cache[klassname]
|
413
|
+
out << RDoc::Markup::BlankLine.new unless with.empty?
|
436
414
|
|
437
|
-
|
438
|
-
|
439
|
-
|
415
|
+
with.each do |incl|
|
416
|
+
out << RDoc::Markup::Paragraph.new(incl.name)
|
417
|
+
out << RDoc::Markup::BlankLine.new
|
418
|
+
out << incl.comment
|
440
419
|
end
|
441
420
|
|
442
|
-
|
443
|
-
|
421
|
+
unless wout.empty? then
|
422
|
+
verb = RDoc::Markup::Verbatim.new
|
423
|
+
|
424
|
+
wout.each do |incl|
|
425
|
+
verb.push ' ', incl.name, "\n"
|
426
|
+
end
|
427
|
+
|
428
|
+
out << verb
|
429
|
+
end
|
444
430
|
end
|
445
431
|
end
|
446
432
|
end
|
447
433
|
|
448
434
|
##
|
449
|
-
#
|
435
|
+
# Adds a list of +methods+ to +out+ with a heading of +name+
|
450
436
|
|
451
|
-
def
|
452
|
-
|
437
|
+
def add_method_list out, methods, name
|
438
|
+
return unless methods
|
439
|
+
|
440
|
+
out << RDoc::Markup::Heading.new(1, "#{name}:")
|
441
|
+
out << RDoc::Markup::BlankLine.new
|
442
|
+
|
443
|
+
out.push(*methods.map do |method|
|
444
|
+
RDoc::Markup::Verbatim.new ' ', method
|
445
|
+
end)
|
446
|
+
|
447
|
+
out << RDoc::Markup::BlankLine.new
|
453
448
|
end
|
454
449
|
|
455
450
|
##
|
456
|
-
#
|
451
|
+
# Returns ancestor classes of +klass+
|
452
|
+
|
453
|
+
def ancestors_of klass
|
454
|
+
ancestors = []
|
455
|
+
|
456
|
+
unexamined = [klass]
|
457
|
+
seen = []
|
458
|
+
|
459
|
+
loop do
|
460
|
+
break if unexamined.empty?
|
461
|
+
current = unexamined.shift
|
462
|
+
seen << current
|
463
|
+
|
464
|
+
stores = classes[current]
|
465
|
+
|
466
|
+
break unless stores and not stores.empty?
|
467
|
+
|
468
|
+
klasses = stores.map do |store|
|
469
|
+
store.ancestors[current]
|
470
|
+
end.flatten.uniq
|
457
471
|
|
458
|
-
|
459
|
-
|
472
|
+
klasses = klasses - seen
|
473
|
+
|
474
|
+
ancestors.push(*klasses)
|
475
|
+
unexamined.push(*klasses)
|
476
|
+
end
|
477
|
+
|
478
|
+
ancestors.reverse
|
460
479
|
end
|
461
480
|
|
462
481
|
##
|
463
|
-
#
|
482
|
+
# For RubyGems backwards compatibility
|
464
483
|
|
465
|
-
def
|
466
|
-
File.join @homepath, 'cache'
|
484
|
+
def class_cache # :nodoc:
|
467
485
|
end
|
468
486
|
|
469
487
|
##
|
470
|
-
#
|
471
|
-
# method in the ancestors list if it isn't in the named module.
|
488
|
+
# Hash mapping a known class or module to the stores it can be loaded from
|
472
489
|
|
473
|
-
def
|
474
|
-
|
475
|
-
method_map = display_class name
|
476
|
-
elsif name =~ /::|\#|\./ then
|
477
|
-
method = nil
|
478
|
-
klass, = parse_name name
|
490
|
+
def classes
|
491
|
+
return @classes if @classes
|
479
492
|
|
480
|
-
|
493
|
+
@classes = {}
|
481
494
|
|
482
|
-
|
483
|
-
|
495
|
+
@stores.each do |store|
|
496
|
+
store.cache[:modules].each do |mod|
|
497
|
+
# using default block causes searched-for modules to be added
|
498
|
+
@classes[mod] ||= []
|
499
|
+
@classes[mod] << store
|
500
|
+
end
|
501
|
+
end
|
484
502
|
|
485
|
-
|
486
|
-
|
503
|
+
@classes
|
504
|
+
end
|
487
505
|
|
488
|
-
|
506
|
+
##
|
507
|
+
# Completes +name+ based on the caches. For Readline
|
489
508
|
|
490
|
-
|
509
|
+
def complete name
|
510
|
+
klasses = classes.keys
|
511
|
+
completions = []
|
491
512
|
|
492
|
-
|
513
|
+
klass, selector, method = parse_name name
|
493
514
|
|
494
|
-
|
495
|
-
|
496
|
-
end
|
515
|
+
# may need to include Foo when given Foo::
|
516
|
+
klass_name = method ? name : klass
|
497
517
|
|
498
|
-
|
518
|
+
if name !~ /#|\./ then
|
519
|
+
completions.push(*klasses.grep(/^#{klass_name}/))
|
520
|
+
elsif selector then
|
521
|
+
completions << klass if classes.key? klass
|
522
|
+
elsif classes.key? klass_name then
|
523
|
+
completions << klass_name
|
524
|
+
end
|
499
525
|
|
500
|
-
|
501
|
-
|
502
|
-
methods = select_methods(/#{name}/)
|
526
|
+
if completions.include? klass and name =~ /#|\.|::/ then
|
527
|
+
methods = list_methods_matching name
|
503
528
|
|
504
|
-
if methods.
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
529
|
+
if not methods.empty? then
|
530
|
+
# remove Foo if given Foo:: and a method was found
|
531
|
+
completions.delete klass
|
532
|
+
elsif selector then
|
533
|
+
# replace Foo with Foo:: as given
|
534
|
+
completions.delete klass
|
535
|
+
completions << "#{klass}#{selector}"
|
510
536
|
end
|
537
|
+
|
538
|
+
completions.push(*methods)
|
511
539
|
end
|
540
|
+
|
541
|
+
completions.sort
|
512
542
|
end
|
513
543
|
|
514
544
|
##
|
515
|
-
#
|
545
|
+
# Converts +document+ to text and writes it to the pager
|
516
546
|
|
517
|
-
def
|
518
|
-
|
519
|
-
|
547
|
+
def display document
|
548
|
+
page do |io|
|
549
|
+
text = document.accept formatter
|
550
|
+
|
551
|
+
io.write text
|
552
|
+
end
|
520
553
|
end
|
521
554
|
|
522
555
|
##
|
523
|
-
#
|
556
|
+
# Outputs formatted RI data for class +name+. Groups undocumented classes
|
557
|
+
|
558
|
+
def display_class name
|
559
|
+
return if name =~ /#|\./
|
560
|
+
|
561
|
+
klasses = []
|
562
|
+
includes = []
|
563
|
+
|
564
|
+
found = @stores.map do |store|
|
565
|
+
begin
|
566
|
+
klass = store.load_class name
|
567
|
+
klasses << klass
|
568
|
+
includes << [klass.includes, store] if klass.includes
|
569
|
+
[store, klass]
|
570
|
+
rescue Errno::ENOENT
|
571
|
+
end
|
572
|
+
end.compact
|
524
573
|
|
525
|
-
|
526
|
-
|
574
|
+
return if found.empty?
|
575
|
+
|
576
|
+
also_in = []
|
577
|
+
|
578
|
+
includes.reject! do |modules,| modules.empty? end
|
579
|
+
|
580
|
+
out = RDoc::Markup::Document.new
|
581
|
+
|
582
|
+
add_class out, name, klasses
|
583
|
+
|
584
|
+
add_includes out, includes
|
585
|
+
|
586
|
+
found.each do |store, klass|
|
587
|
+
comment = klass.comment
|
588
|
+
class_methods = store.class_methods[klass.full_name]
|
589
|
+
instance_methods = store.instance_methods[klass.full_name]
|
590
|
+
attributes = store.attributes[klass.full_name]
|
591
|
+
|
592
|
+
if comment.empty? and !(instance_methods or class_methods) then
|
593
|
+
also_in << store
|
594
|
+
next
|
595
|
+
end
|
596
|
+
|
597
|
+
add_from out, store
|
598
|
+
|
599
|
+
unless comment.empty? then
|
600
|
+
out << RDoc::Markup::Rule.new(1)
|
601
|
+
out << comment
|
602
|
+
end
|
603
|
+
|
604
|
+
if class_methods or instance_methods or not klass.constants.empty? then
|
605
|
+
out << RDoc::Markup::Rule.new
|
606
|
+
end
|
607
|
+
|
608
|
+
unless klass.constants.empty? then
|
609
|
+
out << RDoc::Markup::Heading.new(1, "Constants:")
|
610
|
+
out << RDoc::Markup::BlankLine.new
|
611
|
+
list = RDoc::Markup::List.new :NOTE
|
612
|
+
|
613
|
+
constants = klass.constants.sort_by { |constant| constant.name }
|
614
|
+
|
615
|
+
list.push(*constants.map do |constant|
|
616
|
+
parts = constant.comment.parts if constant.comment
|
617
|
+
parts << RDoc::Markup::Paragraph.new('[not documented]') if
|
618
|
+
parts.empty?
|
619
|
+
|
620
|
+
RDoc::Markup::ListItem.new(constant.name, *parts)
|
621
|
+
end)
|
622
|
+
|
623
|
+
out << list
|
624
|
+
end
|
625
|
+
|
626
|
+
add_method_list out, class_methods, 'Class methods'
|
627
|
+
add_method_list out, instance_methods, 'Instance methods'
|
628
|
+
add_method_list out, attributes, 'Attributes'
|
629
|
+
|
630
|
+
out << RDoc::Markup::BlankLine.new
|
631
|
+
end
|
632
|
+
|
633
|
+
add_also_in out, also_in
|
634
|
+
|
635
|
+
display out
|
527
636
|
end
|
528
637
|
|
529
638
|
##
|
530
|
-
#
|
639
|
+
# Outputs formatted RI data for method +name+
|
531
640
|
|
532
|
-
def
|
533
|
-
|
641
|
+
def display_method name
|
642
|
+
found = load_methods_matching name
|
534
643
|
|
535
|
-
if
|
536
|
-
# prepare abbreviations for tab completion
|
537
|
-
klasses = class_cache.keys
|
644
|
+
raise NotFoundError, name if found.empty?
|
538
645
|
|
539
|
-
|
540
|
-
case name
|
541
|
-
when /(#|\.|::)([^A-Z]|$)/ then
|
542
|
-
methods = []
|
543
|
-
method_type = $1 == '.' ? '#|::' : $1
|
646
|
+
out = RDoc::Markup::Document.new
|
544
647
|
|
545
|
-
|
546
|
-
|
547
|
-
else
|
548
|
-
parse_name name
|
549
|
-
end
|
648
|
+
out << RDoc::Markup::Heading.new(1, name)
|
649
|
+
out << RDoc::Markup::BlankLine.new
|
550
650
|
|
551
|
-
|
651
|
+
found.each do |store, methods|
|
652
|
+
methods.each do |method|
|
653
|
+
out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
|
552
654
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
# TODO ancestor lookup
|
655
|
+
unless name =~ /^#{Regexp.escape method.parent_name}/ then
|
656
|
+
out << RDoc::Markup::Heading.new(3, "Implementation from #{method.parent_name}")
|
657
|
+
end
|
658
|
+
out << RDoc::Markup::Rule.new(1)
|
558
659
|
|
559
|
-
|
560
|
-
|
561
|
-
|
660
|
+
if method.call_seq then
|
661
|
+
call_seq = method.call_seq.chomp.split "\n"
|
662
|
+
call_seq = call_seq.map { |line| [' ', line, "\n"] }
|
663
|
+
out << RDoc::Markup::Verbatim.new(*call_seq.flatten)
|
664
|
+
end
|
562
665
|
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
[]
|
666
|
+
if method.block_params then
|
667
|
+
out << RDoc::Markup::BlankLine.new if method.call_seq
|
668
|
+
params = "yields: #{method.block_params}"
|
669
|
+
out << RDoc::Markup::Verbatim.new(' ', params, "\n")
|
568
670
|
end
|
671
|
+
|
672
|
+
out << RDoc::Markup::Rule.new(1) if
|
673
|
+
method.call_seq or method.block_params
|
674
|
+
|
675
|
+
out << RDoc::Markup::BlankLine.new
|
676
|
+
out << method.comment
|
677
|
+
out << RDoc::Markup::BlankLine.new
|
569
678
|
end
|
570
679
|
end
|
571
680
|
|
572
|
-
|
681
|
+
display out
|
682
|
+
end
|
573
683
|
|
574
|
-
|
575
|
-
|
576
|
-
|
684
|
+
##
|
685
|
+
# Outputs formatted RI data for the class or method +name+.
|
686
|
+
#
|
687
|
+
# Returns true if +name+ was found, false if it was not an alternative could
|
688
|
+
# be guessed, raises an error if +name+ couldn't be guessed.
|
577
689
|
|
578
|
-
|
690
|
+
def display_name name
|
691
|
+
return true if display_class name
|
579
692
|
|
580
|
-
|
581
|
-
name = if defined? Readline then
|
582
|
-
Readline.readline ">> "
|
583
|
-
else
|
584
|
-
formatter.raw_print_line ">> "
|
585
|
-
$stdin.gets
|
586
|
-
end
|
693
|
+
display_method name if name =~ /::|#|\./
|
587
694
|
|
588
|
-
|
695
|
+
true
|
696
|
+
rescue NotFoundError
|
697
|
+
matches = list_methods_matching name if name =~ /::|#|\./
|
698
|
+
matches = classes.keys.grep(/^#{name}/) if matches.empty?
|
589
699
|
|
590
|
-
|
700
|
+
raise if matches.empty?
|
591
701
|
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
end
|
702
|
+
page do |io|
|
703
|
+
io.puts "#{name} not found, maybe you meant:"
|
704
|
+
io.puts
|
705
|
+
io.puts matches.join("\n")
|
597
706
|
end
|
598
707
|
|
599
|
-
|
600
|
-
exit
|
708
|
+
false
|
601
709
|
end
|
602
710
|
|
603
711
|
##
|
604
|
-
#
|
712
|
+
# Displays each name in +name+
|
713
|
+
|
714
|
+
def display_names names
|
715
|
+
names.each do |name|
|
716
|
+
name = expand_name name
|
717
|
+
|
718
|
+
display_name name
|
719
|
+
end
|
720
|
+
end
|
721
|
+
##
|
722
|
+
# Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da"
|
605
723
|
# will be expanded to Zlib::DataError.
|
606
724
|
|
607
|
-
def
|
725
|
+
def expand_class klass
|
608
726
|
klass.split('::').inject '' do |expanded, klass_part|
|
609
727
|
expanded << '::' unless expanded.empty?
|
610
728
|
short = expanded << klass_part
|
611
729
|
|
612
|
-
subset =
|
613
|
-
|
730
|
+
subset = classes.keys.select do |klass_name|
|
731
|
+
klass_name =~ /^#{expanded}[^:]*$/
|
614
732
|
end
|
615
733
|
|
616
734
|
abbrevs = Abbrev.abbrev subset
|
@@ -624,152 +742,277 @@ Options may also be set in the 'RI' environment variable.
|
|
624
742
|
end
|
625
743
|
|
626
744
|
##
|
627
|
-
#
|
745
|
+
# Expands the class portion of +name+ into a fully-qualified class. See
|
746
|
+
# #expand_class.
|
628
747
|
|
629
|
-
def
|
630
|
-
|
748
|
+
def expand_name name
|
749
|
+
klass, selector, method = parse_name name
|
631
750
|
|
632
|
-
|
751
|
+
return [selector, method].join if klass.empty?
|
633
752
|
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
753
|
+
"#{expand_class klass}#{selector}#{method}"
|
754
|
+
end
|
755
|
+
|
756
|
+
##
|
757
|
+
# Yields items matching +name+ including the store they were found in, the
|
758
|
+
# class being searched for, the class they were found in (an ancestor) the
|
759
|
+
# types of methods to look up (from #method_type), and the method name being
|
760
|
+
# searched for
|
761
|
+
|
762
|
+
def find_methods name
|
763
|
+
klass, selector, method = parse_name name
|
764
|
+
|
765
|
+
types = method_type selector
|
766
|
+
|
767
|
+
klasses = nil
|
768
|
+
ambiguous = klass.empty?
|
769
|
+
|
770
|
+
if ambiguous then
|
771
|
+
klasses = classes.keys
|
648
772
|
else
|
649
|
-
|
773
|
+
klasses = ancestors_of klass
|
774
|
+
klasses.unshift klass
|
775
|
+
end
|
776
|
+
|
777
|
+
methods = []
|
778
|
+
|
779
|
+
klasses.each do |ancestor|
|
780
|
+
ancestors = classes[ancestor]
|
781
|
+
|
782
|
+
next unless ancestors
|
783
|
+
|
784
|
+
klass = ancestor if ambiguous
|
785
|
+
|
786
|
+
ancestors.each do |store|
|
787
|
+
methods << [store, klass, ancestor, types, method]
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
791
|
+
methods = methods.sort_by do |_, k, a, _, m|
|
792
|
+
[k, a, m].compact
|
650
793
|
end
|
651
794
|
|
652
|
-
|
795
|
+
methods.each do |item|
|
796
|
+
yield(*item)
|
797
|
+
end
|
798
|
+
|
799
|
+
self
|
653
800
|
end
|
654
801
|
|
655
802
|
##
|
656
|
-
#
|
803
|
+
# Creates a new RDoc::Markup::Formatter. If a formatter is given with -f,
|
804
|
+
# use it. If we're outputting to a pager, use bs, otherwise ansi.
|
805
|
+
|
806
|
+
def formatter
|
807
|
+
if @formatter_klass then
|
808
|
+
@formatter_klass.new
|
809
|
+
elsif paging? then
|
810
|
+
RDoc::Markup::ToBs.new
|
811
|
+
else
|
812
|
+
RDoc::Markup::ToAnsi.new
|
813
|
+
end
|
814
|
+
end
|
657
815
|
|
658
|
-
|
659
|
-
|
660
|
-
return nil unless klass
|
816
|
+
##
|
817
|
+
# Runs ri interactively using Readline if it is available.
|
661
818
|
|
662
|
-
|
663
|
-
|
819
|
+
def interactive
|
820
|
+
puts "\nEnter the method name you want to look up."
|
664
821
|
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
next if yaml =~ /cdesc-[^\/]+yaml$/
|
822
|
+
if defined? Readline then
|
823
|
+
Readline.completion_proc = method :complete
|
824
|
+
puts "You can use tab to autocomplete."
|
825
|
+
end
|
670
826
|
|
671
|
-
|
827
|
+
puts "Enter a blank line to exit.\n\n"
|
672
828
|
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
829
|
+
loop do
|
830
|
+
name = if defined? Readline then
|
831
|
+
Readline.readline ">> "
|
832
|
+
else
|
833
|
+
print ">> "
|
834
|
+
$stdin.gets
|
835
|
+
end
|
678
836
|
|
679
|
-
|
680
|
-
end
|
837
|
+
return if name.nil? or name.empty?
|
681
838
|
|
682
|
-
|
683
|
-
"gem #{$1}"
|
684
|
-
else
|
685
|
-
f
|
686
|
-
end
|
687
|
-
end
|
839
|
+
name = expand_name name.strip
|
688
840
|
|
689
|
-
|
690
|
-
|
841
|
+
begin
|
842
|
+
display_name name
|
843
|
+
rescue NotFoundError => e
|
844
|
+
puts e.message
|
691
845
|
end
|
692
846
|
end
|
693
847
|
|
694
|
-
|
848
|
+
rescue Interrupt
|
849
|
+
exit
|
695
850
|
end
|
696
851
|
|
697
852
|
##
|
698
|
-
#
|
853
|
+
# Lists classes known to ri
|
854
|
+
|
855
|
+
def list_known_classes
|
856
|
+
classes = []
|
699
857
|
|
700
|
-
|
701
|
-
|
702
|
-
# since Object has an Object ancestor for some reason. Depending on the
|
703
|
-
# documentation state, I've seen Kernel as an ancestor of Object and not
|
704
|
-
# as an ancestor of Object.
|
705
|
-
if orig_klass == "Object" && (klass == "Kernel" || klass == "Object") then
|
706
|
-
return nil
|
858
|
+
stores.each do |store|
|
859
|
+
classes << store.modules
|
707
860
|
end
|
708
861
|
|
709
|
-
|
862
|
+
classes = classes.flatten.uniq.sort
|
710
863
|
|
711
|
-
|
864
|
+
page do |io|
|
865
|
+
if paging? or io.tty? then
|
866
|
+
io.puts "Classes and Modules known to ri:"
|
867
|
+
io.puts
|
868
|
+
end
|
869
|
+
|
870
|
+
io.puts classes.join("\n")
|
871
|
+
end
|
872
|
+
end
|
873
|
+
|
874
|
+
##
|
875
|
+
# Returns an Array of methods matching +name+
|
876
|
+
|
877
|
+
def list_methods_matching name
|
878
|
+
found = []
|
879
|
+
|
880
|
+
find_methods name do |store, klass, ancestor, types, method|
|
881
|
+
if types == :instance or types == :both then
|
882
|
+
methods = store.instance_methods[ancestor]
|
883
|
+
|
884
|
+
if methods then
|
885
|
+
matches = methods.grep(/^#{method}/)
|
886
|
+
|
887
|
+
matches = matches.map do |match|
|
888
|
+
"#{klass}##{match}"
|
889
|
+
end
|
890
|
+
|
891
|
+
found.push(*matches)
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
if types == :class or types == :both then
|
896
|
+
methods = store.class_methods[ancestor]
|
712
897
|
|
713
|
-
|
714
|
-
|
715
|
-
ancestors << cache.superclass
|
898
|
+
next unless methods
|
899
|
+
matches = methods.grep(/^#{method}/)
|
716
900
|
|
717
|
-
|
901
|
+
matches = matches.map do |match|
|
902
|
+
"#{klass}::#{match}"
|
903
|
+
end
|
718
904
|
|
719
|
-
|
720
|
-
|
721
|
-
return ancestor if ancestor
|
905
|
+
found.push(*matches)
|
906
|
+
end
|
722
907
|
end
|
723
908
|
|
724
|
-
|
909
|
+
found.uniq
|
725
910
|
end
|
726
911
|
|
727
912
|
##
|
728
|
-
#
|
913
|
+
# Loads RI data for method +name+ on +klass+ from +store+. +type+ and
|
914
|
+
# +cache+ indicate if it is a class or instance method.
|
915
|
+
|
916
|
+
def load_method store, cache, klass, type, name
|
917
|
+
methods = store.send(cache)[klass]
|
918
|
+
|
919
|
+
return unless methods
|
920
|
+
|
921
|
+
method = methods.find do |method_name|
|
922
|
+
method_name == name
|
923
|
+
end
|
729
924
|
|
730
|
-
|
731
|
-
cache = load_cache_for klass
|
732
|
-
return nil unless cache
|
925
|
+
return unless method
|
733
926
|
|
734
|
-
|
735
|
-
method = cache[name.gsub('.', '::')] unless method
|
736
|
-
method
|
927
|
+
store.load_method klass, "#{type}#{method}"
|
737
928
|
end
|
738
929
|
|
739
|
-
|
740
|
-
|
930
|
+
##
|
931
|
+
# Returns an Array of RI data for methods matching +name+
|
932
|
+
|
933
|
+
def load_methods_matching name
|
934
|
+
found = []
|
935
|
+
|
936
|
+
find_methods name do |store, klass, ancestor, types, method|
|
937
|
+
methods = []
|
938
|
+
|
939
|
+
methods << load_method(store, :class_methods, ancestor, '::', method) if
|
940
|
+
types == :class or types == :both
|
941
|
+
|
942
|
+
methods << load_method(store, :instance_methods, ancestor, '#', method) if
|
943
|
+
types == :instance or types == :both
|
944
|
+
|
945
|
+
found << [store, methods.compact]
|
946
|
+
end
|
947
|
+
|
948
|
+
found.reject do |path, methods| methods.empty? end
|
741
949
|
end
|
742
950
|
|
743
951
|
##
|
744
|
-
#
|
952
|
+
# Returns the type of method (:both, :instance, :class) for +selector+
|
745
953
|
|
746
|
-
def
|
747
|
-
|
954
|
+
def method_type selector
|
955
|
+
case selector
|
956
|
+
when '.', nil then :both
|
957
|
+
when '#' then :instance
|
958
|
+
else :class
|
959
|
+
end
|
960
|
+
end
|
748
961
|
|
749
|
-
|
750
|
-
|
751
|
-
|
962
|
+
##
|
963
|
+
# Paginates output through a pager program.
|
964
|
+
|
965
|
+
def page
|
966
|
+
if pager = setup_pager then
|
967
|
+
begin
|
968
|
+
yield pager
|
969
|
+
ensure
|
970
|
+
pager.close
|
971
|
+
end
|
972
|
+
else
|
973
|
+
yield $stdout
|
752
974
|
end
|
975
|
+
rescue Errno::EPIPE
|
976
|
+
ensure
|
977
|
+
@paging = false
|
978
|
+
end
|
753
979
|
|
754
|
-
|
980
|
+
##
|
981
|
+
# Are we using a pager?
|
755
982
|
|
756
|
-
|
983
|
+
def paging?
|
984
|
+
@paging
|
757
985
|
end
|
758
986
|
|
759
987
|
##
|
760
|
-
#
|
761
|
-
#
|
988
|
+
# Extract the class, selector and method name parts from +name+ like
|
989
|
+
# Foo::Bar#baz.
|
990
|
+
#
|
991
|
+
# NOTE: Given Foo::Bar, Bar is considered a class even though it may be a
|
992
|
+
# method
|
993
|
+
|
994
|
+
def parse_name(name)
|
995
|
+
parts = name.split(/(::|#|\.)/)
|
762
996
|
|
763
|
-
|
764
|
-
|
997
|
+
if parts.length == 1 then
|
998
|
+
if parts.first =~ /^[a-z]/ then
|
999
|
+
type = '.'
|
1000
|
+
meth = parts.pop
|
1001
|
+
else
|
1002
|
+
type = nil
|
1003
|
+
meth = nil
|
1004
|
+
end
|
1005
|
+
elsif parts.length == 2 or parts.last =~ /::|#|\./ then
|
1006
|
+
type = parts.pop
|
1007
|
+
meth = nil
|
1008
|
+
elsif parts[-2] != '::' or parts.last !~ /^[A-Z]/ then
|
1009
|
+
meth = parts.pop
|
1010
|
+
type = parts.pop
|
1011
|
+
end
|
765
1012
|
|
766
|
-
|
767
|
-
# by earliar RDoc versions.
|
768
|
-
data = data.gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '')
|
769
|
-
data = data.gsub(/ \!ruby\/(object|struct):SM::(\S+)/,
|
770
|
-
' !ruby/\1:RDoc::Markup::\2')
|
1013
|
+
klass = parts.join
|
771
1014
|
|
772
|
-
|
1015
|
+
[klass, type, meth]
|
773
1016
|
end
|
774
1017
|
|
775
1018
|
##
|
@@ -781,47 +1024,34 @@ Options may also be set in the 'RI' environment variable.
|
|
781
1024
|
elsif @interactive then
|
782
1025
|
interactive
|
783
1026
|
elsif @names.empty? then
|
784
|
-
|
1027
|
+
list_known_classes
|
785
1028
|
else
|
786
|
-
@names
|
787
|
-
display_name name
|
788
|
-
end
|
1029
|
+
display_names @names
|
789
1030
|
end
|
790
1031
|
rescue NotFoundError => e
|
791
1032
|
abort e.message
|
792
1033
|
end
|
793
1034
|
|
794
1035
|
##
|
795
|
-
#
|
1036
|
+
# Sets up a pager program to pass output through. Tries the RI_PAGER and
|
1037
|
+
# PAGER environment variables followed by pager, less then more.
|
796
1038
|
|
797
|
-
def
|
798
|
-
|
799
|
-
class_cache.keys.sort.each do |klass|
|
800
|
-
class_cache[klass]["instance_methods"].map{|h|h["name"]}.grep(pattern) do |name|
|
801
|
-
method = load_cache_for(klass)[klass+'#'+name]
|
802
|
-
methods << method if method
|
803
|
-
end
|
804
|
-
class_cache[klass]["class_methods"].map{|h|h["name"]}.grep(pattern) do |name|
|
805
|
-
method = load_cache_for(klass)[klass+'::'+name]
|
806
|
-
methods << method if method
|
807
|
-
end
|
808
|
-
end
|
809
|
-
methods
|
810
|
-
end
|
1039
|
+
def setup_pager
|
1040
|
+
return if @use_stdout
|
811
1041
|
|
812
|
-
|
813
|
-
# Writes +cache+ to +path+
|
1042
|
+
pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more']
|
814
1043
|
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
1044
|
+
pagers.compact.uniq.each do |pager|
|
1045
|
+
io = IO.popen(pager, "w") rescue next
|
1046
|
+
|
1047
|
+
@paging = true
|
1048
|
+
|
1049
|
+
return io
|
820
1050
|
end
|
821
1051
|
|
822
|
-
|
823
|
-
|
824
|
-
|
1052
|
+
@use_stdout = true
|
1053
|
+
|
1054
|
+
nil
|
825
1055
|
end
|
826
1056
|
|
827
1057
|
end
|