rdoc 8.0.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +1 -3
- data/RI.md +75 -75
- data/exe/rdoc +2 -2
- data/lib/rdoc/code_object/alias.rb +71 -69
- data/lib/rdoc/code_object/any_method.rb +305 -303
- data/lib/rdoc/code_object/attr.rb +150 -148
- data/lib/rdoc/code_object/class_module.rb +798 -792
- data/lib/rdoc/code_object/constant.rb +175 -173
- data/lib/rdoc/code_object/context/section.rb +142 -138
- data/lib/rdoc/code_object/context.rb +926 -958
- data/lib/rdoc/code_object/extend.rb +7 -5
- data/lib/rdoc/code_object/include.rb +7 -5
- data/lib/rdoc/code_object/method_attr.rb +326 -319
- data/lib/rdoc/code_object/mixin.rb +97 -95
- data/lib/rdoc/code_object/normal_class.rb +77 -78
- data/lib/rdoc/code_object/normal_module.rb +61 -59
- data/lib/rdoc/code_object/require.rb +23 -39
- data/lib/rdoc/code_object/single_class.rb +21 -19
- data/lib/rdoc/code_object/top_level.rb +212 -219
- data/lib/rdoc/code_object.rb +305 -303
- data/lib/rdoc/comment.rb +275 -273
- data/lib/rdoc/cross_reference.rb +192 -190
- data/lib/rdoc/encoding.rb +105 -103
- data/lib/rdoc/erb_partial.rb +13 -11
- data/lib/rdoc/erbio.rb +29 -27
- data/lib/rdoc/generator/aliki.rb +161 -153
- data/lib/rdoc/generator/darkfish.rb +645 -635
- data/lib/rdoc/generator/json_index.rb +233 -229
- data/lib/rdoc/generator/markup.rb +164 -146
- data/lib/rdoc/generator/pot/message_extractor.rb +57 -51
- data/lib/rdoc/generator/pot/po.rb +52 -51
- data/lib/rdoc/generator/pot/po_entry.rb +138 -132
- data/lib/rdoc/generator/pot.rb +85 -81
- data/lib/rdoc/generator/ri.rb +23 -19
- data/lib/rdoc/generator/template/aliki/DESIGN.md +6 -4
- data/lib/rdoc/generator/template/aliki/_footer.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_head.rhtml +10 -10
- data/lib/rdoc/generator/template/aliki/_header.rhtml +29 -44
- data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +4 -4
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +207 -178
- data/lib/rdoc/generator/template/aliki/js/aliki.js +60 -84
- data/lib/rdoc/generator/template/darkfish/_footer.rhtml +1 -1
- data/lib/rdoc/generator.rb +48 -46
- data/lib/rdoc/i18n/locale.rb +99 -95
- data/lib/rdoc/i18n/text.rb +109 -105
- data/lib/rdoc/i18n.rb +7 -5
- data/lib/rdoc/markdown/byte_runtime.rb +80 -0
- data/lib/rdoc/markdown.kpeg +15 -11
- data/lib/rdoc/markdown.rb +40 -47
- data/lib/rdoc/markup/block_quote.rb +12 -8
- data/lib/rdoc/markup/document.rb +127 -123
- data/lib/rdoc/markup/formatter.rb +219 -215
- data/lib/rdoc/markup/include.rb +33 -29
- data/lib/rdoc/markup/indented_paragraph.rb +37 -33
- data/lib/rdoc/markup/inline_parser.rb +281 -277
- data/lib/rdoc/markup/list.rb +80 -88
- data/lib/rdoc/markup/list_item.rb +73 -85
- data/lib/rdoc/markup/paragraph.rb +23 -19
- data/lib/rdoc/markup/parser.rb +501 -497
- data/lib/rdoc/markup/pre_process.rb +283 -279
- data/lib/rdoc/markup/raw.rb +2 -2
- data/lib/rdoc/markup/rule.rb +16 -12
- data/lib/rdoc/markup/to_ansi.rb +143 -139
- data/lib/rdoc/markup/to_bs.rb +72 -68
- data/lib/rdoc/markup/to_html.rb +594 -565
- data/lib/rdoc/markup/to_html_crossref.rb +234 -230
- data/lib/rdoc/markup/to_html_snippet.rb +232 -227
- data/lib/rdoc/markup/to_joined_paragraph.rb +36 -32
- data/lib/rdoc/markup/to_label.rb +63 -59
- data/lib/rdoc/markup/to_markdown.rb +212 -208
- data/lib/rdoc/markup/to_rdoc.rb +336 -332
- data/lib/rdoc/markup/to_table_of_contents.rb +66 -62
- data/lib/rdoc/markup/to_test.rb +60 -56
- data/lib/rdoc/markup/to_tt_only.rb +84 -80
- data/lib/rdoc/markup/verbatim.rb +62 -58
- data/lib/rdoc/markup.rb +198 -196
- data/lib/rdoc/options.rb +1063 -1061
- data/lib/rdoc/parser/c.rb +1039 -1037
- data/lib/rdoc/parser/changelog.rb +319 -315
- data/lib/rdoc/parser/markdown.rb +17 -13
- data/lib/rdoc/parser/rbs.rb +239 -235
- data/lib/rdoc/parser/rd.rb +17 -13
- data/lib/rdoc/parser/ruby.rb +1245 -1124
- data/lib/rdoc/parser/ruby_colorizer.rb +263 -213
- data/lib/rdoc/parser/simple.rb +31 -27
- data/lib/rdoc/parser/text.rb +12 -8
- data/lib/rdoc/parser.rb +228 -220
- data/lib/rdoc/rbs_helper.rb +1 -1
- data/lib/rdoc/rd/inline.rb +57 -53
- data/lib/rdoc/rd.rb +90 -88
- data/lib/rdoc/rdoc.rb +500 -491
- data/lib/rdoc/ri/driver.rb +1140 -1135
- data/lib/rdoc/ri/formatter.rb +7 -3
- data/lib/rdoc/ri/paths.rb +140 -136
- data/lib/rdoc/ri/servlet.rb +354 -350
- data/lib/rdoc/ri/store.rb +4 -2
- data/lib/rdoc/ri/task.rb +55 -51
- data/lib/rdoc/ri.rb +14 -12
- data/lib/rdoc/rubygems_hook.rb +183 -181
- data/lib/rdoc/server.rb +349 -347
- data/lib/rdoc/stats/normal.rb +46 -42
- data/lib/rdoc/stats/quiet.rb +39 -35
- data/lib/rdoc/stats/verbose.rb +35 -31
- data/lib/rdoc/stats.rb +365 -363
- data/lib/rdoc/store.rb +888 -902
- data/lib/rdoc/task.rb +260 -256
- data/lib/rdoc/text.rb +135 -133
- data/lib/rdoc/token_stream.rb +101 -93
- data/lib/rdoc/tom_doc.rb +203 -201
- data/lib/rdoc/version.rb +1 -1
- metadata +4 -5
- data/lib/rdoc/markdown/literals.kpeg +0 -21
- data/lib/rdoc/markdown/literals.rb +0 -454
data/lib/rdoc/ri/driver.rb
CHANGED
|
@@ -4,119 +4,121 @@ require 'optparse'
|
|
|
4
4
|
require_relative '../../rdoc'
|
|
5
5
|
|
|
6
6
|
require_relative 'formatter' # For RubyGems backwards compatibility
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# The RI driver implements the command-line ri tool.
|
|
11
|
-
#
|
|
12
|
-
# The driver supports:
|
|
13
|
-
# * loading RI data from:
|
|
14
|
-
# * Ruby's standard library
|
|
15
|
-
# * RubyGems
|
|
16
|
-
# * ~/.rdoc
|
|
17
|
-
# * A user-supplied directory
|
|
18
|
-
# * Paging output (uses RI_PAGER environment variable, PAGER environment
|
|
19
|
-
# variable or the less, more and pager programs)
|
|
20
|
-
# * Interactive mode with tab-completion
|
|
21
|
-
# * Abbreviated names (ri Zl shows Zlib documentation)
|
|
22
|
-
# * Colorized output
|
|
23
|
-
# * Merging output from multiple RI data sources
|
|
24
|
-
|
|
25
|
-
class RDoc::RI::Driver
|
|
26
|
-
|
|
27
|
-
##
|
|
28
|
-
# Base Driver error class
|
|
29
|
-
|
|
30
|
-
class Error < RDoc::RI::Error; end
|
|
31
|
-
|
|
32
|
-
##
|
|
33
|
-
# Raised when a name isn't found in the ri data stores
|
|
34
|
-
|
|
35
|
-
class NotFoundError < Error
|
|
36
|
-
|
|
37
|
-
def initialize(klass, suggestion_proc = nil) # :nodoc:
|
|
38
|
-
@klass = klass
|
|
39
|
-
@suggestion_proc = suggestion_proc
|
|
40
|
-
end
|
|
7
|
+
module RDoc
|
|
8
|
+
module RI
|
|
9
|
+
# TODO: Fix weird documentation with `require_relative`
|
|
41
10
|
|
|
42
11
|
##
|
|
43
|
-
#
|
|
12
|
+
# The RI driver implements the command-line ri tool.
|
|
13
|
+
#
|
|
14
|
+
# The driver supports:
|
|
15
|
+
# * loading RI data from:
|
|
16
|
+
# * Ruby's standard library
|
|
17
|
+
# * RubyGems
|
|
18
|
+
# * ~/.rdoc
|
|
19
|
+
# * A user-supplied directory
|
|
20
|
+
# * Paging output (uses RI_PAGER environment variable, PAGER environment
|
|
21
|
+
# variable or the less, more and pager programs)
|
|
22
|
+
# * Interactive mode with tab-completion
|
|
23
|
+
# * Abbreviated names (ri Zl shows Zlib documentation)
|
|
24
|
+
# * Colorized output
|
|
25
|
+
# * Merging output from multiple RI data sources
|
|
26
|
+
|
|
27
|
+
class Driver
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Base Driver error class
|
|
31
|
+
|
|
32
|
+
class Error < RI::Error; end
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# Raised when a name isn't found in the ri data stores
|
|
36
|
+
|
|
37
|
+
class NotFoundError < Error
|
|
38
|
+
|
|
39
|
+
def initialize(klass, suggestion_proc = nil) # :nodoc:
|
|
40
|
+
@klass = klass
|
|
41
|
+
@suggestion_proc = suggestion_proc
|
|
42
|
+
end
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
end
|
|
44
|
+
##
|
|
45
|
+
# Name that wasn't found
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
def name
|
|
48
|
+
@klass
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def message # :nodoc:
|
|
52
|
+
str = "Nothing known about #{@klass}"
|
|
53
|
+
suggestions = @suggestion_proc&.call
|
|
54
|
+
if suggestions and !suggestions.empty?
|
|
55
|
+
str += "\nDid you mean? #{suggestions.join("\n ")}"
|
|
56
|
+
end
|
|
57
|
+
str
|
|
58
|
+
end
|
|
54
59
|
end
|
|
55
|
-
str
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
##
|
|
62
|
+
# Show all method documentation following a class or module
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
attr_accessor :show_all
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
##
|
|
67
|
+
# An RDoc::RI::Store for each entry in the RI path
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
attr_accessor :stores
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
##
|
|
72
|
+
# Controls the user of the pager vs $stdout
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
attr_accessor :use_stdout
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
##
|
|
77
|
+
# Default options for ri
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
def self.default_options
|
|
80
|
+
options = {}
|
|
81
|
+
options[:interactive] = false
|
|
82
|
+
options[:profile] = false
|
|
83
|
+
options[:show_all] = false
|
|
84
|
+
options[:expand_refs] = true
|
|
85
|
+
options[:use_stdout] = !$stdout.tty?
|
|
86
|
+
options[:width] = 72
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
# By default all standard paths are used.
|
|
89
|
+
options[:use_system] = true
|
|
90
|
+
options[:use_site] = true
|
|
91
|
+
options[:use_home] = true
|
|
92
|
+
options[:use_gems] = true
|
|
93
|
+
options[:extra_doc_dirs] = []
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
return options
|
|
96
|
+
end
|
|
95
97
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
##
|
|
99
|
+
# Dump +data_path+ using pp
|
|
98
100
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
def self.dump(data_path)
|
|
102
|
+
require 'pp'
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
File.open data_path, 'rb' do |io|
|
|
105
|
+
pp Marshal.load(io.read)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
##
|
|
110
|
+
# Parses +argv+ and returns a Hash of options
|
|
109
111
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
def self.process_args(argv)
|
|
113
|
+
options = default_options
|
|
112
114
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
opts = OptionParser.new do |opt|
|
|
116
|
+
opt.program_name = File.basename $0
|
|
117
|
+
opt.version = VERSION
|
|
118
|
+
opt.release = nil
|
|
119
|
+
opt.summary_indent = ' ' * 4
|
|
118
120
|
|
|
119
|
-
|
|
121
|
+
opt.banner = <<-EOT
|
|
120
122
|
Usage: #{opt.program_name} [options] [name ...]
|
|
121
123
|
|
|
122
124
|
Where name can be:
|
|
@@ -172,1401 +174,1404 @@ The ri pager can be set with the RI_PAGER environment variable
|
|
|
172
174
|
or the PAGER environment variable.
|
|
173
175
|
EOT
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
opt.separator nil
|
|
178
|
+
opt.separator "Options:"
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
opt.separator nil
|
|
179
181
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
opt.on("--[no-]interactive", "-i",
|
|
183
|
+
"In interactive mode you can repeatedly",
|
|
184
|
+
"look up methods with autocomplete.") do |interactive|
|
|
185
|
+
options[:interactive] = interactive
|
|
186
|
+
end
|
|
185
187
|
|
|
186
|
-
|
|
188
|
+
opt.separator nil
|
|
187
189
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
opt.on("--[no-]all", "-a",
|
|
191
|
+
"Show all documentation for a class or",
|
|
192
|
+
"module.") do |show_all|
|
|
193
|
+
options[:show_all] = show_all
|
|
194
|
+
end
|
|
193
195
|
|
|
194
|
-
|
|
196
|
+
opt.separator nil
|
|
195
197
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
opt.on("--[no-]list", "-l",
|
|
199
|
+
"List classes ri knows about.") do |list|
|
|
200
|
+
options[:list] = list
|
|
201
|
+
end
|
|
200
202
|
|
|
201
|
-
|
|
203
|
+
opt.separator nil
|
|
202
204
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
opt.on("--[no-]pager",
|
|
206
|
+
"Send output to a pager,",
|
|
207
|
+
"rather than directly to stdout.") do |use_pager|
|
|
208
|
+
options[:use_stdout] = !use_pager
|
|
209
|
+
end
|
|
208
210
|
|
|
209
|
-
|
|
211
|
+
opt.separator nil
|
|
210
212
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
opt.on("-T",
|
|
214
|
+
"Synonym for --no-pager.") do
|
|
215
|
+
options[:use_stdout] = true
|
|
216
|
+
end
|
|
215
217
|
|
|
216
|
-
|
|
218
|
+
opt.separator nil
|
|
217
219
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
|
|
221
|
+
"Set the width of the output.") do |width|
|
|
222
|
+
options[:width] = width
|
|
223
|
+
end
|
|
222
224
|
|
|
223
|
-
|
|
225
|
+
opt.separator nil
|
|
224
226
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
227
|
+
opt.on("--server[=PORT]", Integer,
|
|
228
|
+
"Run RDoc server on the given port.",
|
|
229
|
+
"The default port is 8214.") do |port|
|
|
230
|
+
options[:server] = port || 8214
|
|
231
|
+
end
|
|
230
232
|
|
|
231
|
-
|
|
233
|
+
opt.separator nil
|
|
232
234
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
235
|
+
formatters = Markup.constants.grep(/^To[A-Z][a-z]+$/).sort
|
|
236
|
+
formatters = formatters.sort.map do |formatter|
|
|
237
|
+
formatter.to_s.sub('To', '').downcase
|
|
238
|
+
end
|
|
239
|
+
formatters -= %w[html label test] # remove useless output formats
|
|
240
|
+
|
|
241
|
+
opt.on("--format=NAME", "-f",
|
|
242
|
+
"Use the selected formatter. The default",
|
|
243
|
+
"formatter is bs for paged output and ansi",
|
|
244
|
+
"otherwise. Valid formatters are:",
|
|
245
|
+
"#{formatters.join(', ')}.", formatters) do |value|
|
|
246
|
+
options[:formatter] = Markup.const_get "To#{value.capitalize}"
|
|
247
|
+
end
|
|
246
248
|
|
|
247
|
-
|
|
249
|
+
opt.separator nil
|
|
248
250
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
251
|
+
opt.on("--[no-]expand-refs", "Expand rdoc-refs at the end of output") do |value|
|
|
252
|
+
options[:expand_refs] = value
|
|
253
|
+
end
|
|
252
254
|
|
|
253
|
-
|
|
255
|
+
opt.separator nil
|
|
254
256
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
opt.on("--help", "-h",
|
|
258
|
+
"Show help and exit.") do
|
|
259
|
+
puts opts
|
|
260
|
+
exit
|
|
261
|
+
end
|
|
260
262
|
|
|
261
|
-
|
|
263
|
+
opt.separator nil
|
|
262
264
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
opt.on("--version", "-v",
|
|
266
|
+
"Output version information and exit.") do
|
|
267
|
+
puts "#{opts.program_name} #{opts.version}"
|
|
268
|
+
exit
|
|
269
|
+
end
|
|
268
270
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
271
|
+
opt.separator nil
|
|
272
|
+
opt.separator "Data source options:"
|
|
273
|
+
opt.separator nil
|
|
272
274
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
275
|
+
opt.on("--[no-]list-doc-dirs",
|
|
276
|
+
"List the directories from which ri will",
|
|
277
|
+
"source documentation on stdout and exit.") do |list_doc_dirs|
|
|
278
|
+
options[:list_doc_dirs] = list_doc_dirs
|
|
279
|
+
end
|
|
278
280
|
|
|
279
|
-
|
|
281
|
+
opt.separator nil
|
|
280
282
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
opt.on("--doc-dir=DIRNAME", "-d", Array,
|
|
284
|
+
"List of directories from which to source",
|
|
285
|
+
"documentation in addition to the standard",
|
|
286
|
+
"directories. May be repeated.") do |value|
|
|
287
|
+
value.each do |dir|
|
|
288
|
+
unless File.directory? dir
|
|
289
|
+
raise OptionParser::InvalidArgument, "#{dir} is not a directory"
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
options[:extra_doc_dirs] << File.expand_path(dir)
|
|
293
|
+
end
|
|
288
294
|
end
|
|
289
295
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
296
|
+
opt.separator nil
|
|
297
|
+
|
|
298
|
+
opt.on("--no-standard-docs",
|
|
299
|
+
"Do not include documentation from",
|
|
300
|
+
"the Ruby standard library, site_lib,",
|
|
301
|
+
"installed gems, or ~/.rdoc.",
|
|
302
|
+
"Use with --doc-dir.") do
|
|
303
|
+
options[:use_system] = false
|
|
304
|
+
options[:use_site] = false
|
|
305
|
+
options[:use_gems] = false
|
|
306
|
+
options[:use_home] = false
|
|
307
|
+
end
|
|
293
308
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
opt.on("--no-standard-docs",
|
|
297
|
-
"Do not include documentation from",
|
|
298
|
-
"the Ruby standard library, site_lib,",
|
|
299
|
-
"installed gems, or ~/.rdoc.",
|
|
300
|
-
"Use with --doc-dir.") do
|
|
301
|
-
options[:use_system] = false
|
|
302
|
-
options[:use_site] = false
|
|
303
|
-
options[:use_gems] = false
|
|
304
|
-
options[:use_home] = false
|
|
305
|
-
end
|
|
309
|
+
opt.separator nil
|
|
306
310
|
|
|
307
|
-
|
|
311
|
+
opt.on("--[no-]system",
|
|
312
|
+
"Include documentation from Ruby's",
|
|
313
|
+
"standard library. Defaults to true.") do |value|
|
|
314
|
+
options[:use_system] = value
|
|
315
|
+
end
|
|
308
316
|
|
|
309
|
-
|
|
310
|
-
"Include documentation from Ruby's",
|
|
311
|
-
"standard library. Defaults to true.") do |value|
|
|
312
|
-
options[:use_system] = value
|
|
313
|
-
end
|
|
317
|
+
opt.separator nil
|
|
314
318
|
|
|
315
|
-
|
|
319
|
+
opt.on("--[no-]site",
|
|
320
|
+
"Include documentation from libraries",
|
|
321
|
+
"installed in site_lib.",
|
|
322
|
+
"Defaults to true.") do |value|
|
|
323
|
+
options[:use_site] = value
|
|
324
|
+
end
|
|
316
325
|
|
|
317
|
-
|
|
318
|
-
"Include documentation from libraries",
|
|
319
|
-
"installed in site_lib.",
|
|
320
|
-
"Defaults to true.") do |value|
|
|
321
|
-
options[:use_site] = value
|
|
322
|
-
end
|
|
326
|
+
opt.separator nil
|
|
323
327
|
|
|
324
|
-
|
|
328
|
+
opt.on("--[no-]gems",
|
|
329
|
+
"Include documentation from RubyGems.",
|
|
330
|
+
"Defaults to true.") do |value|
|
|
331
|
+
options[:use_gems] = value
|
|
332
|
+
end
|
|
325
333
|
|
|
326
|
-
|
|
327
|
-
"Include documentation from RubyGems.",
|
|
328
|
-
"Defaults to true.") do |value|
|
|
329
|
-
options[:use_gems] = value
|
|
330
|
-
end
|
|
334
|
+
opt.separator nil
|
|
331
335
|
|
|
332
|
-
|
|
336
|
+
opt.on("--[no-]home",
|
|
337
|
+
"Include documentation stored in ~/.rdoc.",
|
|
338
|
+
"Defaults to true.") do |value|
|
|
339
|
+
options[:use_home] = value
|
|
340
|
+
end
|
|
333
341
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
options[:use_home] = value
|
|
338
|
-
end
|
|
342
|
+
opt.separator nil
|
|
343
|
+
opt.separator "Debug options:"
|
|
344
|
+
opt.separator nil
|
|
339
345
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
346
|
+
opt.on("--[no-]profile",
|
|
347
|
+
"Run with the ruby profiler.") do |value|
|
|
348
|
+
options[:profile] = value
|
|
349
|
+
end
|
|
343
350
|
|
|
344
|
-
|
|
345
|
-
"Run with the ruby profiler.") do |value|
|
|
346
|
-
options[:profile] = value
|
|
347
|
-
end
|
|
351
|
+
opt.separator nil
|
|
348
352
|
|
|
349
|
-
|
|
353
|
+
opt.on("--dump=CACHE",
|
|
354
|
+
"Dump data from an ri cache or data file.") do |value|
|
|
355
|
+
unless File.readable?(value)
|
|
356
|
+
abort "#{value.inspect} is not readable"
|
|
357
|
+
end
|
|
350
358
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
abort "#{value.inspect} is not readable"
|
|
355
|
-
end
|
|
359
|
+
if File.directory?(value)
|
|
360
|
+
abort "#{value.inspect} is a directory"
|
|
361
|
+
end
|
|
356
362
|
|
|
357
|
-
|
|
358
|
-
|
|
363
|
+
options[:dump_path] = File.new(value)
|
|
364
|
+
end
|
|
359
365
|
end
|
|
360
366
|
|
|
361
|
-
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
argv = ENV['RI'].to_s.split(' ').concat argv
|
|
367
|
+
argv = ENV['RI'].to_s.split(' ').concat argv
|
|
366
368
|
|
|
367
|
-
|
|
369
|
+
opts.parse! argv
|
|
368
370
|
|
|
369
|
-
|
|
371
|
+
options[:names] = argv
|
|
370
372
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
373
|
+
options[:use_stdout] ||= !$stdout.tty?
|
|
374
|
+
options[:use_stdout] ||= options[:interactive]
|
|
375
|
+
options[:width] ||= 72
|
|
374
376
|
|
|
375
|
-
|
|
377
|
+
options
|
|
376
378
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
379
|
+
rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
|
|
380
|
+
puts opts
|
|
381
|
+
puts
|
|
382
|
+
puts e
|
|
383
|
+
exit 1
|
|
384
|
+
end
|
|
383
385
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
+
##
|
|
387
|
+
# Runs the ri command line executable using +argv+
|
|
386
388
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
+
def self.run(argv = ARGV)
|
|
390
|
+
options = process_args argv
|
|
389
391
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
392
|
+
if options[:dump_path]
|
|
393
|
+
dump options[:dump_path]
|
|
394
|
+
return
|
|
395
|
+
end
|
|
394
396
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
397
|
+
ri = new options
|
|
398
|
+
ri.run
|
|
399
|
+
end
|
|
398
400
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
+
##
|
|
402
|
+
# Creates a new driver using +initial_options+ from ::process_args
|
|
401
403
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
404
|
+
def initialize(initial_options = {})
|
|
405
|
+
@paging = false
|
|
406
|
+
@classes = nil
|
|
405
407
|
|
|
406
|
-
|
|
408
|
+
options = self.class.default_options.update(initial_options)
|
|
407
409
|
|
|
408
|
-
|
|
410
|
+
@formatter_klass = options[:formatter]
|
|
409
411
|
|
|
410
|
-
|
|
412
|
+
require 'profile' if options[:profile]
|
|
411
413
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
+
@names = options[:names]
|
|
415
|
+
@list = options[:list]
|
|
414
416
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
+
@doc_dirs = []
|
|
418
|
+
@stores = []
|
|
417
419
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
420
|
+
RI::Paths.each(options[:use_system], options[:use_site],
|
|
421
|
+
options[:use_home], options[:use_gems],
|
|
422
|
+
*options[:extra_doc_dirs]) do |path, type|
|
|
423
|
+
@doc_dirs << path
|
|
422
424
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
425
|
+
store = RI::Store.new(Options.new, path: path, type: type)
|
|
426
|
+
store.load_cache
|
|
427
|
+
@stores << store
|
|
428
|
+
end
|
|
427
429
|
|
|
428
|
-
|
|
430
|
+
@list_doc_dirs = options[:list_doc_dirs]
|
|
429
431
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
432
|
+
@interactive = options[:interactive]
|
|
433
|
+
@server = options[:server]
|
|
434
|
+
@use_stdout = options[:use_stdout]
|
|
435
|
+
@show_all = options[:show_all]
|
|
436
|
+
@width = options[:width]
|
|
437
|
+
@expand_refs = options[:expand_refs]
|
|
438
|
+
end
|
|
437
439
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
+
##
|
|
441
|
+
# Adds paths for undocumented classes +also_in+ to +out+
|
|
440
442
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
+
def add_also_in(out, also_in)
|
|
444
|
+
return if also_in.empty?
|
|
443
445
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
+
out << Markup::Rule.new(1)
|
|
447
|
+
out << Markup::Paragraph.new("Also found in:")
|
|
446
448
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
449
|
+
paths = Markup::Verbatim.new
|
|
450
|
+
also_in.each do |store|
|
|
451
|
+
paths.parts.push store.friendly_path, "\n"
|
|
452
|
+
end
|
|
453
|
+
out << paths
|
|
454
|
+
end
|
|
453
455
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
456
|
+
##
|
|
457
|
+
# Adds a class header to +out+ for class +name+ which is described in
|
|
458
|
+
# +classes+.
|
|
457
459
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
460
|
+
def add_class(out, name, classes)
|
|
461
|
+
heading = if classes.all? { |klass| klass.module? }
|
|
462
|
+
name
|
|
463
|
+
else
|
|
464
|
+
superclass = classes.map do |klass|
|
|
465
|
+
klass.superclass unless klass.module?
|
|
466
|
+
end.compact.shift || 'Object'
|
|
465
467
|
|
|
466
|
-
|
|
468
|
+
superclass = superclass.full_name unless String === superclass
|
|
467
469
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
+
"#{name} < #{superclass}"
|
|
471
|
+
end
|
|
470
472
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
473
|
+
out << Markup::Heading.new(1, heading)
|
|
474
|
+
out << Markup::BlankLine.new
|
|
475
|
+
end
|
|
474
476
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
+
##
|
|
478
|
+
# Adds "(from ...)" to +out+ for +store+
|
|
477
479
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
480
|
+
def add_from(out, store)
|
|
481
|
+
out << Markup::Paragraph.new("(from #{store.friendly_path})")
|
|
482
|
+
end
|
|
481
483
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
+
##
|
|
485
|
+
# Adds +extends+ to +out+
|
|
484
486
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
487
|
+
def add_extends(out, extends)
|
|
488
|
+
add_extension_modules out, 'Extended by', extends
|
|
489
|
+
end
|
|
488
490
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
491
|
+
##
|
|
492
|
+
# Adds a list of +extensions+ to this module of the given +type+ to +out+.
|
|
493
|
+
# add_includes and add_extends call this, so you should use those directly.
|
|
492
494
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
+
def add_extension_modules(out, type, extensions)
|
|
496
|
+
return if extensions.empty?
|
|
495
497
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
+
out << Markup::Rule.new(1)
|
|
499
|
+
out << Markup::Heading.new(1, "#{type}:")
|
|
498
500
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
501
|
+
extensions.each do |modules, store|
|
|
502
|
+
if modules.length == 1
|
|
503
|
+
add_extension_modules_single out, store, modules.first
|
|
504
|
+
else
|
|
505
|
+
add_extension_modules_multiple out, store, modules
|
|
506
|
+
end
|
|
507
|
+
end
|
|
504
508
|
end
|
|
505
|
-
end
|
|
506
|
-
end
|
|
507
509
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
+
##
|
|
511
|
+
# Renders multiple included +modules+ from +store+ to +out+.
|
|
510
512
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
+
def add_extension_modules_multiple(out, store, modules) # :nodoc:
|
|
514
|
+
out << Markup::Paragraph.new("(from #{store.friendly_path})")
|
|
513
515
|
|
|
514
|
-
|
|
516
|
+
wout, with = modules.partition { |incl| incl.comment.empty? }
|
|
515
517
|
|
|
516
|
-
|
|
518
|
+
out << Markup::BlankLine.new unless with.empty?
|
|
517
519
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
520
|
+
with.each do |incl|
|
|
521
|
+
out << Markup::Paragraph.new(incl.name)
|
|
522
|
+
out << Markup::BlankLine.new
|
|
523
|
+
out << incl.comment.parse
|
|
524
|
+
end
|
|
523
525
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
+
unless wout.empty?
|
|
527
|
+
verb = Markup::Verbatim.new
|
|
526
528
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
529
|
+
wout.each do |incl|
|
|
530
|
+
verb.push incl.name, "\n"
|
|
531
|
+
end
|
|
530
532
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
533
|
+
out << verb
|
|
534
|
+
end
|
|
535
|
+
end
|
|
534
536
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
+
##
|
|
538
|
+
# Adds a single extension module +include+ from +store+ to +out+
|
|
537
539
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
540
|
+
def add_extension_modules_single(out, store, include) # :nodoc:
|
|
541
|
+
name = include.name
|
|
542
|
+
path = store.friendly_path
|
|
543
|
+
out << Markup::Paragraph.new("#{name} (from #{path})")
|
|
542
544
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
545
|
+
if include.comment
|
|
546
|
+
out << Markup::BlankLine.new
|
|
547
|
+
out << include.comment.parse
|
|
548
|
+
end
|
|
549
|
+
end
|
|
548
550
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
+
##
|
|
552
|
+
# Adds +includes+ to +out+
|
|
551
553
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
554
|
+
def add_includes(out, includes)
|
|
555
|
+
add_extension_modules out, 'Includes', includes
|
|
556
|
+
end
|
|
555
557
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
+
##
|
|
559
|
+
# Looks up the method +name+ and adds it to +out+
|
|
558
560
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
561
|
+
def add_method(out, name)
|
|
562
|
+
filtered = lookup_method name
|
|
563
|
+
method_document out, name, filtered
|
|
564
|
+
end
|
|
563
565
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
+
##
|
|
567
|
+
# Adds documentation for all methods in +klass+ to +out+
|
|
566
568
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
569
|
+
def add_method_documentation(out, klass)
|
|
570
|
+
klass.method_list.each do |method|
|
|
571
|
+
begin
|
|
572
|
+
add_method out, method.full_name
|
|
573
|
+
rescue NotFoundError
|
|
574
|
+
next
|
|
575
|
+
end
|
|
576
|
+
end
|
|
573
577
|
end
|
|
574
|
-
end
|
|
575
|
-
end
|
|
576
578
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
+
##
|
|
580
|
+
# Adds a list of +methods+ to +out+ with a heading of +name+
|
|
579
581
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
+
def add_method_list(out, methods, name)
|
|
583
|
+
return if methods.empty?
|
|
582
584
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
+
out << Markup::Heading.new(1, "#{name}:")
|
|
586
|
+
out << Markup::BlankLine.new
|
|
585
587
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
588
|
+
if @use_stdout and !@interactive
|
|
589
|
+
out.concat methods.map { |method|
|
|
590
|
+
Markup::Verbatim.new method
|
|
591
|
+
}
|
|
592
|
+
else
|
|
593
|
+
out << Markup::IndentedParagraph.new(2, methods.join(', '))
|
|
594
|
+
end
|
|
593
595
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
+
out << Markup::BlankLine.new
|
|
597
|
+
end
|
|
596
598
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
+
##
|
|
600
|
+
# Returns ancestor classes of +klass+
|
|
599
601
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
+
def ancestors_of(klass)
|
|
603
|
+
ancestors = []
|
|
602
604
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
+
unexamined = [klass]
|
|
606
|
+
seen = []
|
|
605
607
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
608
|
+
loop do
|
|
609
|
+
break if unexamined.empty?
|
|
610
|
+
current = unexamined.shift
|
|
611
|
+
seen << current
|
|
610
612
|
|
|
611
|
-
|
|
613
|
+
stores = classes[current]
|
|
612
614
|
|
|
613
|
-
|
|
615
|
+
next unless stores and not stores.empty?
|
|
614
616
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
617
|
+
klasses = stores.flat_map do |store|
|
|
618
|
+
store.ancestors[current] || []
|
|
619
|
+
end.uniq
|
|
618
620
|
|
|
619
|
-
|
|
621
|
+
klasses = klasses - seen
|
|
620
622
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
623
|
+
ancestors.concat klasses
|
|
624
|
+
unexamined.concat klasses
|
|
625
|
+
end
|
|
624
626
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
+
ancestors.reverse
|
|
628
|
+
end
|
|
627
629
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
+
##
|
|
631
|
+
# For RubyGems backwards compatibility
|
|
630
632
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
+
def class_cache # :nodoc:
|
|
634
|
+
end
|
|
633
635
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
+
##
|
|
637
|
+
# Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+
|
|
636
638
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
+
def class_document(name, found, klasses, includes, extends)
|
|
640
|
+
also_in = []
|
|
639
641
|
|
|
640
|
-
|
|
642
|
+
out = Markup::Document.new
|
|
641
643
|
|
|
642
|
-
|
|
644
|
+
add_class out, name, klasses
|
|
643
645
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
+
add_includes out, includes
|
|
647
|
+
add_extends out, extends
|
|
646
648
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
649
|
+
found.each do |store, klass|
|
|
650
|
+
render_class out, store, klass, also_in
|
|
651
|
+
end
|
|
650
652
|
|
|
651
|
-
|
|
653
|
+
add_also_in out, also_in
|
|
652
654
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
655
|
+
expand_rdoc_refs_at_the_bottom(out)
|
|
656
|
+
out
|
|
657
|
+
end
|
|
656
658
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
+
##
|
|
660
|
+
# Adds the class +comment+ to +out+.
|
|
659
661
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
662
|
+
def class_document_comment(out, document) # :nodoc:
|
|
663
|
+
unless document.empty?
|
|
664
|
+
out << Markup::Rule.new(1)
|
|
663
665
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
666
|
+
if document.merged?
|
|
667
|
+
parts = document.parts
|
|
668
|
+
parts = parts.zip [Markup::BlankLine.new] * parts.length
|
|
669
|
+
parts.flatten!
|
|
670
|
+
parts.pop
|
|
669
671
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
672
|
+
out.concat parts
|
|
673
|
+
else
|
|
674
|
+
out << comment
|
|
675
|
+
end
|
|
676
|
+
end
|
|
673
677
|
end
|
|
674
|
-
end
|
|
675
|
-
end
|
|
676
678
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
+
##
|
|
680
|
+
# Adds the constants from +klass+ to the Document +out+.
|
|
679
681
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
+
def class_document_constants(out, klass) # :nodoc:
|
|
683
|
+
return if klass.constants.empty?
|
|
682
684
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
685
|
+
out << Markup::Heading.new(1, "Constants:")
|
|
686
|
+
out << Markup::BlankLine.new
|
|
687
|
+
list = Markup::List.new :NOTE
|
|
686
688
|
|
|
687
|
-
|
|
689
|
+
constants = klass.constants.sort_by { |constant| constant.name }
|
|
688
690
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
691
|
+
list.items.concat constants.map { |constant|
|
|
692
|
+
parts = constant.comment.parse.parts
|
|
693
|
+
parts << Markup::Paragraph.new('[not documented]') if
|
|
694
|
+
parts.empty?
|
|
693
695
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
+
Markup::ListItem.new(constant.name, *parts)
|
|
697
|
+
}
|
|
696
698
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
699
|
+
out << list
|
|
700
|
+
out << Markup::BlankLine.new
|
|
701
|
+
end
|
|
700
702
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
+
##
|
|
704
|
+
# Hash mapping a known class or module to the stores it can be loaded from
|
|
703
705
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
+
def classes
|
|
707
|
+
return @classes if @classes
|
|
706
708
|
|
|
707
|
-
|
|
709
|
+
@classes = {}
|
|
708
710
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
@classes
|
|
718
|
-
end
|
|
711
|
+
@stores.each do |store|
|
|
712
|
+
store.cache[:modules].each do |mod|
|
|
713
|
+
# using default block causes searched-for modules to be added
|
|
714
|
+
@classes[mod] ||= []
|
|
715
|
+
@classes[mod] << store
|
|
716
|
+
end
|
|
717
|
+
end
|
|
719
718
|
|
|
720
|
-
|
|
721
|
-
# Returns the stores wherein +name+ is found along with the classes,
|
|
722
|
-
# extends and includes that match it
|
|
723
|
-
|
|
724
|
-
def classes_and_includes_and_extends_for(name)
|
|
725
|
-
klasses = []
|
|
726
|
-
extends = []
|
|
727
|
-
includes = []
|
|
728
|
-
|
|
729
|
-
found = @stores.map do |store|
|
|
730
|
-
begin
|
|
731
|
-
klass = store.load_class name
|
|
732
|
-
klasses << klass
|
|
733
|
-
extends << [klass.extends, store] if klass.extends
|
|
734
|
-
includes << [klass.includes, store] if klass.includes
|
|
735
|
-
[store, klass]
|
|
736
|
-
rescue RDoc::Store::MissingFileError
|
|
719
|
+
@classes
|
|
737
720
|
end
|
|
738
|
-
end.compact
|
|
739
721
|
|
|
740
|
-
|
|
741
|
-
|
|
722
|
+
##
|
|
723
|
+
# Returns the stores wherein +name+ is found along with the classes,
|
|
724
|
+
# extends and includes that match it
|
|
725
|
+
|
|
726
|
+
def classes_and_includes_and_extends_for(name)
|
|
727
|
+
klasses = []
|
|
728
|
+
extends = []
|
|
729
|
+
includes = []
|
|
730
|
+
|
|
731
|
+
found = @stores.map do |store|
|
|
732
|
+
begin
|
|
733
|
+
klass = store.load_class name
|
|
734
|
+
klasses << klass
|
|
735
|
+
extends << [klass.extends, store] if klass.extends
|
|
736
|
+
includes << [klass.includes, store] if klass.includes
|
|
737
|
+
[store, klass]
|
|
738
|
+
rescue ::RDoc::Store::MissingFileError
|
|
739
|
+
end
|
|
740
|
+
end.compact
|
|
742
741
|
|
|
743
|
-
|
|
744
|
-
|
|
742
|
+
extends.reject! do |modules,| modules.empty? end
|
|
743
|
+
includes.reject! do |modules,| modules.empty? end
|
|
745
744
|
|
|
746
|
-
|
|
747
|
-
|
|
745
|
+
[found, klasses, includes, extends]
|
|
746
|
+
end
|
|
748
747
|
|
|
749
|
-
|
|
750
|
-
|
|
748
|
+
##
|
|
749
|
+
# Completes +name+ based on the caches. For Readline
|
|
751
750
|
|
|
752
|
-
|
|
751
|
+
def complete(name)
|
|
752
|
+
completions = []
|
|
753
753
|
|
|
754
|
-
|
|
755
|
-
complete_method name, klass, selector, completions
|
|
754
|
+
klass, selector, method = parse_name name
|
|
756
755
|
|
|
757
|
-
|
|
758
|
-
|
|
756
|
+
complete_klass name, klass, selector, method, completions
|
|
757
|
+
complete_method name, klass, selector, completions
|
|
759
758
|
|
|
760
|
-
|
|
761
|
-
|
|
759
|
+
completions.uniq.select {|s| s.start_with? name }.sort
|
|
760
|
+
end
|
|
762
761
|
|
|
763
|
-
|
|
764
|
-
|
|
762
|
+
def complete_klass(name, klass, selector, method, completions) # :nodoc:
|
|
763
|
+
klasses = classes.keys
|
|
765
764
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
completions.concat klasses.grep(/^#{Regexp.escape name}[^:]*$/) if
|
|
769
|
-
name =~ /::$/
|
|
765
|
+
# may need to include Foo when given Foo::
|
|
766
|
+
klass_name = method ? name : klass
|
|
770
767
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
completions << klass_name
|
|
776
|
-
end
|
|
777
|
-
end
|
|
768
|
+
if name !~ /#|\./
|
|
769
|
+
completions.replace klasses.grep(/^#{Regexp.escape klass_name}[^:]*$/)
|
|
770
|
+
completions.concat klasses.grep(/^#{Regexp.escape name}[^:]*$/) if
|
|
771
|
+
name =~ /::$/
|
|
778
772
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
completions.delete klass
|
|
786
|
-
elsif selector then
|
|
787
|
-
# replace Foo with Foo:: as given
|
|
788
|
-
completions.delete klass
|
|
789
|
-
completions << "#{klass}#{selector}"
|
|
773
|
+
completions << klass if classes.key? klass # to complete a method name
|
|
774
|
+
elsif selector
|
|
775
|
+
completions << klass if classes.key? klass
|
|
776
|
+
elsif classes.key? klass_name
|
|
777
|
+
completions << klass_name
|
|
778
|
+
end
|
|
790
779
|
end
|
|
791
780
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
781
|
+
def complete_method(name, klass, selector, completions) # :nodoc:
|
|
782
|
+
if completions.include? klass and name =~ /#|\.|::/
|
|
783
|
+
methods = list_methods_matching name
|
|
784
|
+
|
|
785
|
+
if not methods.empty?
|
|
786
|
+
# remove Foo if given Foo:: and a method was found
|
|
787
|
+
completions.delete klass
|
|
788
|
+
elsif selector
|
|
789
|
+
# replace Foo with Foo:: as given
|
|
790
|
+
completions.delete klass
|
|
791
|
+
completions << "#{klass}#{selector}"
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
methods.each do |klass_sel_method|
|
|
795
|
+
match = klass_sel_method.match(/^(.+)(#|\.|::)([^#.:]+)$/)
|
|
796
|
+
# match[2] is `::` for class method and `#` for instance method.
|
|
797
|
+
# To be consistent with old completion that completes `['Foo#i', 'Foo::c']` for `Foo.`,
|
|
798
|
+
# `.` should be a wildcard for both `#` and `::` here.
|
|
799
|
+
if match && match[2] == selector || selector == '.'
|
|
800
|
+
completions << match[1] + selector + match[3]
|
|
801
|
+
end
|
|
802
|
+
end
|
|
799
803
|
end
|
|
800
804
|
end
|
|
801
|
-
end
|
|
802
|
-
end
|
|
803
805
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
+
##
|
|
807
|
+
# Converts +document+ to text and writes it to the pager
|
|
806
808
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
809
|
+
def display(document)
|
|
810
|
+
page do |io|
|
|
811
|
+
f = formatter(io)
|
|
812
|
+
f.width = @width if @width and f.respond_to?(:width)
|
|
813
|
+
text = document.accept f
|
|
812
814
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
815
|
+
io.write text
|
|
816
|
+
end
|
|
817
|
+
end
|
|
816
818
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
+
##
|
|
820
|
+
# Outputs formatted RI data for class +name+. Groups undocumented classes
|
|
819
821
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
+
def display_class(name)
|
|
823
|
+
_klass, selector, _method = parse_name name
|
|
824
|
+
return if selector
|
|
822
825
|
|
|
823
|
-
|
|
824
|
-
|
|
826
|
+
found, klasses, includes, extends =
|
|
827
|
+
classes_and_includes_and_extends_for name
|
|
825
828
|
|
|
826
|
-
|
|
829
|
+
return if found.empty?
|
|
827
830
|
|
|
828
|
-
|
|
831
|
+
out = class_document name, found, klasses, includes, extends
|
|
829
832
|
|
|
830
|
-
|
|
831
|
-
|
|
833
|
+
display out
|
|
834
|
+
end
|
|
832
835
|
|
|
833
|
-
|
|
834
|
-
|
|
836
|
+
##
|
|
837
|
+
# Outputs formatted RI data for method +name+
|
|
835
838
|
|
|
836
|
-
|
|
837
|
-
|
|
839
|
+
def display_method(name)
|
|
840
|
+
out = Markup::Document.new
|
|
838
841
|
|
|
839
|
-
|
|
842
|
+
add_method out, name
|
|
840
843
|
|
|
841
|
-
|
|
844
|
+
expand_rdoc_refs_at_the_bottom(out)
|
|
842
845
|
|
|
843
|
-
|
|
844
|
-
|
|
846
|
+
display out
|
|
847
|
+
end
|
|
845
848
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
849
|
+
##
|
|
850
|
+
# Outputs formatted RI data for the class or method +name+.
|
|
851
|
+
#
|
|
852
|
+
# Returns true if +name+ was found, false if it was not an alternative could
|
|
853
|
+
# be guessed, raises an error if +name+ couldn't be guessed.
|
|
851
854
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
855
|
+
def display_name(name)
|
|
856
|
+
if name =~ /\w:(\w|$)/
|
|
857
|
+
display_page name
|
|
858
|
+
return true
|
|
859
|
+
end
|
|
857
860
|
|
|
858
|
-
|
|
861
|
+
return true if display_class name
|
|
859
862
|
|
|
860
|
-
|
|
863
|
+
display_method name if name =~ /::|#|\./
|
|
861
864
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
865
|
+
true
|
|
866
|
+
rescue NotFoundError
|
|
867
|
+
matches = list_methods_matching name if name =~ /::|#|\./
|
|
868
|
+
matches = classes.keys.grep(/^#{Regexp.escape name}/) if matches.empty?
|
|
866
869
|
|
|
867
|
-
|
|
870
|
+
raise if matches.empty?
|
|
868
871
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
872
|
+
page do |io|
|
|
873
|
+
io.puts "#{name} not found, maybe you meant:"
|
|
874
|
+
io.puts
|
|
875
|
+
io.puts matches.sort.join("\n")
|
|
876
|
+
end
|
|
874
877
|
|
|
875
|
-
|
|
876
|
-
|
|
878
|
+
false
|
|
879
|
+
end
|
|
877
880
|
|
|
878
|
-
|
|
879
|
-
|
|
881
|
+
##
|
|
882
|
+
# Displays each name in +name+
|
|
880
883
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
+
def display_names(names)
|
|
885
|
+
names.each do |name|
|
|
886
|
+
name = expand_name name
|
|
884
887
|
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
+
display_name name
|
|
889
|
+
end
|
|
890
|
+
end
|
|
888
891
|
|
|
889
|
-
|
|
890
|
-
|
|
892
|
+
##
|
|
893
|
+
# Outputs formatted RI data for page +name+.
|
|
891
894
|
|
|
892
|
-
|
|
893
|
-
|
|
895
|
+
def display_page(name)
|
|
896
|
+
store_name, page_name = name.split ':', 2
|
|
894
897
|
|
|
895
|
-
|
|
898
|
+
store = @stores.find { |s| s.source == store_name }
|
|
896
899
|
|
|
897
|
-
|
|
900
|
+
return display_page_list store if page_name.empty?
|
|
898
901
|
|
|
899
|
-
|
|
902
|
+
pages = store.cache[:pages]
|
|
900
903
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
904
|
+
unless pages.include? page_name
|
|
905
|
+
found_names = pages.select do |n|
|
|
906
|
+
n =~ /#{Regexp.escape page_name}\.[^.]+$/
|
|
907
|
+
end
|
|
905
908
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
909
|
+
if found_names.length.zero?
|
|
910
|
+
return display_page_list store, pages
|
|
911
|
+
elsif found_names.length > 1
|
|
912
|
+
return display_page_list store, found_names, page_name
|
|
913
|
+
end
|
|
911
914
|
|
|
912
|
-
|
|
913
|
-
|
|
915
|
+
page_name = found_names.first
|
|
916
|
+
end
|
|
914
917
|
|
|
915
|
-
|
|
918
|
+
page = store.load_page page_name
|
|
916
919
|
|
|
917
|
-
|
|
918
|
-
|
|
920
|
+
display page.comment.parse
|
|
921
|
+
end
|
|
919
922
|
|
|
920
|
-
|
|
921
|
-
|
|
923
|
+
##
|
|
924
|
+
# Outputs a formatted RI page list for the pages in +store+.
|
|
922
925
|
|
|
923
|
-
|
|
924
|
-
|
|
926
|
+
def display_page_list(store, pages = store.cache[:pages], search = nil)
|
|
927
|
+
out = Markup::Document.new
|
|
925
928
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
929
|
+
title = if search
|
|
930
|
+
"#{search} pages"
|
|
931
|
+
else
|
|
932
|
+
'Pages'
|
|
933
|
+
end
|
|
931
934
|
|
|
932
|
-
|
|
933
|
-
|
|
935
|
+
out << Markup::Heading.new(1, "#{title} in #{store.friendly_path}")
|
|
936
|
+
out << Markup::BlankLine.new
|
|
934
937
|
|
|
935
|
-
|
|
938
|
+
list = Markup::List.new(:BULLET)
|
|
936
939
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
+
pages.each do |page|
|
|
941
|
+
list << Markup::Paragraph.new(page)
|
|
942
|
+
end
|
|
940
943
|
|
|
941
|
-
|
|
944
|
+
out << list
|
|
942
945
|
|
|
943
|
-
|
|
944
|
-
|
|
946
|
+
display out
|
|
947
|
+
end
|
|
945
948
|
|
|
946
|
-
|
|
947
|
-
if defined? DidYouMean::SpellChecker
|
|
948
|
-
true
|
|
949
|
-
else
|
|
950
|
-
begin
|
|
951
|
-
require 'did_you_mean'
|
|
949
|
+
def check_did_you_mean # :nodoc:
|
|
952
950
|
if defined? DidYouMean::SpellChecker
|
|
953
951
|
true
|
|
954
952
|
else
|
|
955
|
-
|
|
953
|
+
begin
|
|
954
|
+
require 'did_you_mean'
|
|
955
|
+
if defined? DidYouMean::SpellChecker
|
|
956
|
+
true
|
|
957
|
+
else
|
|
958
|
+
false
|
|
959
|
+
end
|
|
960
|
+
rescue LoadError
|
|
961
|
+
false
|
|
962
|
+
end
|
|
956
963
|
end
|
|
957
|
-
rescue LoadError
|
|
958
|
-
false
|
|
959
964
|
end
|
|
960
|
-
end
|
|
961
|
-
end
|
|
962
965
|
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
966
|
+
##
|
|
967
|
+
# Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da"
|
|
968
|
+
# will be expanded to Zlib::DataError.
|
|
969
|
+
|
|
970
|
+
def expand_class(klass)
|
|
971
|
+
class_names = classes.keys
|
|
972
|
+
ary = class_names.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z"))
|
|
973
|
+
if ary.length != 1 && ary.first != klass
|
|
974
|
+
if check_did_you_mean
|
|
975
|
+
suggestion_proc = -> { DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass) }
|
|
976
|
+
raise NotFoundError.new(klass, suggestion_proc)
|
|
977
|
+
else
|
|
978
|
+
raise NotFoundError, klass
|
|
979
|
+
end
|
|
980
|
+
end
|
|
981
|
+
ary.first
|
|
976
982
|
end
|
|
977
|
-
end
|
|
978
|
-
ary.first
|
|
979
|
-
end
|
|
980
983
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
+
##
|
|
985
|
+
# Expands the class portion of +name+ into a fully-qualified class. See
|
|
986
|
+
# #expand_class.
|
|
984
987
|
|
|
985
|
-
|
|
986
|
-
|
|
988
|
+
def expand_name(name)
|
|
989
|
+
klass, selector, method = parse_name name
|
|
987
990
|
|
|
988
|
-
|
|
991
|
+
return [selector, method].join if klass.empty?
|
|
989
992
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
993
|
+
case selector
|
|
994
|
+
when ':'
|
|
995
|
+
[find_store(klass), selector, method]
|
|
996
|
+
else
|
|
997
|
+
[expand_class(klass), selector, method]
|
|
998
|
+
end.join
|
|
999
|
+
end
|
|
997
1000
|
|
|
998
|
-
|
|
999
|
-
|
|
1001
|
+
##
|
|
1002
|
+
# Filters the methods in +found+ trying to find a match for +name+.
|
|
1000
1003
|
|
|
1001
|
-
|
|
1002
|
-
|
|
1004
|
+
def filter_methods(found, name)
|
|
1005
|
+
regexp = name_regexp name
|
|
1003
1006
|
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
+
filtered = found.find_all do |store, methods|
|
|
1008
|
+
methods.any? { |method| method.full_name =~ regexp }
|
|
1009
|
+
end
|
|
1007
1010
|
|
|
1008
|
-
|
|
1011
|
+
return filtered unless filtered.empty?
|
|
1009
1012
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1013
|
+
found
|
|
1014
|
+
end
|
|
1012
1015
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1016
|
+
##
|
|
1017
|
+
# Yields items matching +name+ including the store they were found in, the
|
|
1018
|
+
# class being searched for, the class they were found in (an ancestor) the
|
|
1019
|
+
# types of methods to look up (from #method_type), and the method name being
|
|
1020
|
+
# searched for
|
|
1018
1021
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1022
|
+
def find_methods(name)
|
|
1023
|
+
klass, selector, method = parse_name name
|
|
1021
1024
|
|
|
1022
|
-
|
|
1025
|
+
types = method_type selector
|
|
1023
1026
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1027
|
+
klasses = nil
|
|
1028
|
+
ambiguous = klass.empty?
|
|
1026
1029
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1030
|
+
if ambiguous
|
|
1031
|
+
klasses = classes.keys
|
|
1032
|
+
else
|
|
1033
|
+
klasses = ancestors_of klass
|
|
1034
|
+
klasses.unshift klass
|
|
1035
|
+
end
|
|
1033
1036
|
|
|
1034
|
-
|
|
1037
|
+
methods = []
|
|
1035
1038
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1039
|
+
klasses.each do |ancestor|
|
|
1040
|
+
ancestors = classes[ancestor]
|
|
1038
1041
|
|
|
1039
|
-
|
|
1042
|
+
next unless ancestors
|
|
1040
1043
|
|
|
1041
|
-
|
|
1044
|
+
klass = ancestor if ambiguous
|
|
1042
1045
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1046
|
+
ancestors.each do |store|
|
|
1047
|
+
methods << [store, klass, ancestor, types, method]
|
|
1048
|
+
end
|
|
1049
|
+
end
|
|
1047
1050
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
+
methods = methods.sort_by do |_, k, a, _, m|
|
|
1052
|
+
[k, a, m].compact
|
|
1053
|
+
end
|
|
1051
1054
|
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
+
methods.each do |item|
|
|
1056
|
+
yield(*item) # :yields: store, klass, ancestor, types, method
|
|
1057
|
+
end
|
|
1055
1058
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1059
|
+
self
|
|
1060
|
+
end
|
|
1058
1061
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1062
|
+
##
|
|
1063
|
+
# Finds a store that matches +name+ which can be the name of a gem, "ruby",
|
|
1064
|
+
# "home" or "site".
|
|
1065
|
+
#
|
|
1066
|
+
# See also RDoc::Store#source
|
|
1064
1067
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
+
def find_store(name)
|
|
1069
|
+
@stores.each do |store|
|
|
1070
|
+
source = store.source
|
|
1068
1071
|
|
|
1069
|
-
|
|
1072
|
+
return source if source == name
|
|
1070
1073
|
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
+
return source if
|
|
1075
|
+
store.type == :gem and source =~ /^#{Regexp.escape name}-\d/
|
|
1076
|
+
end
|
|
1074
1077
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1078
|
+
raise RI::Driver::NotFoundError, name
|
|
1079
|
+
end
|
|
1077
1080
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
def formatter(io)
|
|
1083
|
-
if @formatter_klass then
|
|
1084
|
-
@formatter_klass.new
|
|
1085
|
-
elsif paging? or !io.tty? then
|
|
1086
|
-
RDoc::Markup::ToBs.new
|
|
1087
|
-
else
|
|
1088
|
-
RDoc::Markup::ToAnsi.new
|
|
1089
|
-
end
|
|
1090
|
-
end
|
|
1081
|
+
##
|
|
1082
|
+
# Creates a new RDoc::Markup::Formatter. If a formatter is given with -f,
|
|
1083
|
+
# use it. If we're outputting to a pager, use bs, otherwise ansi.
|
|
1091
1084
|
|
|
1092
|
-
|
|
1093
|
-
|
|
1085
|
+
def formatter(io)
|
|
1086
|
+
if @formatter_klass
|
|
1087
|
+
@formatter_klass.new
|
|
1088
|
+
elsif paging? or !io.tty?
|
|
1089
|
+
Markup::ToBs.new
|
|
1090
|
+
else
|
|
1091
|
+
Markup::ToAnsi.new
|
|
1092
|
+
end
|
|
1093
|
+
end
|
|
1094
1094
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1095
|
+
##
|
|
1096
|
+
# Runs ri interactively using Readline if it is available.
|
|
1097
1097
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1098
|
+
def interactive
|
|
1099
|
+
puts "\nEnter the method name you want to look up."
|
|
1100
|
+
|
|
1101
|
+
begin
|
|
1102
|
+
require 'readline'
|
|
1103
|
+
rescue LoadError
|
|
1104
|
+
end
|
|
1105
|
+
if defined? Readline
|
|
1106
|
+
Readline.completion_proc = method :complete
|
|
1107
|
+
puts "You can use tab to autocomplete."
|
|
1108
|
+
end
|
|
1106
1109
|
|
|
1107
|
-
|
|
1110
|
+
puts "Enter a blank line to exit.\n\n"
|
|
1108
1111
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1112
|
+
loop do
|
|
1113
|
+
name = if defined? Readline
|
|
1114
|
+
Readline.readline ">> ", true
|
|
1115
|
+
else
|
|
1116
|
+
print ">> "
|
|
1117
|
+
$stdin.gets
|
|
1118
|
+
end
|
|
1116
1119
|
|
|
1117
|
-
|
|
1120
|
+
return if name.nil? or name.empty?
|
|
1118
1121
|
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1122
|
+
begin
|
|
1123
|
+
display_name expand_name(name.strip)
|
|
1124
|
+
rescue NotFoundError => e
|
|
1125
|
+
puts e.message
|
|
1126
|
+
end
|
|
1127
|
+
end
|
|
1128
|
+
|
|
1129
|
+
rescue Interrupt
|
|
1130
|
+
exit
|
|
1123
1131
|
end
|
|
1124
|
-
end
|
|
1125
1132
|
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1133
|
+
##
|
|
1134
|
+
# Lists classes known to ri starting with +names+. If +names+ is empty all
|
|
1135
|
+
# known classes are shown.
|
|
1129
1136
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
# known classes are shown.
|
|
1137
|
+
def list_known_classes(names = [])
|
|
1138
|
+
classes = []
|
|
1133
1139
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1140
|
+
stores.each do |store|
|
|
1141
|
+
classes << store.module_names
|
|
1142
|
+
end
|
|
1136
1143
|
|
|
1137
|
-
|
|
1138
|
-
classes << store.module_names
|
|
1139
|
-
end
|
|
1144
|
+
classes = classes.flatten.uniq.sort
|
|
1140
1145
|
|
|
1141
|
-
|
|
1146
|
+
unless names.empty?
|
|
1147
|
+
filter = Regexp.union names.map { |name| /^#{name}/ }
|
|
1142
1148
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1149
|
+
classes = classes.grep filter
|
|
1150
|
+
end
|
|
1145
1151
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1152
|
+
page do |io|
|
|
1153
|
+
if paging? or io.tty?
|
|
1154
|
+
if names.empty?
|
|
1155
|
+
io.puts "Classes and Modules known to ri:"
|
|
1156
|
+
else
|
|
1157
|
+
io.puts "Classes and Modules starting with #{names.join ', '}:"
|
|
1158
|
+
end
|
|
1159
|
+
io.puts
|
|
1160
|
+
end
|
|
1148
1161
|
|
|
1149
|
-
|
|
1150
|
-
if paging? or io.tty? then
|
|
1151
|
-
if names.empty? then
|
|
1152
|
-
io.puts "Classes and Modules known to ri:"
|
|
1153
|
-
else
|
|
1154
|
-
io.puts "Classes and Modules starting with #{names.join ', '}:"
|
|
1162
|
+
io.puts classes.join("\n")
|
|
1155
1163
|
end
|
|
1156
|
-
io.puts
|
|
1157
1164
|
end
|
|
1158
1165
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
end
|
|
1166
|
+
##
|
|
1167
|
+
# Returns an Array of methods matching +name+
|
|
1162
1168
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1169
|
+
def list_methods_matching(name)
|
|
1170
|
+
found = []
|
|
1165
1171
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1172
|
+
find_methods name do |store, klass, ancestor, types, method|
|
|
1173
|
+
if types == :instance or types == :both
|
|
1174
|
+
methods = store.instance_methods[ancestor]
|
|
1168
1175
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
methods = store.instance_methods[ancestor]
|
|
1176
|
+
if methods
|
|
1177
|
+
matches = methods.grep(/^#{Regexp.escape method.to_s}/)
|
|
1172
1178
|
|
|
1173
|
-
|
|
1174
|
-
|
|
1179
|
+
matches = matches.map do |match|
|
|
1180
|
+
"#{klass}##{match}"
|
|
1181
|
+
end
|
|
1175
1182
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1183
|
+
found.concat matches
|
|
1184
|
+
end
|
|
1178
1185
|
end
|
|
1179
1186
|
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
end
|
|
1187
|
+
if types == :class or types == :both
|
|
1188
|
+
methods = store.class_methods[ancestor]
|
|
1183
1189
|
|
|
1184
|
-
|
|
1185
|
-
|
|
1190
|
+
next unless methods
|
|
1191
|
+
matches = methods.grep(/^#{Regexp.escape method.to_s}/)
|
|
1186
1192
|
|
|
1187
|
-
|
|
1188
|
-
|
|
1193
|
+
matches = matches.map do |match|
|
|
1194
|
+
"#{klass}::#{match}"
|
|
1195
|
+
end
|
|
1189
1196
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1197
|
+
found.concat matches
|
|
1198
|
+
end
|
|
1192
1199
|
end
|
|
1193
1200
|
|
|
1194
|
-
found.
|
|
1201
|
+
found.uniq
|
|
1195
1202
|
end
|
|
1196
|
-
end
|
|
1197
|
-
|
|
1198
|
-
found.uniq
|
|
1199
|
-
end
|
|
1200
1203
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
+
##
|
|
1205
|
+
# Loads RI data for method +name+ on +klass+ from +store+. +type+ and
|
|
1206
|
+
# +cache+ indicate if it is a class or instance method.
|
|
1204
1207
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1208
|
+
def load_method(store, cache, klass, type, name)
|
|
1209
|
+
methods = store.public_send(cache)[klass]
|
|
1207
1210
|
|
|
1208
|
-
|
|
1211
|
+
return unless methods
|
|
1209
1212
|
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
+
method = methods.find do |method_name|
|
|
1214
|
+
method_name == name
|
|
1215
|
+
end
|
|
1213
1216
|
|
|
1214
|
-
|
|
1217
|
+
return unless method
|
|
1215
1218
|
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1219
|
+
store.load_method klass, "#{type}#{method}"
|
|
1220
|
+
rescue ::RDoc::Store::MissingFileError => e
|
|
1221
|
+
comment = Comment.new("missing documentation at #{e.file}")
|
|
1222
|
+
comment.parse
|
|
1220
1223
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1224
|
+
method = AnyMethod.new name
|
|
1225
|
+
method.comment = comment
|
|
1226
|
+
method
|
|
1227
|
+
end
|
|
1225
1228
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1229
|
+
##
|
|
1230
|
+
# Returns an Array of RI data for methods matching +name+
|
|
1228
1231
|
|
|
1229
|
-
|
|
1230
|
-
|
|
1232
|
+
def load_methods_matching(name)
|
|
1233
|
+
found = []
|
|
1231
1234
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1235
|
+
find_methods name do |store, klass, ancestor, types, method|
|
|
1236
|
+
methods = []
|
|
1234
1237
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1238
|
+
methods << load_method(store, :class_methods, ancestor, '::', method) if
|
|
1239
|
+
[:class, :both].include? types
|
|
1237
1240
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1241
|
+
methods << load_method(store, :instance_methods, ancestor, '#', method) if
|
|
1242
|
+
[:instance, :both].include? types
|
|
1240
1243
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1244
|
+
found << [store, methods.compact]
|
|
1245
|
+
end
|
|
1243
1246
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1247
|
+
found.reject do |path, methods| methods.empty? end
|
|
1248
|
+
end
|
|
1246
1249
|
|
|
1247
|
-
|
|
1248
|
-
|
|
1250
|
+
##
|
|
1251
|
+
# Returns a filtered list of methods matching +name+
|
|
1249
1252
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1253
|
+
def lookup_method(name)
|
|
1254
|
+
found = load_methods_matching name
|
|
1252
1255
|
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1256
|
+
if found.empty?
|
|
1257
|
+
if check_did_you_mean
|
|
1258
|
+
methods = []
|
|
1259
|
+
_, _, method_name = parse_name name
|
|
1260
|
+
find_methods name do |store, klass, ancestor, types, method|
|
|
1261
|
+
methods.push(*store.class_methods[klass]) if [:class, :both].include? types
|
|
1262
|
+
methods.push(*store.instance_methods[klass]) if [:instance, :both].include? types
|
|
1263
|
+
end
|
|
1264
|
+
methods = methods.uniq
|
|
1265
|
+
suggestion_proc = -> { DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name) }
|
|
1266
|
+
raise NotFoundError.new(name, suggestion_proc)
|
|
1267
|
+
else
|
|
1268
|
+
raise NotFoundError, name
|
|
1269
|
+
end
|
|
1260
1270
|
end
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
raise NotFoundError.new(name, suggestion_proc)
|
|
1264
|
-
else
|
|
1265
|
-
raise NotFoundError, name
|
|
1271
|
+
|
|
1272
|
+
filter_methods found, name
|
|
1266
1273
|
end
|
|
1267
|
-
end
|
|
1268
1274
|
|
|
1269
|
-
|
|
1270
|
-
|
|
1275
|
+
##
|
|
1276
|
+
# Builds a RDoc::Markup::Document from +found+, +klasses+ and +includes+
|
|
1271
1277
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1278
|
+
def method_document(out, name, filtered)
|
|
1279
|
+
out << Markup::Heading.new(1, name)
|
|
1280
|
+
out << Markup::BlankLine.new
|
|
1274
1281
|
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1282
|
+
filtered.each do |store, methods|
|
|
1283
|
+
methods.each do |method|
|
|
1284
|
+
render_method out, store, method, name
|
|
1285
|
+
end
|
|
1286
|
+
end
|
|
1278
1287
|
|
|
1279
|
-
|
|
1280
|
-
methods.each do |method|
|
|
1281
|
-
render_method out, store, method, name
|
|
1288
|
+
out
|
|
1282
1289
|
end
|
|
1283
|
-
end
|
|
1284
1290
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
##
|
|
1289
|
-
# Returns the type of method (:both, :instance, :class) for +selector+
|
|
1291
|
+
##
|
|
1292
|
+
# Returns the type of method (:both, :instance, :class) for +selector+
|
|
1290
1293
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1294
|
+
def method_type(selector)
|
|
1295
|
+
case selector
|
|
1296
|
+
when '.', nil then :both
|
|
1297
|
+
when '#' then :instance
|
|
1298
|
+
else :class
|
|
1299
|
+
end
|
|
1300
|
+
end
|
|
1298
1301
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
+
##
|
|
1303
|
+
# Returns a regular expression for +name+ that will match an
|
|
1304
|
+
# RDoc::AnyMethod's name.
|
|
1302
1305
|
|
|
1303
|
-
|
|
1304
|
-
|
|
1306
|
+
def name_regexp(name)
|
|
1307
|
+
klass, type, name = parse_name name
|
|
1305
1308
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1309
|
+
case type
|
|
1310
|
+
when '#', '::'
|
|
1311
|
+
/^#{klass}#{type}#{Regexp.escape name}$/
|
|
1312
|
+
else
|
|
1313
|
+
/^#{klass}(#|::)#{Regexp.escape name}$/
|
|
1314
|
+
end
|
|
1315
|
+
end
|
|
1313
1316
|
|
|
1314
|
-
|
|
1315
|
-
|
|
1317
|
+
##
|
|
1318
|
+
# Paginates output through a pager program.
|
|
1316
1319
|
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1320
|
+
def page
|
|
1321
|
+
if pager = setup_pager
|
|
1322
|
+
begin
|
|
1323
|
+
yield pager
|
|
1324
|
+
ensure
|
|
1325
|
+
pager.close
|
|
1326
|
+
end
|
|
1327
|
+
else
|
|
1328
|
+
yield $stdout
|
|
1329
|
+
end
|
|
1330
|
+
rescue Errno::EPIPE
|
|
1321
1331
|
ensure
|
|
1322
|
-
|
|
1332
|
+
@paging = false
|
|
1323
1333
|
end
|
|
1324
|
-
else
|
|
1325
|
-
yield $stdout
|
|
1326
|
-
end
|
|
1327
|
-
rescue Errno::EPIPE
|
|
1328
|
-
ensure
|
|
1329
|
-
@paging = false
|
|
1330
|
-
end
|
|
1331
1334
|
|
|
1332
|
-
|
|
1333
|
-
|
|
1335
|
+
##
|
|
1336
|
+
# Are we using a pager?
|
|
1334
1337
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
+
def paging?
|
|
1339
|
+
@paging
|
|
1340
|
+
end
|
|
1341
|
+
|
|
1342
|
+
##
|
|
1343
|
+
# Extracts the class, selector and method name parts from +name+ like
|
|
1344
|
+
# Foo::Bar#baz.
|
|
1345
|
+
#
|
|
1346
|
+
# NOTE: Given Foo::Bar, Bar is considered a class even though it may be a
|
|
1347
|
+
# method
|
|
1348
|
+
|
|
1349
|
+
def parse_name(name)
|
|
1350
|
+
parts = name.split(/(::?|#|\.)/)
|
|
1351
|
+
|
|
1352
|
+
if parts.length == 1
|
|
1353
|
+
if parts.first =~ /^[a-z]|^([%&*+\/<>^`|~-]|\+@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/
|
|
1354
|
+
type = '.'
|
|
1355
|
+
meth = parts.pop
|
|
1356
|
+
else
|
|
1357
|
+
type = nil
|
|
1358
|
+
meth = nil
|
|
1359
|
+
end
|
|
1360
|
+
elsif parts.length == 2 or parts.last =~ /::|#|\./
|
|
1361
|
+
type = parts.pop
|
|
1362
|
+
meth = nil
|
|
1363
|
+
elsif parts[1] == ':'
|
|
1364
|
+
klass = parts.shift
|
|
1365
|
+
type = parts.shift
|
|
1366
|
+
meth = parts.join
|
|
1367
|
+
elsif parts[-2] != '::' or parts.last !~ /^[A-Z]/
|
|
1368
|
+
meth = parts.pop
|
|
1369
|
+
type = parts.pop
|
|
1370
|
+
end
|
|
1371
|
+
|
|
1372
|
+
klass ||= parts.join
|
|
1338
1373
|
|
|
1339
|
-
|
|
1340
|
-
# Extracts the class, selector and method name parts from +name+ like
|
|
1341
|
-
# Foo::Bar#baz.
|
|
1342
|
-
#
|
|
1343
|
-
# NOTE: Given Foo::Bar, Bar is considered a class even though it may be a
|
|
1344
|
-
# method
|
|
1345
|
-
|
|
1346
|
-
def parse_name(name)
|
|
1347
|
-
parts = name.split(/(::?|#|\.)/)
|
|
1348
|
-
|
|
1349
|
-
if parts.length == 1 then
|
|
1350
|
-
if parts.first =~ /^[a-z]|^([%&*+\/<>^`|~-]|\+@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/ then
|
|
1351
|
-
type = '.'
|
|
1352
|
-
meth = parts.pop
|
|
1353
|
-
else
|
|
1354
|
-
type = nil
|
|
1355
|
-
meth = nil
|
|
1374
|
+
[klass, type, meth]
|
|
1356
1375
|
end
|
|
1357
|
-
elsif parts.length == 2 or parts.last =~ /::|#|\./ then
|
|
1358
|
-
type = parts.pop
|
|
1359
|
-
meth = nil
|
|
1360
|
-
elsif parts[1] == ':' then
|
|
1361
|
-
klass = parts.shift
|
|
1362
|
-
type = parts.shift
|
|
1363
|
-
meth = parts.join
|
|
1364
|
-
elsif parts[-2] != '::' or parts.last !~ /^[A-Z]/ then
|
|
1365
|
-
meth = parts.pop
|
|
1366
|
-
type = parts.pop
|
|
1367
|
-
end
|
|
1368
1376
|
|
|
1369
|
-
|
|
1377
|
+
##
|
|
1378
|
+
# Renders the +klass+ from +store+ to +out+. If the klass has no
|
|
1379
|
+
# documentable items the class is added to +also_in+ instead.
|
|
1380
|
+
|
|
1381
|
+
def render_class(out, store, klass, also_in) # :nodoc:
|
|
1382
|
+
document = klass.comment.parse
|
|
1383
|
+
# TODO the store's cache should always return an empty Array
|
|
1384
|
+
class_methods = store.class_methods[klass.full_name] || []
|
|
1385
|
+
instance_methods = store.instance_methods[klass.full_name] || []
|
|
1386
|
+
attributes = store.attributes[klass.full_name] || []
|
|
1387
|
+
|
|
1388
|
+
if document.empty? and
|
|
1389
|
+
instance_methods.empty? and class_methods.empty?
|
|
1390
|
+
also_in << store
|
|
1391
|
+
return
|
|
1392
|
+
end
|
|
1370
1393
|
|
|
1371
|
-
|
|
1372
|
-
end
|
|
1394
|
+
add_from out, store
|
|
1373
1395
|
|
|
1374
|
-
|
|
1375
|
-
# Renders the +klass+ from +store+ to +out+. If the klass has no
|
|
1376
|
-
# documentable items the class is added to +also_in+ instead.
|
|
1377
|
-
|
|
1378
|
-
def render_class(out, store, klass, also_in) # :nodoc:
|
|
1379
|
-
document = klass.comment.parse
|
|
1380
|
-
# TODO the store's cache should always return an empty Array
|
|
1381
|
-
class_methods = store.class_methods[klass.full_name] || []
|
|
1382
|
-
instance_methods = store.instance_methods[klass.full_name] || []
|
|
1383
|
-
attributes = store.attributes[klass.full_name] || []
|
|
1384
|
-
|
|
1385
|
-
if document.empty? and
|
|
1386
|
-
instance_methods.empty? and class_methods.empty? then
|
|
1387
|
-
also_in << store
|
|
1388
|
-
return
|
|
1389
|
-
end
|
|
1396
|
+
class_document_comment out, document
|
|
1390
1397
|
|
|
1391
|
-
|
|
1398
|
+
if class_methods or instance_methods or not klass.constants.empty?
|
|
1399
|
+
out << Markup::Rule.new(1)
|
|
1400
|
+
end
|
|
1392
1401
|
|
|
1393
|
-
|
|
1402
|
+
class_document_constants out, klass
|
|
1394
1403
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1404
|
+
add_method_list out, class_methods, 'Class methods'
|
|
1405
|
+
add_method_list out, instance_methods, 'Instance methods'
|
|
1406
|
+
add_method_list out, attributes, 'Attributes'
|
|
1398
1407
|
|
|
1399
|
-
|
|
1408
|
+
add_method_documentation out, klass if @show_all
|
|
1409
|
+
end
|
|
1400
1410
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
add_method_list out, attributes, 'Attributes'
|
|
1411
|
+
def render_method(out, store, method, name) # :nodoc:
|
|
1412
|
+
out << Markup::Paragraph.new("(from #{store.friendly_path})")
|
|
1404
1413
|
|
|
1405
|
-
|
|
1406
|
-
|
|
1414
|
+
unless name =~ /^#{Regexp.escape method.parent_name}/
|
|
1415
|
+
out << Markup::Heading.new(3, "Implementation from #{method.parent_name}")
|
|
1416
|
+
end
|
|
1407
1417
|
|
|
1408
|
-
|
|
1409
|
-
out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
|
|
1418
|
+
out << Markup::Rule.new(1)
|
|
1410
1419
|
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1420
|
+
render_method_arguments out, method.arglists
|
|
1421
|
+
sig = method.type_signature_lines || store.rbs_signature_for(method)
|
|
1422
|
+
render_method_type_signature out, sig if sig
|
|
1423
|
+
render_method_superclass out, method
|
|
1424
|
+
if method.is_alias_for
|
|
1425
|
+
al = method.is_alias_for
|
|
1426
|
+
alias_for = store.load_method al.parent_name, "#{al.name_prefix}#{al.name}"
|
|
1427
|
+
render_method_comment out, method, alias_for
|
|
1428
|
+
else
|
|
1429
|
+
render_method_comment out, method
|
|
1430
|
+
end
|
|
1431
|
+
end
|
|
1414
1432
|
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
render_method_arguments out, method.arglists
|
|
1418
|
-
sig = method.type_signature_lines || store.rbs_signature_for(method)
|
|
1419
|
-
render_method_type_signature out, sig if sig
|
|
1420
|
-
render_method_superclass out, method
|
|
1421
|
-
if method.is_alias_for
|
|
1422
|
-
al = method.is_alias_for
|
|
1423
|
-
alias_for = store.load_method al.parent_name, "#{al.name_prefix}#{al.name}"
|
|
1424
|
-
render_method_comment out, method, alias_for
|
|
1425
|
-
else
|
|
1426
|
-
render_method_comment out, method
|
|
1427
|
-
end
|
|
1428
|
-
end
|
|
1433
|
+
def render_method_arguments(out, arglists) # :nodoc:
|
|
1434
|
+
return unless arglists
|
|
1429
1435
|
|
|
1430
|
-
|
|
1431
|
-
|
|
1436
|
+
arglists = arglists.chomp.split "\n"
|
|
1437
|
+
arglists = arglists.map { |line| line + "\n" }
|
|
1438
|
+
out << Markup::Verbatim.new(*arglists)
|
|
1439
|
+
out << Markup::Rule.new(1)
|
|
1440
|
+
end
|
|
1432
1441
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1442
|
+
def render_method_comment(out, method, alias_for = nil)# :nodoc:
|
|
1443
|
+
if alias_for
|
|
1444
|
+
unless method.comment.nil? or method.comment.empty?
|
|
1445
|
+
out << Markup::BlankLine.new
|
|
1446
|
+
out << method.comment.parse
|
|
1447
|
+
end
|
|
1448
|
+
out << Markup::BlankLine.new
|
|
1449
|
+
out << Markup::Paragraph.new("(This method is an alias for #{alias_for.full_name}.)")
|
|
1450
|
+
out << Markup::BlankLine.new
|
|
1451
|
+
out << alias_for.comment.parse
|
|
1452
|
+
out << Markup::BlankLine.new
|
|
1453
|
+
else
|
|
1454
|
+
out << Markup::BlankLine.new
|
|
1455
|
+
out << method.comment.parse
|
|
1456
|
+
out << Markup::BlankLine.new
|
|
1457
|
+
end
|
|
1458
|
+
end
|
|
1438
1459
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
unless method.comment.nil? or method.comment.empty?
|
|
1442
|
-
out << RDoc::Markup::BlankLine.new
|
|
1443
|
-
out << method.comment.parse
|
|
1460
|
+
def render_method_type_signature(out, lines) # :nodoc:
|
|
1461
|
+
out << Markup::Verbatim.new(*lines.map { |s| s + "\n" })
|
|
1444
1462
|
end
|
|
1445
|
-
out << RDoc::Markup::BlankLine.new
|
|
1446
|
-
out << RDoc::Markup::Paragraph.new("(This method is an alias for #{alias_for.full_name}.)")
|
|
1447
|
-
out << RDoc::Markup::BlankLine.new
|
|
1448
|
-
out << alias_for.comment.parse
|
|
1449
|
-
out << RDoc::Markup::BlankLine.new
|
|
1450
|
-
else
|
|
1451
|
-
out << RDoc::Markup::BlankLine.new
|
|
1452
|
-
out << method.comment.parse
|
|
1453
|
-
out << RDoc::Markup::BlankLine.new
|
|
1454
|
-
end
|
|
1455
|
-
end
|
|
1456
1463
|
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1464
|
+
def render_method_superclass(out, method) # :nodoc:
|
|
1465
|
+
return unless
|
|
1466
|
+
method.respond_to?(:superclass_method) and method.superclass_method
|
|
1460
1467
|
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1468
|
+
out << Markup::BlankLine.new
|
|
1469
|
+
out << Markup::Heading.new(4, "(Uses superclass method #{method.superclass_method})")
|
|
1470
|
+
out << Markup::Rule.new(1)
|
|
1471
|
+
end
|
|
1464
1472
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1473
|
+
##
|
|
1474
|
+
# Looks up and displays ri data according to the options given.
|
|
1475
|
+
|
|
1476
|
+
def run
|
|
1477
|
+
if @list_doc_dirs
|
|
1478
|
+
puts @doc_dirs
|
|
1479
|
+
elsif @list
|
|
1480
|
+
list_known_classes @names
|
|
1481
|
+
elsif @server
|
|
1482
|
+
start_server
|
|
1483
|
+
elsif @interactive or @names.empty?
|
|
1484
|
+
interactive
|
|
1485
|
+
else
|
|
1486
|
+
display_names @names
|
|
1487
|
+
end
|
|
1488
|
+
rescue NotFoundError => e
|
|
1489
|
+
abort e.message
|
|
1490
|
+
end
|
|
1469
1491
|
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
def run
|
|
1474
|
-
if @list_doc_dirs then
|
|
1475
|
-
puts @doc_dirs
|
|
1476
|
-
elsif @list then
|
|
1477
|
-
list_known_classes @names
|
|
1478
|
-
elsif @server then
|
|
1479
|
-
start_server
|
|
1480
|
-
elsif @interactive or @names.empty? then
|
|
1481
|
-
interactive
|
|
1482
|
-
else
|
|
1483
|
-
display_names @names
|
|
1484
|
-
end
|
|
1485
|
-
rescue NotFoundError => e
|
|
1486
|
-
abort e.message
|
|
1487
|
-
end
|
|
1492
|
+
##
|
|
1493
|
+
# Sets up a pager program to pass output through. Tries the RI_PAGER and
|
|
1494
|
+
# PAGER environment variables followed by pager, less then more.
|
|
1488
1495
|
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
# PAGER environment variables followed by pager, less then more.
|
|
1496
|
+
def setup_pager
|
|
1497
|
+
return if @use_stdout
|
|
1492
1498
|
|
|
1493
|
-
|
|
1494
|
-
return if @use_stdout
|
|
1499
|
+
pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more']
|
|
1495
1500
|
|
|
1496
|
-
|
|
1501
|
+
require 'shellwords'
|
|
1502
|
+
pagers.compact.uniq.each do |pager|
|
|
1503
|
+
pager = Shellwords.split(pager)
|
|
1504
|
+
next if pager.empty?
|
|
1497
1505
|
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
pager = Shellwords.split(pager)
|
|
1501
|
-
next if pager.empty?
|
|
1506
|
+
io = IO.popen(pager, 'w') rescue next
|
|
1507
|
+
next if $? and $?.pid == io.pid and $?.exited? # pager didn't work
|
|
1502
1508
|
|
|
1503
|
-
|
|
1504
|
-
next if $? and $?.pid == io.pid and $?.exited? # pager didn't work
|
|
1509
|
+
@paging = true
|
|
1505
1510
|
|
|
1506
|
-
|
|
1511
|
+
return io
|
|
1512
|
+
end
|
|
1507
1513
|
|
|
1508
|
-
|
|
1509
|
-
end
|
|
1514
|
+
@use_stdout = true
|
|
1510
1515
|
|
|
1511
|
-
|
|
1516
|
+
nil
|
|
1517
|
+
end
|
|
1512
1518
|
|
|
1513
|
-
|
|
1514
|
-
|
|
1519
|
+
##
|
|
1520
|
+
# Starts a WEBrick server for ri.
|
|
1515
1521
|
|
|
1516
|
-
|
|
1517
|
-
|
|
1522
|
+
def start_server
|
|
1523
|
+
begin
|
|
1524
|
+
require 'webrick'
|
|
1525
|
+
rescue LoadError
|
|
1526
|
+
abort "webrick is not found. You may need to `gem install webrick` to install webrick."
|
|
1527
|
+
end
|
|
1518
1528
|
|
|
1519
|
-
|
|
1520
|
-
begin
|
|
1521
|
-
require 'webrick'
|
|
1522
|
-
rescue LoadError
|
|
1523
|
-
abort "webrick is not found. You may need to `gem install webrick` to install webrick."
|
|
1524
|
-
end
|
|
1529
|
+
server = WEBrick::HTTPServer.new :Port => @server
|
|
1525
1530
|
|
|
1526
|
-
|
|
1531
|
+
extra_doc_dirs = @stores.map {|s| s.type == :extra ? s.path : nil}.compact
|
|
1527
1532
|
|
|
1528
|
-
|
|
1533
|
+
server.mount '/', RI::Servlet, nil, extra_doc_dirs
|
|
1529
1534
|
|
|
1530
|
-
|
|
1535
|
+
trap 'INT' do server.shutdown end
|
|
1536
|
+
trap 'TERM' do server.shutdown end
|
|
1531
1537
|
|
|
1532
|
-
|
|
1533
|
-
|
|
1538
|
+
server.start
|
|
1539
|
+
end
|
|
1534
1540
|
|
|
1535
|
-
|
|
1536
|
-
end
|
|
1541
|
+
RDOC_REFS_REGEXP = /\[rdoc-ref:([\w.]+)(@.*)?\]/
|
|
1537
1542
|
|
|
1538
|
-
|
|
1543
|
+
def expand_rdoc_refs_at_the_bottom(out)
|
|
1544
|
+
return unless @expand_refs
|
|
1539
1545
|
|
|
1540
|
-
|
|
1541
|
-
return unless @expand_refs
|
|
1546
|
+
extracted_rdoc_refs = []
|
|
1542
1547
|
|
|
1543
|
-
|
|
1548
|
+
out.each do |part|
|
|
1549
|
+
content = if part.respond_to?(:text)
|
|
1550
|
+
part.text
|
|
1551
|
+
else
|
|
1552
|
+
next
|
|
1553
|
+
end
|
|
1544
1554
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
else
|
|
1549
|
-
next
|
|
1550
|
-
end
|
|
1555
|
+
rdoc_refs = content.scan(RDOC_REFS_REGEXP).uniq.map do |file_name, _anchor|
|
|
1556
|
+
file_name
|
|
1557
|
+
end
|
|
1551
1558
|
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
end
|
|
1559
|
+
extracted_rdoc_refs.concat(rdoc_refs)
|
|
1560
|
+
end
|
|
1555
1561
|
|
|
1556
|
-
|
|
1557
|
-
|
|
1562
|
+
found_pages = extracted_rdoc_refs.map do |ref|
|
|
1563
|
+
begin
|
|
1564
|
+
@stores.first.load_page(ref)
|
|
1565
|
+
rescue ::RDoc::Store::MissingFileError
|
|
1566
|
+
end
|
|
1567
|
+
end.compact
|
|
1558
1568
|
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1569
|
+
found_pages.each do |page|
|
|
1570
|
+
out << Markup::Heading.new(4, "Expanded from #{page.full_name}")
|
|
1571
|
+
out << Markup::BlankLine.new
|
|
1572
|
+
out << page.comment.parse
|
|
1573
|
+
end
|
|
1563
1574
|
end
|
|
1564
|
-
end.compact
|
|
1565
|
-
|
|
1566
|
-
found_pages.each do |page|
|
|
1567
|
-
out << RDoc::Markup::Heading.new(4, "Expanded from #{page.full_name}")
|
|
1568
|
-
out << RDoc::Markup::BlankLine.new
|
|
1569
|
-
out << page.comment.parse
|
|
1570
1575
|
end
|
|
1571
1576
|
end
|
|
1572
1577
|
end
|