rdoc 3.1 → 6.3.3

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.

Files changed (247) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.rdoc +220 -0
  3. data/CVE-2013-0256.rdoc +49 -0
  4. data/ExampleMarkdown.md +37 -0
  5. data/ExampleRDoc.rdoc +208 -0
  6. data/Gemfile +12 -0
  7. data/History.rdoc +1666 -0
  8. data/LEGAL.rdoc +50 -0
  9. data/LICENSE.rdoc +57 -0
  10. data/README.rdoc +129 -0
  11. data/RI.rdoc +57 -0
  12. data/Rakefile +84 -81
  13. data/TODO.rdoc +59 -0
  14. data/bin/console +7 -0
  15. data/bin/setup +6 -0
  16. data/{bin → exe}/rdoc +11 -2
  17. data/exe/ri +12 -0
  18. data/lib/rdoc/alias.rb +1 -2
  19. data/lib/rdoc/anon_class.rb +3 -2
  20. data/lib/rdoc/any_method.rb +234 -40
  21. data/lib/rdoc/attr.rb +79 -11
  22. data/lib/rdoc/class_module.rb +443 -71
  23. data/lib/rdoc/code_object.rb +216 -20
  24. data/lib/rdoc/code_objects.rb +4 -21
  25. data/lib/rdoc/comment.rb +250 -0
  26. data/lib/rdoc/constant.rb +110 -9
  27. data/lib/rdoc/context/section.rb +232 -0
  28. data/lib/rdoc/context.rb +392 -172
  29. data/lib/rdoc/cross_reference.rb +202 -0
  30. data/lib/rdoc/encoding.rb +83 -28
  31. data/lib/rdoc/erb_partial.rb +19 -0
  32. data/lib/rdoc/erbio.rb +8 -3
  33. data/lib/rdoc/extend.rb +10 -0
  34. data/lib/rdoc/generator/darkfish.rb +507 -84
  35. data/lib/rdoc/generator/json_index.rb +300 -0
  36. data/lib/rdoc/generator/markup.rb +27 -74
  37. data/lib/rdoc/generator/pot/message_extractor.rb +68 -0
  38. data/lib/rdoc/generator/pot/po.rb +84 -0
  39. data/lib/rdoc/generator/pot/po_entry.rb +141 -0
  40. data/lib/rdoc/generator/pot.rb +98 -0
  41. data/lib/rdoc/generator/ri.rb +8 -62
  42. data/lib/rdoc/generator/template/darkfish/_footer.rhtml +5 -0
  43. data/lib/rdoc/generator/template/darkfish/_head.rhtml +22 -0
  44. data/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml +19 -0
  45. data/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +9 -0
  46. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +15 -0
  47. data/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml +9 -0
  48. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +15 -0
  49. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +15 -0
  50. data/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +12 -0
  51. data/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml +11 -0
  52. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +12 -0
  53. data/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +11 -0
  54. data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +14 -0
  55. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +11 -0
  56. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +18 -0
  57. data/lib/rdoc/generator/template/darkfish/class.rhtml +172 -0
  58. data/lib/rdoc/generator/template/darkfish/css/fonts.css +167 -0
  59. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +639 -0
  60. data/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttf +0 -0
  61. data/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttf +0 -0
  62. data/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttf +0 -0
  63. data/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttf +0 -0
  64. data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf +0 -0
  65. data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf +0 -0
  66. data/lib/rdoc/generator/template/darkfish/images/add.png +0 -0
  67. data/lib/rdoc/generator/template/darkfish/images/arrow_up.png +0 -0
  68. data/lib/rdoc/generator/template/darkfish/images/delete.png +0 -0
  69. data/lib/rdoc/generator/template/darkfish/images/tag_blue.png +0 -0
  70. data/lib/rdoc/generator/template/darkfish/images/transparent.png +0 -0
  71. data/lib/rdoc/generator/template/darkfish/index.rhtml +18 -60
  72. data/lib/rdoc/generator/template/darkfish/js/darkfish.js +51 -83
  73. data/lib/rdoc/generator/template/darkfish/js/search.js +110 -0
  74. data/lib/rdoc/generator/template/darkfish/page.rhtml +18 -0
  75. data/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml +18 -0
  76. data/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +62 -0
  77. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +58 -0
  78. data/lib/rdoc/generator/template/json_index/.document +1 -0
  79. data/lib/rdoc/generator/template/json_index/js/navigation.js +105 -0
  80. data/lib/rdoc/generator/template/json_index/js/searcher.js +229 -0
  81. data/lib/rdoc/generator.rb +24 -13
  82. data/lib/rdoc/ghost_method.rb +1 -2
  83. data/lib/rdoc/i18n/locale.rb +102 -0
  84. data/lib/rdoc/i18n/text.rb +126 -0
  85. data/lib/rdoc/i18n.rb +10 -0
  86. data/lib/rdoc/include.rb +5 -95
  87. data/lib/rdoc/known_classes.rb +5 -2
  88. data/lib/rdoc/markdown/entities.rb +2132 -0
  89. data/lib/rdoc/markdown/literals.kpeg +23 -0
  90. data/lib/rdoc/markdown/literals.rb +416 -0
  91. data/lib/rdoc/markdown.kpeg +1237 -0
  92. data/lib/rdoc/markdown.rb +16684 -0
  93. data/lib/rdoc/markup/attr_changer.rb +23 -0
  94. data/lib/rdoc/markup/attr_span.rb +36 -0
  95. data/lib/rdoc/markup/attribute_manager.rb +135 -62
  96. data/lib/rdoc/markup/attributes.rb +71 -0
  97. data/lib/rdoc/markup/blank_line.rb +1 -0
  98. data/lib/rdoc/markup/block_quote.rb +15 -0
  99. data/lib/rdoc/markup/document.rb +96 -9
  100. data/lib/rdoc/markup/formatter.rb +138 -25
  101. data/lib/rdoc/markup/hard_break.rb +32 -0
  102. data/lib/rdoc/markup/heading.rb +61 -2
  103. data/lib/rdoc/markup/include.rb +43 -0
  104. data/lib/rdoc/markup/indented_paragraph.rb +48 -0
  105. data/lib/rdoc/markup/list.rb +25 -4
  106. data/lib/rdoc/markup/list_item.rb +18 -4
  107. data/lib/rdoc/markup/paragraph.rb +15 -0
  108. data/lib/rdoc/markup/parser.rb +180 -88
  109. data/lib/rdoc/markup/pre_process.rb +183 -38
  110. data/lib/rdoc/markup/raw.rb +6 -5
  111. data/lib/rdoc/markup/regexp_handling.rb +41 -0
  112. data/lib/rdoc/markup/rule.rb +1 -0
  113. data/lib/rdoc/markup/table.rb +47 -0
  114. data/lib/rdoc/markup/to_ansi.rb +17 -7
  115. data/lib/rdoc/markup/to_bs.rb +5 -8
  116. data/lib/rdoc/markup/to_html.rb +238 -137
  117. data/lib/rdoc/markup/to_html_crossref.rb +125 -152
  118. data/lib/rdoc/markup/to_html_snippet.rb +285 -0
  119. data/lib/rdoc/markup/to_joined_paragraph.rb +47 -0
  120. data/lib/rdoc/markup/to_label.rb +75 -0
  121. data/lib/rdoc/markup/to_markdown.rb +192 -0
  122. data/lib/rdoc/markup/to_rdoc.rb +85 -15
  123. data/lib/rdoc/markup/to_table_of_contents.rb +89 -0
  124. data/lib/rdoc/markup/to_test.rb +2 -4
  125. data/lib/rdoc/markup/to_tt_only.rb +121 -0
  126. data/lib/rdoc/markup/verbatim.rb +39 -0
  127. data/lib/rdoc/markup.rb +388 -110
  128. data/lib/rdoc/meta_method.rb +1 -2
  129. data/lib/rdoc/method_attr.rb +87 -21
  130. data/lib/rdoc/mixin.rb +121 -0
  131. data/lib/rdoc/normal_class.rb +39 -10
  132. data/lib/rdoc/normal_module.rb +22 -7
  133. data/lib/rdoc/options.rb +613 -73
  134. data/lib/rdoc/parser/c.rb +621 -287
  135. data/lib/rdoc/parser/changelog.rb +335 -0
  136. data/lib/rdoc/parser/markdown.rb +24 -0
  137. data/lib/rdoc/parser/rd.rb +23 -0
  138. data/lib/rdoc/parser/ripper_state_lex.rb +590 -0
  139. data/lib/rdoc/parser/ruby.rb +1368 -762
  140. data/lib/rdoc/parser/ruby_tools.rb +42 -35
  141. data/lib/rdoc/parser/simple.rb +23 -11
  142. data/lib/rdoc/parser/text.rb +12 -0
  143. data/lib/rdoc/parser.rb +162 -89
  144. data/lib/rdoc/rd/block_parser.rb +1056 -0
  145. data/lib/rdoc/rd/block_parser.ry +639 -0
  146. data/lib/rdoc/rd/inline.rb +72 -0
  147. data/lib/rdoc/rd/inline_parser.rb +1208 -0
  148. data/lib/rdoc/rd/inline_parser.ry +593 -0
  149. data/lib/rdoc/rd.rb +100 -0
  150. data/lib/rdoc/rdoc.rb +208 -115
  151. data/lib/rdoc/require.rb +1 -2
  152. data/lib/rdoc/ri/driver.rb +734 -239
  153. data/lib/rdoc/ri/formatter.rb +1 -0
  154. data/lib/rdoc/ri/paths.rb +91 -48
  155. data/lib/rdoc/ri/store.rb +3 -261
  156. data/lib/rdoc/ri/task.rb +71 -0
  157. data/lib/rdoc/ri.rb +5 -2
  158. data/lib/rdoc/rubygems_hook.rb +246 -0
  159. data/lib/rdoc/servlet.rb +451 -0
  160. data/lib/rdoc/single_class.rb +14 -2
  161. data/lib/rdoc/stats/normal.rb +19 -12
  162. data/lib/rdoc/stats/quiet.rb +1 -0
  163. data/lib/rdoc/stats/verbose.rb +1 -0
  164. data/lib/rdoc/stats.rb +262 -104
  165. data/lib/rdoc/store.rb +979 -0
  166. data/lib/rdoc/task.rb +84 -44
  167. data/lib/rdoc/text.rb +117 -72
  168. data/lib/rdoc/token_stream.rb +73 -4
  169. data/lib/rdoc/tom_doc.rb +263 -0
  170. data/lib/rdoc/top_level.rb +111 -261
  171. data/lib/rdoc/version.rb +8 -0
  172. data/lib/rdoc.rb +127 -64
  173. data/man/ri.1 +247 -0
  174. data/rdoc.gemspec +249 -0
  175. metadata +171 -291
  176. data/.autotest +0 -16
  177. data/.document +0 -5
  178. data/History.txt +0 -594
  179. data/LICENSE.txt +0 -57
  180. data/Manifest.txt +0 -158
  181. data/README.txt +0 -45
  182. data/RI.txt +0 -58
  183. data/bin/ri +0 -5
  184. data/lib/rdoc/gauntlet.rb +0 -52
  185. data/lib/rdoc/generator/template/darkfish/classpage.rhtml +0 -296
  186. data/lib/rdoc/generator/template/darkfish/filepage.rhtml +0 -124
  187. data/lib/rdoc/generator/template/darkfish/js/jquery.js +0 -32
  188. data/lib/rdoc/generator/template/darkfish/js/quicksearch.js +0 -114
  189. data/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js +0 -10
  190. data/lib/rdoc/generator/template/darkfish/rdoc.css +0 -706
  191. data/lib/rdoc/markup/formatter_test_case.rb +0 -689
  192. data/lib/rdoc/markup/inline.rb +0 -137
  193. data/lib/rdoc/markup/text_formatter_test_case.rb +0 -116
  194. data/lib/rdoc/ruby_lex.rb +0 -1291
  195. data/lib/rdoc/ruby_token.rb +0 -416
  196. data/test/README +0 -1
  197. data/test/binary.dat +0 -0
  198. data/test/hidden.zip.txt +0 -1
  199. data/test/test.ja.rdoc +0 -10
  200. data/test/test.ja.txt +0 -8
  201. data/test/test.txt +0 -1
  202. data/test/test_attribute_manager.rb +0 -120
  203. data/test/test_rdoc_alias.rb +0 -13
  204. data/test/test_rdoc_any_method.rb +0 -126
  205. data/test/test_rdoc_attr.rb +0 -61
  206. data/test/test_rdoc_class_module.rb +0 -233
  207. data/test/test_rdoc_code_object.rb +0 -165
  208. data/test/test_rdoc_constant.rb +0 -15
  209. data/test/test_rdoc_context.rb +0 -370
  210. data/test/test_rdoc_encoding.rb +0 -166
  211. data/test/test_rdoc_generator_darkfish.rb +0 -119
  212. data/test/test_rdoc_generator_ri.rb +0 -76
  213. data/test/test_rdoc_include.rb +0 -96
  214. data/test/test_rdoc_markup.rb +0 -37
  215. data/test/test_rdoc_markup_attribute_manager.rb +0 -240
  216. data/test/test_rdoc_markup_document.rb +0 -51
  217. data/test/test_rdoc_markup_paragraph.rb +0 -9
  218. data/test/test_rdoc_markup_parser.rb +0 -1395
  219. data/test/test_rdoc_markup_pre_process.rb +0 -185
  220. data/test/test_rdoc_markup_raw.rb +0 -27
  221. data/test/test_rdoc_markup_to_ansi.rb +0 -328
  222. data/test/test_rdoc_markup_to_bs.rb +0 -341
  223. data/test/test_rdoc_markup_to_html.rb +0 -335
  224. data/test/test_rdoc_markup_to_html_crossref.rb +0 -169
  225. data/test/test_rdoc_markup_to_rdoc.rb +0 -327
  226. data/test/test_rdoc_method_attr.rb +0 -122
  227. data/test/test_rdoc_normal_class.rb +0 -17
  228. data/test/test_rdoc_normal_module.rb +0 -31
  229. data/test/test_rdoc_options.rb +0 -342
  230. data/test/test_rdoc_parser.rb +0 -83
  231. data/test/test_rdoc_parser_c.rb +0 -912
  232. data/test/test_rdoc_parser_ruby.rb +0 -1754
  233. data/test/test_rdoc_parser_simple.rb +0 -99
  234. data/test/test_rdoc_rdoc.rb +0 -164
  235. data/test/test_rdoc_require.rb +0 -25
  236. data/test/test_rdoc_ri_driver.rb +0 -846
  237. data/test/test_rdoc_ri_paths.rb +0 -43
  238. data/test/test_rdoc_ri_store.rb +0 -352
  239. data/test/test_rdoc_ruby_lex.rb +0 -23
  240. data/test/test_rdoc_stats.rb +0 -38
  241. data/test/test_rdoc_task.rb +0 -92
  242. data/test/test_rdoc_text.rb +0 -251
  243. data/test/test_rdoc_top_level.rb +0 -120
  244. data/test/xref_data.rb +0 -62
  245. data/test/xref_test_case.rb +0 -61
  246. data.tar.gz.sig +0 -3
  247. metadata.gz.sig +0 -0
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'abbrev'
2
3
  require 'optparse'
3
4
 
@@ -11,16 +12,12 @@ begin
11
12
  rescue LoadError
12
13
  end
13
14
 
14
- require 'rdoc/ri'
15
- require 'rdoc/ri/paths'
16
- require 'rdoc/markup'
17
- require 'rdoc/markup/formatter'
18
- require 'rdoc/text'
15
+ require 'rdoc'
19
16
 
20
17
  ##
21
18
  # For RubyGems backwards compatibility
22
19
 
23
- require 'rdoc/ri/formatter'
20
+ require_relative 'formatter'
24
21
 
25
22
  ##
26
23
  # The RI driver implements the command-line ri tool.
@@ -50,16 +47,32 @@ class RDoc::RI::Driver
50
47
 
51
48
  class NotFoundError < Error
52
49
 
50
+ def initialize(klass, suggestions = nil) # :nodoc:
51
+ @klass = klass
52
+ @suggestions = suggestions
53
+ end
54
+
53
55
  ##
54
56
  # Name that wasn't found
55
57
 
56
- alias name message
58
+ def name
59
+ @klass
60
+ end
57
61
 
58
62
  def message # :nodoc:
59
- "Nothing known about #{super}"
63
+ str = "Nothing known about #{@klass}"
64
+ if @suggestions and !@suggestions.empty?
65
+ str += "\nDid you mean? #{@suggestions.join("\n ")}"
66
+ end
67
+ str
60
68
  end
61
69
  end
62
70
 
71
+ ##
72
+ # Show all method documentation following a class or module
73
+
74
+ attr_accessor :show_all
75
+
63
76
  ##
64
77
  # An RDoc::RI::Store for each entry in the RI path
65
78
 
@@ -75,17 +88,17 @@ class RDoc::RI::Driver
75
88
 
76
89
  def self.default_options
77
90
  options = {}
78
- options[:use_stdout] = !$stdout.tty?
79
- options[:width] = 72
80
91
  options[:interactive] = false
81
- options[:use_cache] = true
82
- options[:profile] = false
92
+ options[:profile] = false
93
+ options[:show_all] = false
94
+ options[:use_stdout] = !$stdout.tty?
95
+ options[:width] = 72
83
96
 
84
97
  # By default all standard paths are used.
85
- options[:use_system] = true
86
- options[:use_site] = true
87
- options[:use_home] = true
88
- options[:use_gems] = true
98
+ options[:use_system] = true
99
+ options[:use_site] = true
100
+ options[:use_home] = true
101
+ options[:use_gems] = true
89
102
  options[:extra_doc_dirs] = []
90
103
 
91
104
  return options
@@ -97,7 +110,7 @@ class RDoc::RI::Driver
97
110
  def self.dump data_path
98
111
  require 'pp'
99
112
 
100
- open data_path, 'rb' do |io|
113
+ File.open data_path, 'rb' do |io|
101
114
  pp Marshal.load(io.read)
102
115
  end
103
116
  end
@@ -119,39 +132,52 @@ class RDoc::RI::Driver
119
132
  opt.summary_indent = ' ' * 4
120
133
 
121
134
  opt.banner = <<-EOT
122
- Usage: #{opt.program_name} [options] [names...]
135
+ Usage: #{opt.program_name} [options] [name ...]
123
136
 
124
137
  Where name can be:
125
138
 
126
- Class | Class::method | Class#method | Class.method | method
139
+ Class | Module | Module::Class
127
140
 
128
- All class names may be abbreviated to their minimum unambiguous form. If a name
129
- is ambiguous, all valid options will be listed.
141
+ Class::method | Class#method | Class.method | method
142
+
143
+ gem_name: | gem_name:README | gem_name:History
144
+
145
+ All class names may be abbreviated to their minimum unambiguous form.
146
+ If a name is ambiguous, all valid options will be listed.
130
147
 
131
148
  A '.' matches either class or instance methods, while #method
132
149
  matches only instance and ::method matches only class methods.
133
150
 
151
+ README and other files may be displayed by prefixing them with the gem name
152
+ they're contained in. If the gem name is followed by a ':' all files in the
153
+ gem will be shown. The file name extension may be omitted where it is
154
+ unambiguous.
155
+
134
156
  For example:
135
157
 
136
158
  #{opt.program_name} Fil
137
159
  #{opt.program_name} File
138
160
  #{opt.program_name} File.new
139
161
  #{opt.program_name} zip
162
+ #{opt.program_name} rdoc:README
140
163
 
141
- Note that shell quoting or escaping may be required for method names containing
142
- punctuation:
164
+ Note that shell quoting or escaping may be required for method names
165
+ containing punctuation:
143
166
 
144
167
  #{opt.program_name} 'Array.[]'
145
168
  #{opt.program_name} compact\\!
146
169
 
147
- To see the default directories ri will search, run:
170
+ To see the default directories #{opt.program_name} will search, run:
148
171
 
149
172
  #{opt.program_name} --list-doc-dirs
150
173
 
151
- Specifying the --system, --site, --home, --gems or --doc-dir options will
152
- limit ri to searching only the specified directories.
174
+ Specifying the --system, --site, --home, --gems, or --doc-dir options
175
+ will limit ri to searching only the specified directories.
153
176
 
154
- Options may also be set in the 'RI' environment variable.
177
+ ri options may be set in the RI environment variable.
178
+
179
+ The ri pager can be set with the RI_PAGER environment variable
180
+ or the PAGER environment variable.
155
181
  EOT
156
182
 
157
183
  opt.separator nil
@@ -159,57 +185,97 @@ Options may also be set in the 'RI' environment variable.
159
185
 
160
186
  opt.separator nil
161
187
 
162
- formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort
163
- formatters = formatters.sort.map do |formatter|
164
- formatter.to_s.sub('To', '').downcase
188
+ opt.on("--[no-]interactive", "-i",
189
+ "In interactive mode you can repeatedly",
190
+ "look up methods with autocomplete.") do |interactive|
191
+ options[:interactive] = interactive
165
192
  end
166
193
 
167
- opt.on("--format=NAME", "-f",
168
- "Uses the selected formatter. The default",
169
- "formatter is bs for paged output and ansi",
170
- "otherwise. Valid formatters are:",
171
- formatters.join(' '), formatters) do |value|
172
- options[:formatter] = RDoc::Markup.const_get "To#{value.capitalize}"
194
+ opt.separator nil
195
+
196
+ opt.on("--[no-]all", "-a",
197
+ "Show all documentation for a class or",
198
+ "module.") do |show_all|
199
+ options[:show_all] = show_all
200
+ end
201
+
202
+ opt.separator nil
203
+
204
+ opt.on("--[no-]list", "-l",
205
+ "List classes ri knows about.") do |list|
206
+ options[:list] = list
207
+ end
208
+
209
+ opt.separator nil
210
+
211
+ opt.on("--[no-]pager",
212
+ "Send output to a pager,",
213
+ "rather than directly to stdout.") do |use_pager|
214
+ options[:use_stdout] = !use_pager
173
215
  end
174
216
 
175
217
  opt.separator nil
176
218
 
177
- opt.on("--no-pager", "-T",
178
- "Send output directly to stdout,",
179
- "rather than to a pager.") do
219
+ opt.on("-T",
220
+ "Synonym for --no-pager.") do
180
221
  options[:use_stdout] = true
181
222
  end
182
223
 
183
224
  opt.separator nil
184
225
 
185
226
  opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
186
- "Set the width of the output.") do |value|
187
- options[:width] = value
227
+ "Set the width of the output.") do |width|
228
+ options[:width] = width
188
229
  end
189
230
 
190
231
  opt.separator nil
191
232
 
192
- opt.on("--interactive", "-i",
193
- "In interactive mode you can repeatedly",
194
- "look up methods with autocomplete.") do
195
- options[:interactive] = true
233
+ opt.on("--server[=PORT]", Integer,
234
+ "Run RDoc server on the given port.",
235
+ "The default port is 8214.") do |port|
236
+ options[:server] = port || 8214
196
237
  end
197
238
 
198
239
  opt.separator nil
199
240
 
200
- opt.on("--[no-]profile",
201
- "Run with the ruby profiler") do |value|
202
- options[:profile] = value
241
+ formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort
242
+ formatters = formatters.sort.map do |formatter|
243
+ formatter.to_s.sub('To', '').downcase
244
+ end
245
+ formatters -= %w[html label test] # remove useless output formats
246
+
247
+ opt.on("--format=NAME", "-f",
248
+ "Use the selected formatter. The default",
249
+ "formatter is bs for paged output and ansi",
250
+ "otherwise. Valid formatters are:",
251
+ "#{formatters.join(', ')}.", formatters) do |value|
252
+ options[:formatter] = RDoc::Markup.const_get "To#{value.capitalize}"
253
+ end
254
+
255
+ opt.separator nil
256
+
257
+ opt.on("--help", "-h",
258
+ "Show help and exit.") do
259
+ puts opts
260
+ exit
261
+ end
262
+
263
+ opt.separator nil
264
+
265
+ opt.on("--version", "-v",
266
+ "Output version information and exit.") do
267
+ puts "#{opts.program_name} #{opts.version}"
268
+ exit
203
269
  end
204
270
 
205
271
  opt.separator nil
206
272
  opt.separator "Data source options:"
207
273
  opt.separator nil
208
274
 
209
- opt.on("--list-doc-dirs",
275
+ opt.on("--[no-]list-doc-dirs",
210
276
  "List the directories from which ri will",
211
- "source documentation on stdout and exit.") do
212
- options[:list_doc_dirs] = true
277
+ "source documentation on stdout and exit.") do |list_doc_dirs|
278
+ options[:list_doc_dirs] = list_doc_dirs
213
279
  end
214
280
 
215
281
  opt.separator nil
@@ -233,7 +299,7 @@ Options may also be set in the 'RI' environment variable.
233
299
  "Do not include documentation from",
234
300
  "the Ruby standard library, site_lib,",
235
301
  "installed gems, or ~/.rdoc.",
236
- "Use with --doc-dir") do
302
+ "Use with --doc-dir.") do
237
303
  options[:use_system] = false
238
304
  options[:use_site] = false
239
305
  options[:use_gems] = false
@@ -243,8 +309,8 @@ Options may also be set in the 'RI' environment variable.
243
309
  opt.separator nil
244
310
 
245
311
  opt.on("--[no-]system",
246
- "Include documentation from Ruby's standard",
247
- "library. Defaults to true.") do |value|
312
+ "Include documentation from Ruby's",
313
+ "standard library. Defaults to true.") do |value|
248
314
  options[:use_system] = value
249
315
  end
250
316
 
@@ -277,13 +343,20 @@ Options may also be set in the 'RI' environment variable.
277
343
  opt.separator "Debug options:"
278
344
  opt.separator nil
279
345
 
346
+ opt.on("--[no-]profile",
347
+ "Run with the ruby profiler.") do |value|
348
+ options[:profile] = value
349
+ end
350
+
351
+ opt.separator nil
352
+
280
353
  opt.on("--dump=CACHE", File,
281
- "Dumps data from an ri cache or data file") do |value|
354
+ "Dump data from an ri cache or data file.") do |value|
282
355
  options[:dump_path] = value
283
356
  end
284
357
  end
285
358
 
286
- argv = ENV['RI'].to_s.split.concat argv
359
+ argv = ENV['RI'].to_s.split(' ').concat argv
287
360
 
288
361
  opts.parse! argv
289
362
 
@@ -331,13 +404,14 @@ Options may also be set in the 'RI' environment variable.
331
404
  require 'profile' if options[:profile]
332
405
 
333
406
  @names = options[:names]
407
+ @list = options[:list]
334
408
 
335
409
  @doc_dirs = []
336
410
  @stores = []
337
411
 
338
412
  RDoc::RI::Paths.each(options[:use_system], options[:use_site],
339
- options[:use_home], options[:use_gems],
340
- *options[:extra_doc_dirs]) do |path, type|
413
+ options[:use_home], options[:use_gems],
414
+ *options[:extra_doc_dirs]) do |path, type|
341
415
  @doc_dirs << path
342
416
 
343
417
  store = RDoc::RI::Store.new path, type
@@ -348,7 +422,13 @@ Options may also be set in the 'RI' environment variable.
348
422
  @list_doc_dirs = options[:list_doc_dirs]
349
423
 
350
424
  @interactive = options[:interactive]
425
+ @server = options[:server]
351
426
  @use_stdout = options[:use_stdout]
427
+ @show_all = options[:show_all]
428
+ @width = options[:width]
429
+
430
+ # pager process for jruby
431
+ @jruby_pager_process = nil
352
432
  end
353
433
 
354
434
  ##
@@ -379,6 +459,8 @@ Options may also be set in the 'RI' environment variable.
379
459
  klass.superclass unless klass.module?
380
460
  end.compact.shift || 'Object'
381
461
 
462
+ superclass = superclass.full_name unless String === superclass
463
+
382
464
  "#{name} < #{superclass}"
383
465
  end
384
466
 
@@ -394,47 +476,99 @@ Options may also be set in the 'RI' environment variable.
394
476
  end
395
477
 
396
478
  ##
397
- # Adds +includes+ to +out+
479
+ # Adds +extends+ to +out+
398
480
 
399
- def add_includes out, includes
400
- return if includes.empty?
481
+ def add_extends out, extends
482
+ add_extension_modules out, 'Extended by', extends
483
+ end
484
+
485
+ ##
486
+ # Adds a list of +extensions+ to this module of the given +type+ to +out+.
487
+ # add_includes and add_extends call this, so you should use those directly.
488
+
489
+ def add_extension_modules out, type, extensions
490
+ return if extensions.empty?
401
491
 
402
492
  out << RDoc::Markup::Rule.new(1)
403
- out << RDoc::Markup::Heading.new(1, "Includes:")
493
+ out << RDoc::Markup::Heading.new(1, "#{type}:")
404
494
 
405
- includes.each do |modules, store|
495
+ extensions.each do |modules, store|
406
496
  if modules.length == 1 then
407
- include = modules.first
408
- name = include.name
409
- path = store.friendly_path
410
- out << RDoc::Markup::Paragraph.new("#{name} (from #{path})")
411
-
412
- if include.comment then
413
- out << RDoc::Markup::BlankLine.new
414
- out << include.comment
415
- end
497
+ add_extension_modules_single out, store, modules.first
416
498
  else
417
- out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
499
+ add_extension_modules_multiple out, store, modules
500
+ end
501
+ end
502
+ end
418
503
 
419
- wout, with = modules.partition { |incl| incl.comment.empty? }
504
+ ##
505
+ # Renders multiple included +modules+ from +store+ to +out+.
420
506
 
421
- out << RDoc::Markup::BlankLine.new unless with.empty?
507
+ def add_extension_modules_multiple out, store, modules # :nodoc:
508
+ out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
422
509
 
423
- with.each do |incl|
424
- out << RDoc::Markup::Paragraph.new(incl.name)
425
- out << RDoc::Markup::BlankLine.new
426
- out << incl.comment
427
- end
510
+ wout, with = modules.partition { |incl| incl.comment.empty? }
428
511
 
429
- unless wout.empty? then
430
- verb = RDoc::Markup::Verbatim.new
512
+ out << RDoc::Markup::BlankLine.new unless with.empty?
431
513
 
432
- wout.each do |incl|
433
- verb.push incl.name, "\n"
434
- end
514
+ with.each do |incl|
515
+ out << RDoc::Markup::Paragraph.new(incl.name)
516
+ out << RDoc::Markup::BlankLine.new
517
+ out << incl.comment
518
+ end
435
519
 
436
- out << verb
437
- end
520
+ unless wout.empty? then
521
+ verb = RDoc::Markup::Verbatim.new
522
+
523
+ wout.each do |incl|
524
+ verb.push incl.name, "\n"
525
+ end
526
+
527
+ out << verb
528
+ end
529
+ end
530
+
531
+ ##
532
+ # Adds a single extension module +include+ from +store+ to +out+
533
+
534
+ def add_extension_modules_single out, store, include # :nodoc:
535
+ name = include.name
536
+ path = store.friendly_path
537
+ out << RDoc::Markup::Paragraph.new("#{name} (from #{path})")
538
+
539
+ if include.comment then
540
+ out << RDoc::Markup::BlankLine.new
541
+ out << include.comment
542
+ end
543
+ end
544
+
545
+ ##
546
+ # Adds +includes+ to +out+
547
+
548
+ def add_includes out, includes
549
+ add_extension_modules out, 'Includes', includes
550
+ end
551
+
552
+ ##
553
+ # Looks up the method +name+ and adds it to +out+
554
+
555
+ def add_method out, name
556
+ filtered = lookup_method name
557
+
558
+ method_out = method_document name, filtered
559
+
560
+ out.concat method_out.parts
561
+ end
562
+
563
+ ##
564
+ # Adds documentation for all methods in +klass+ to +out+
565
+
566
+ def add_method_documentation out, klass
567
+ klass.method_list.each do |method|
568
+ begin
569
+ add_method out, method.full_name
570
+ rescue NotFoundError
571
+ next
438
572
  end
439
573
  end
440
574
  end
@@ -443,14 +577,18 @@ Options may also be set in the 'RI' environment variable.
443
577
  # Adds a list of +methods+ to +out+ with a heading of +name+
444
578
 
445
579
  def add_method_list out, methods, name
446
- return unless methods
580
+ return if methods.empty?
447
581
 
448
582
  out << RDoc::Markup::Heading.new(1, "#{name}:")
449
583
  out << RDoc::Markup::BlankLine.new
450
584
 
451
- out.push(*methods.map do |method|
452
- RDoc::Markup::Verbatim.new method
453
- end)
585
+ if @use_stdout and !@interactive then
586
+ out.concat methods.map { |method|
587
+ RDoc::Markup::Verbatim.new method
588
+ }
589
+ else
590
+ out << RDoc::Markup::IndentedParagraph.new(2, methods.join(', '))
591
+ end
454
592
 
455
593
  out << RDoc::Markup::BlankLine.new
456
594
  end
@@ -479,8 +617,8 @@ Options may also be set in the 'RI' environment variable.
479
617
 
480
618
  klasses = klasses - seen
481
619
 
482
- ancestors.push(*klasses)
483
- unexamined.push(*klasses)
620
+ ancestors.concat klasses
621
+ unexamined.concat klasses
484
622
  end
485
623
 
486
624
  ancestors.reverse
@@ -492,6 +630,72 @@ Options may also be set in the 'RI' environment variable.
492
630
  def class_cache # :nodoc:
493
631
  end
494
632
 
633
+ ##
634
+ # Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+
635
+
636
+ def class_document name, found, klasses, includes, extends
637
+ also_in = []
638
+
639
+ out = RDoc::Markup::Document.new
640
+
641
+ add_class out, name, klasses
642
+
643
+ add_includes out, includes
644
+ add_extends out, extends
645
+
646
+ found.each do |store, klass|
647
+ render_class out, store, klass, also_in
648
+ end
649
+
650
+ add_also_in out, also_in
651
+
652
+ out
653
+ end
654
+
655
+ ##
656
+ # Adds the class +comment+ to +out+.
657
+
658
+ def class_document_comment out, comment # :nodoc:
659
+ unless comment.empty? then
660
+ out << RDoc::Markup::Rule.new(1)
661
+
662
+ if comment.merged? then
663
+ parts = comment.parts
664
+ parts = parts.zip [RDoc::Markup::BlankLine.new] * parts.length
665
+ parts.flatten!
666
+ parts.pop
667
+
668
+ out.concat parts
669
+ else
670
+ out << comment
671
+ end
672
+ end
673
+ end
674
+
675
+ ##
676
+ # Adds the constants from +klass+ to the Document +out+.
677
+
678
+ def class_document_constants out, klass # :nodoc:
679
+ return if klass.constants.empty?
680
+
681
+ out << RDoc::Markup::Heading.new(1, "Constants:")
682
+ out << RDoc::Markup::BlankLine.new
683
+ list = RDoc::Markup::List.new :NOTE
684
+
685
+ constants = klass.constants.sort_by { |constant| constant.name }
686
+
687
+ list.items.concat constants.map { |constant|
688
+ parts = constant.comment.parts if constant.comment
689
+ parts << RDoc::Markup::Paragraph.new('[not documented]') if
690
+ parts.empty?
691
+
692
+ RDoc::Markup::ListItem.new(constant.name, *parts)
693
+ }
694
+
695
+ out << list
696
+ out << RDoc::Markup::BlankLine.new
697
+ end
698
+
495
699
  ##
496
700
  # Hash mapping a known class or module to the stores it can be loaded from
497
701
 
@@ -511,26 +715,66 @@ Options may also be set in the 'RI' environment variable.
511
715
  @classes
512
716
  end
513
717
 
718
+ ##
719
+ # Returns the stores wherein +name+ is found along with the classes,
720
+ # extends and includes that match it
721
+
722
+ def classes_and_includes_and_extends_for name
723
+ klasses = []
724
+ extends = []
725
+ includes = []
726
+
727
+ found = @stores.map do |store|
728
+ begin
729
+ klass = store.load_class name
730
+ klasses << klass
731
+ extends << [klass.extends, store] if klass.extends
732
+ includes << [klass.includes, store] if klass.includes
733
+ [store, klass]
734
+ rescue RDoc::Store::MissingFileError
735
+ end
736
+ end.compact
737
+
738
+ extends.reject! do |modules,| modules.empty? end
739
+ includes.reject! do |modules,| modules.empty? end
740
+
741
+ [found, klasses, includes, extends]
742
+ end
743
+
514
744
  ##
515
745
  # Completes +name+ based on the caches. For Readline
516
746
 
517
747
  def complete name
518
- klasses = classes.keys
519
748
  completions = []
520
749
 
521
750
  klass, selector, method = parse_name name
522
751
 
752
+ complete_klass name, klass, selector, method, completions
753
+ complete_method name, klass, selector, completions
754
+
755
+ completions.sort.uniq
756
+ end
757
+
758
+ def complete_klass name, klass, selector, method, completions # :nodoc:
759
+ klasses = classes.keys
760
+
523
761
  # may need to include Foo when given Foo::
524
762
  klass_name = method ? name : klass
525
763
 
526
764
  if name !~ /#|\./ then
527
- completions.push(*klasses.grep(/^#{klass_name}/))
765
+ completions.replace klasses.grep(/^#{Regexp.escape klass_name}[^:]*$/)
766
+ completions.concat klasses.grep(/^#{Regexp.escape name}[^:]*$/) if
767
+ name =~ /::$/
768
+
769
+ completions << klass if classes.key? klass # to complete a method name
528
770
  elsif selector then
529
771
  completions << klass if classes.key? klass
530
772
  elsif classes.key? klass_name then
531
773
  completions << klass_name
532
774
  end
775
+ end
533
776
 
777
+ def complete_method name, klass, selector, completions # :nodoc:
534
778
  if completions.include? klass and name =~ /#|\.|::/ then
535
779
  methods = list_methods_matching name
536
780
 
@@ -543,10 +787,8 @@ Options may also be set in the 'RI' environment variable.
543
787
  completions << "#{klass}#{selector}"
544
788
  end
545
789
 
546
- completions.push(*methods)
790
+ completions.concat methods
547
791
  end
548
-
549
- completions.sort
550
792
  end
551
793
 
552
794
  ##
@@ -554,7 +796,9 @@ Options may also be set in the 'RI' environment variable.
554
796
 
555
797
  def display document
556
798
  page do |io|
557
- text = document.accept formatter(io)
799
+ f = formatter(io)
800
+ f.width = @width if @width and f.respond_to?(:width)
801
+ text = document.accept f
558
802
 
559
803
  io.write text
560
804
  end
@@ -566,79 +810,12 @@ Options may also be set in the 'RI' environment variable.
566
810
  def display_class name
567
811
  return if name =~ /#|\./
568
812
 
569
- klasses = []
570
- includes = []
571
-
572
- found = @stores.map do |store|
573
- begin
574
- klass = store.load_class name
575
- klasses << klass
576
- includes << [klass.includes, store] if klass.includes
577
- [store, klass]
578
- rescue Errno::ENOENT
579
- end
580
- end.compact
813
+ found, klasses, includes, extends =
814
+ classes_and_includes_and_extends_for name
581
815
 
582
816
  return if found.empty?
583
817
 
584
- also_in = []
585
-
586
- includes.reject! do |modules,| modules.empty? end
587
-
588
- out = RDoc::Markup::Document.new
589
-
590
- add_class out, name, klasses
591
-
592
- add_includes out, includes
593
-
594
- found.each do |store, klass|
595
- comment = klass.comment
596
- class_methods = store.class_methods[klass.full_name]
597
- instance_methods = store.instance_methods[klass.full_name]
598
- attributes = store.attributes[klass.full_name]
599
-
600
- if comment.empty? and !(instance_methods or class_methods) then
601
- also_in << store
602
- next
603
- end
604
-
605
- add_from out, store
606
-
607
- unless comment.empty? then
608
- out << RDoc::Markup::Rule.new(1)
609
- out << comment
610
- end
611
-
612
- if class_methods or instance_methods or not klass.constants.empty? then
613
- out << RDoc::Markup::Rule.new(1)
614
- end
615
-
616
- unless klass.constants.empty? then
617
- out << RDoc::Markup::Heading.new(1, "Constants:")
618
- out << RDoc::Markup::BlankLine.new
619
- list = RDoc::Markup::List.new :NOTE
620
-
621
- constants = klass.constants.sort_by { |constant| constant.name }
622
-
623
- list.push(*constants.map do |constant|
624
- parts = constant.comment.parts if constant.comment
625
- parts << RDoc::Markup::Paragraph.new('[not documented]') if
626
- parts.empty?
627
-
628
- RDoc::Markup::ListItem.new(constant.name, *parts)
629
- end)
630
-
631
- out << list
632
- end
633
-
634
- add_method_list out, class_methods, 'Class methods'
635
- add_method_list out, instance_methods, 'Instance methods'
636
- add_method_list out, attributes, 'Attributes'
637
-
638
- out << RDoc::Markup::BlankLine.new
639
- end
640
-
641
- add_also_in out, also_in
818
+ out = class_document name, found, klasses, includes, extends
642
819
 
643
820
  display out
644
821
  end
@@ -647,36 +824,9 @@ Options may also be set in the 'RI' environment variable.
647
824
  # Outputs formatted RI data for method +name+
648
825
 
649
826
  def display_method name
650
- found = load_methods_matching name
651
-
652
- raise NotFoundError, name if found.empty?
653
-
654
827
  out = RDoc::Markup::Document.new
655
828
 
656
- out << RDoc::Markup::Heading.new(1, name)
657
- out << RDoc::Markup::BlankLine.new
658
-
659
- found.each do |store, methods|
660
- methods.each do |method|
661
- out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
662
-
663
- unless name =~ /^#{Regexp.escape method.parent_name}/ then
664
- out << RDoc::Markup::Heading.new(3, "Implementation from #{method.parent_name}")
665
- end
666
- out << RDoc::Markup::Rule.new(1)
667
-
668
- if method.arglists then
669
- arglists = method.arglists.chomp.split "\n"
670
- arglists = arglists.map { |line| line + "\n" }
671
- out << RDoc::Markup::Verbatim.new(*arglists)
672
- out << RDoc::Markup::Rule.new(1)
673
- end
674
-
675
- out << RDoc::Markup::BlankLine.new
676
- out << method.comment
677
- out << RDoc::Markup::BlankLine.new
678
- end
679
- end
829
+ add_method out, name
680
830
 
681
831
  display out
682
832
  end
@@ -688,6 +838,11 @@ Options may also be set in the 'RI' environment variable.
688
838
  # be guessed, raises an error if +name+ couldn't be guessed.
689
839
 
690
840
  def display_name name
841
+ if name =~ /\w:(\w|$)/ then
842
+ display_page name
843
+ return true
844
+ end
845
+
691
846
  return true if display_class name
692
847
 
693
848
  display_method name if name =~ /::|#|\./
@@ -695,14 +850,14 @@ Options may also be set in the 'RI' environment variable.
695
850
  true
696
851
  rescue NotFoundError
697
852
  matches = list_methods_matching name if name =~ /::|#|\./
698
- matches = classes.keys.grep(/^#{name}/) if matches.empty?
853
+ matches = classes.keys.grep(/^#{Regexp.escape name}/) if matches.empty?
699
854
 
700
855
  raise if matches.empty?
701
856
 
702
857
  page do |io|
703
858
  io.puts "#{name} not found, maybe you meant:"
704
859
  io.puts
705
- io.puts matches.join("\n")
860
+ io.puts matches.sort.join("\n")
706
861
  end
707
862
 
708
863
  false
@@ -718,29 +873,99 @@ Options may also be set in the 'RI' environment variable.
718
873
  display_name name
719
874
  end
720
875
  end
876
+
721
877
  ##
722
- # Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da"
723
- # will be expanded to Zlib::DataError.
878
+ # Outputs formatted RI data for page +name+.
724
879
 
725
- def expand_class klass
726
- klass.split('::').inject '' do |expanded, klass_part|
727
- expanded << '::' unless expanded.empty?
728
- short = expanded << klass_part
880
+ def display_page name
881
+ store_name, page_name = name.split ':', 2
882
+
883
+ store = @stores.find { |s| s.source == store_name }
884
+
885
+ return display_page_list store if page_name.empty?
729
886
 
730
- subset = classes.keys.select do |klass_name|
731
- klass_name =~ /^#{expanded}[^:]*$/
887
+ pages = store.cache[:pages]
888
+
889
+ unless pages.include? page_name then
890
+ found_names = pages.select do |n|
891
+ n =~ /#{Regexp.escape page_name}\.[^.]+$/
892
+ end
893
+
894
+ if found_names.length.zero? then
895
+ return display_page_list store, pages
896
+ elsif found_names.length > 1 then
897
+ return display_page_list store, found_names, page_name
732
898
  end
733
899
 
734
- abbrevs = Abbrev.abbrev subset
900
+ page_name = found_names.first
901
+ end
902
+
903
+ page = store.load_page page_name
904
+
905
+ display page.comment
906
+ end
907
+
908
+ ##
909
+ # Outputs a formatted RI page list for the pages in +store+.
910
+
911
+ def display_page_list store, pages = store.cache[:pages], search = nil
912
+ out = RDoc::Markup::Document.new
913
+
914
+ title = if search then
915
+ "#{search} pages"
916
+ else
917
+ 'Pages'
918
+ end
735
919
 
736
- expanded = abbrevs[short]
920
+ out << RDoc::Markup::Heading.new(1, "#{title} in #{store.friendly_path}")
921
+ out << RDoc::Markup::BlankLine.new
737
922
 
738
- raise NotFoundError, short unless expanded
923
+ list = RDoc::Markup::List.new(:BULLET)
739
924
 
740
- expanded.dup
925
+ pages.each do |page|
926
+ list << RDoc::Markup::Paragraph.new(page)
927
+ end
928
+
929
+ out << list
930
+
931
+ display out
932
+ end
933
+
934
+ def check_did_you_mean # :nodoc:
935
+ if defined? DidYouMean::SpellChecker
936
+ true
937
+ else
938
+ begin
939
+ require 'did_you_mean'
940
+ if defined? DidYouMean::SpellChecker
941
+ true
942
+ else
943
+ false
944
+ end
945
+ rescue LoadError
946
+ false
947
+ end
741
948
  end
742
949
  end
743
950
 
951
+ ##
952
+ # Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da"
953
+ # will be expanded to Zlib::DataError.
954
+
955
+ def expand_class klass
956
+ class_names = classes.keys
957
+ ary = class_names.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z"))
958
+ if ary.length != 1 && ary.first != klass
959
+ if check_did_you_mean
960
+ suggestions = DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass)
961
+ raise NotFoundError.new(klass, suggestions)
962
+ else
963
+ raise NotFoundError, klass
964
+ end
965
+ end
966
+ ary.first
967
+ end
968
+
744
969
  ##
745
970
  # Expands the class portion of +name+ into a fully-qualified class. See
746
971
  # #expand_class.
@@ -750,7 +975,27 @@ Options may also be set in the 'RI' environment variable.
750
975
 
751
976
  return [selector, method].join if klass.empty?
752
977
 
753
- "#{expand_class klass}#{selector}#{method}"
978
+ case selector
979
+ when ':' then
980
+ [find_store(klass), selector, method]
981
+ else
982
+ [expand_class(klass), selector, method]
983
+ end.join
984
+ end
985
+
986
+ ##
987
+ # Filters the methods in +found+ trying to find a match for +name+.
988
+
989
+ def filter_methods found, name
990
+ regexp = name_regexp name
991
+
992
+ filtered = found.find_all do |store, methods|
993
+ methods.any? { |method| method.full_name =~ regexp }
994
+ end
995
+
996
+ return filtered unless filtered.empty?
997
+
998
+ found
754
999
  end
755
1000
 
756
1001
  ##
@@ -799,6 +1044,55 @@ Options may also be set in the 'RI' environment variable.
799
1044
  self
800
1045
  end
801
1046
 
1047
+ ##
1048
+ # Finds the given +pager+ for jruby. Returns an IO if +pager+ was found.
1049
+ #
1050
+ # Returns false if +pager+ does not exist.
1051
+ #
1052
+ # Returns nil if the jruby JVM doesn't support ProcessBuilder redirection
1053
+ # (1.6 and older).
1054
+
1055
+ def find_pager_jruby pager
1056
+ require 'java'
1057
+ require 'shellwords'
1058
+
1059
+ return nil unless java.lang.ProcessBuilder.constants.include? :Redirect
1060
+
1061
+ pager = Shellwords.split pager
1062
+
1063
+ pb = java.lang.ProcessBuilder.new(*pager)
1064
+ pb = pb.redirect_output java.lang.ProcessBuilder::Redirect::INHERIT
1065
+
1066
+ @jruby_pager_process = pb.start
1067
+
1068
+ input = @jruby_pager_process.output_stream
1069
+
1070
+ io = input.to_io
1071
+ io.sync = true
1072
+ io
1073
+ rescue java.io.IOException
1074
+ false
1075
+ end
1076
+
1077
+ ##
1078
+ # Finds a store that matches +name+ which can be the name of a gem, "ruby",
1079
+ # "home" or "site".
1080
+ #
1081
+ # See also RDoc::Store#source
1082
+
1083
+ def find_store name
1084
+ @stores.each do |store|
1085
+ source = store.source
1086
+
1087
+ return source if source == name
1088
+
1089
+ return source if
1090
+ store.type == :gem and source =~ /^#{Regexp.escape name}-\d/
1091
+ end
1092
+
1093
+ raise RDoc::RI::Driver::NotFoundError, name
1094
+ end
1095
+
802
1096
  ##
803
1097
  # Creates a new RDoc::Markup::Formatter. If a formatter is given with -f,
804
1098
  # use it. If we're outputting to a pager, use bs, otherwise ansi.
@@ -836,10 +1130,8 @@ Options may also be set in the 'RI' environment variable.
836
1130
 
837
1131
  return if name.nil? or name.empty?
838
1132
 
839
- name = expand_name name.strip
840
-
841
1133
  begin
842
- display_name name
1134
+ display_name expand_name(name.strip)
843
1135
  rescue NotFoundError => e
844
1136
  puts e.message
845
1137
  end
@@ -861,20 +1153,31 @@ Options may also be set in the 'RI' environment variable.
861
1153
  end
862
1154
 
863
1155
  ##
864
- # Lists classes known to ri
1156
+ # Lists classes known to ri starting with +names+. If +names+ is empty all
1157
+ # known classes are shown.
865
1158
 
866
- def list_known_classes
1159
+ def list_known_classes names = []
867
1160
  classes = []
868
1161
 
869
1162
  stores.each do |store|
870
- classes << store.modules
1163
+ classes << store.module_names
871
1164
  end
872
1165
 
873
1166
  classes = classes.flatten.uniq.sort
874
1167
 
1168
+ unless names.empty? then
1169
+ filter = Regexp.union names.map { |name| /^#{name}/ }
1170
+
1171
+ classes = classes.grep filter
1172
+ end
1173
+
875
1174
  page do |io|
876
1175
  if paging? or io.tty? then
877
- io.puts "Classes and Modules known to ri:"
1176
+ if names.empty? then
1177
+ io.puts "Classes and Modules known to ri:"
1178
+ else
1179
+ io.puts "Classes and Modules starting with #{names.join ', '}:"
1180
+ end
878
1181
  io.puts
879
1182
  end
880
1183
 
@@ -893,13 +1196,13 @@ Options may also be set in the 'RI' environment variable.
893
1196
  methods = store.instance_methods[ancestor]
894
1197
 
895
1198
  if methods then
896
- matches = methods.grep(/^#{method}/)
1199
+ matches = methods.grep(/^#{Regexp.escape method.to_s}/)
897
1200
 
898
1201
  matches = matches.map do |match|
899
1202
  "#{klass}##{match}"
900
1203
  end
901
1204
 
902
- found.push(*matches)
1205
+ found.concat matches
903
1206
  end
904
1207
  end
905
1208
 
@@ -907,13 +1210,13 @@ Options may also be set in the 'RI' environment variable.
907
1210
  methods = store.class_methods[ancestor]
908
1211
 
909
1212
  next unless methods
910
- matches = methods.grep(/^#{method}/)
1213
+ matches = methods.grep(/^#{Regexp.escape method.to_s}/)
911
1214
 
912
1215
  matches = matches.map do |match|
913
1216
  "#{klass}::#{match}"
914
1217
  end
915
1218
 
916
- found.push(*matches)
1219
+ found.concat matches
917
1220
  end
918
1221
  end
919
1222
 
@@ -925,7 +1228,7 @@ Options may also be set in the 'RI' environment variable.
925
1228
  # +cache+ indicate if it is a class or instance method.
926
1229
 
927
1230
  def load_method store, cache, klass, type, name
928
- methods = store.send(cache)[klass]
1231
+ methods = store.public_send(cache)[klass]
929
1232
 
930
1233
  return unless methods
931
1234
 
@@ -936,6 +1239,12 @@ Options may also be set in the 'RI' environment variable.
936
1239
  return unless method
937
1240
 
938
1241
  store.load_method klass, "#{type}#{method}"
1242
+ rescue RDoc::Store::MissingFileError => e
1243
+ comment = RDoc::Comment.new("missing documentation at #{e.file}").parse
1244
+
1245
+ method = RDoc::AnyMethod.new nil, name
1246
+ method.comment = comment
1247
+ method
939
1248
  end
940
1249
 
941
1250
  ##
@@ -948,10 +1257,10 @@ Options may also be set in the 'RI' environment variable.
948
1257
  methods = []
949
1258
 
950
1259
  methods << load_method(store, :class_methods, ancestor, '::', method) if
951
- types == :class or types == :both
1260
+ [:class, :both].include? types
952
1261
 
953
1262
  methods << load_method(store, :instance_methods, ancestor, '#', method) if
954
- types == :instance or types == :both
1263
+ [:instance, :both].include? types
955
1264
 
956
1265
  found << [store, methods.compact]
957
1266
  end
@@ -959,6 +1268,49 @@ Options may also be set in the 'RI' environment variable.
959
1268
  found.reject do |path, methods| methods.empty? end
960
1269
  end
961
1270
 
1271
+ ##
1272
+ # Returns a filtered list of methods matching +name+
1273
+
1274
+ def lookup_method name
1275
+ found = load_methods_matching name
1276
+
1277
+ if found.empty?
1278
+ if check_did_you_mean
1279
+ methods = []
1280
+ _, _, method_name = parse_name name
1281
+ find_methods name do |store, klass, ancestor, types, method|
1282
+ methods.push(*store.class_methods[klass]) if [:class, :both].include? types
1283
+ methods.push(*store.instance_methods[klass]) if [:instance, :both].include? types
1284
+ end
1285
+ methods = methods.uniq
1286
+ suggestions = DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name)
1287
+ raise NotFoundError.new(name, suggestions)
1288
+ else
1289
+ raise NotFoundError, name
1290
+ end
1291
+ end
1292
+
1293
+ filter_methods found, name
1294
+ end
1295
+
1296
+ ##
1297
+ # Builds a RDoc::Markup::Document from +found+, +klasses+ and +includes+
1298
+
1299
+ def method_document name, filtered
1300
+ out = RDoc::Markup::Document.new
1301
+
1302
+ out << RDoc::Markup::Heading.new(1, name)
1303
+ out << RDoc::Markup::BlankLine.new
1304
+
1305
+ filtered.each do |store, methods|
1306
+ methods.each do |method|
1307
+ render_method out, store, method, name
1308
+ end
1309
+ end
1310
+
1311
+ out
1312
+ end
1313
+
962
1314
  ##
963
1315
  # Returns the type of method (:both, :instance, :class) for +selector+
964
1316
 
@@ -970,6 +1322,21 @@ Options may also be set in the 'RI' environment variable.
970
1322
  end
971
1323
  end
972
1324
 
1325
+ ##
1326
+ # Returns a regular expression for +name+ that will match an
1327
+ # RDoc::AnyMethod's name.
1328
+
1329
+ def name_regexp name
1330
+ klass, type, name = parse_name name
1331
+
1332
+ case type
1333
+ when '#', '::' then
1334
+ /^#{klass}#{type}#{Regexp.escape name}$/
1335
+ else
1336
+ /^#{klass}(#|::)#{Regexp.escape name}$/
1337
+ end
1338
+ end
1339
+
973
1340
  ##
974
1341
  # Paginates output through a pager program.
975
1342
 
@@ -979,6 +1346,7 @@ Options may also be set in the 'RI' environment variable.
979
1346
  yield pager
980
1347
  ensure
981
1348
  pager.close
1349
+ @jruby_pager_process.wait_for if @jruby_pager_process
982
1350
  end
983
1351
  else
984
1352
  yield $stdout
@@ -996,17 +1364,17 @@ Options may also be set in the 'RI' environment variable.
996
1364
  end
997
1365
 
998
1366
  ##
999
- # Extract the class, selector and method name parts from +name+ like
1367
+ # Extracts the class, selector and method name parts from +name+ like
1000
1368
  # Foo::Bar#baz.
1001
1369
  #
1002
1370
  # NOTE: Given Foo::Bar, Bar is considered a class even though it may be a
1003
- # method
1371
+ # method
1004
1372
 
1005
- def parse_name(name)
1006
- parts = name.split(/(::|#|\.)/)
1373
+ def parse_name name
1374
+ parts = name.split(/(::?|#|\.)/)
1007
1375
 
1008
1376
  if parts.length == 1 then
1009
- if parts.first =~ /^[a-z]/ then
1377
+ if parts.first =~ /^[a-z]|^([%&*+\/<>^`|~-]|\+@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/ then
1010
1378
  type = '.'
1011
1379
  meth = parts.pop
1012
1380
  else
@@ -1016,26 +1384,122 @@ Options may also be set in the 'RI' environment variable.
1016
1384
  elsif parts.length == 2 or parts.last =~ /::|#|\./ then
1017
1385
  type = parts.pop
1018
1386
  meth = nil
1387
+ elsif parts[1] == ':' then
1388
+ klass = parts.shift
1389
+ type = parts.shift
1390
+ meth = parts.join
1019
1391
  elsif parts[-2] != '::' or parts.last !~ /^[A-Z]/ then
1020
1392
  meth = parts.pop
1021
1393
  type = parts.pop
1022
1394
  end
1023
1395
 
1024
- klass = parts.join
1396
+ klass ||= parts.join
1025
1397
 
1026
1398
  [klass, type, meth]
1027
1399
  end
1028
1400
 
1401
+ ##
1402
+ # Renders the +klass+ from +store+ to +out+. If the klass has no
1403
+ # documentable items the class is added to +also_in+ instead.
1404
+
1405
+ def render_class out, store, klass, also_in # :nodoc:
1406
+ comment = klass.comment
1407
+ # TODO the store's cache should always return an empty Array
1408
+ class_methods = store.class_methods[klass.full_name] || []
1409
+ instance_methods = store.instance_methods[klass.full_name] || []
1410
+ attributes = store.attributes[klass.full_name] || []
1411
+
1412
+ if comment.empty? and
1413
+ instance_methods.empty? and class_methods.empty? then
1414
+ also_in << store
1415
+ return
1416
+ end
1417
+
1418
+ add_from out, store
1419
+
1420
+ class_document_comment out, comment
1421
+
1422
+ if class_methods or instance_methods or not klass.constants.empty? then
1423
+ out << RDoc::Markup::Rule.new(1)
1424
+ end
1425
+
1426
+ class_document_constants out, klass
1427
+
1428
+ add_method_list out, class_methods, 'Class methods'
1429
+ add_method_list out, instance_methods, 'Instance methods'
1430
+ add_method_list out, attributes, 'Attributes'
1431
+
1432
+ add_method_documentation out, klass if @show_all
1433
+ end
1434
+
1435
+ def render_method out, store, method, name # :nodoc:
1436
+ out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
1437
+
1438
+ unless name =~ /^#{Regexp.escape method.parent_name}/ then
1439
+ out << RDoc::Markup::Heading.new(3, "Implementation from #{method.parent_name}")
1440
+ end
1441
+
1442
+ out << RDoc::Markup::Rule.new(1)
1443
+
1444
+ render_method_arguments out, method.arglists
1445
+ render_method_superclass out, method
1446
+ if method.is_alias_for
1447
+ al = method.is_alias_for
1448
+ alias_for = store.load_method al.parent_name, "#{al.name_prefix}#{al.name}"
1449
+ render_method_comment out, method, alias_for
1450
+ else
1451
+ render_method_comment out, method
1452
+ end
1453
+ end
1454
+
1455
+ def render_method_arguments out, arglists # :nodoc:
1456
+ return unless arglists
1457
+
1458
+ arglists = arglists.chomp.split "\n"
1459
+ arglists = arglists.map { |line| line + "\n" }
1460
+ out << RDoc::Markup::Verbatim.new(*arglists)
1461
+ out << RDoc::Markup::Rule.new(1)
1462
+ end
1463
+
1464
+ def render_method_comment out, method, alias_for = nil# :nodoc:
1465
+ if alias_for
1466
+ unless method.comment.nil? or method.comment.empty?
1467
+ out << RDoc::Markup::BlankLine.new
1468
+ out << method.comment
1469
+ end
1470
+ out << RDoc::Markup::BlankLine.new
1471
+ out << RDoc::Markup::Paragraph.new("(This method is an alias for #{alias_for.full_name}.)")
1472
+ out << RDoc::Markup::BlankLine.new
1473
+ out << alias_for.comment
1474
+ out << RDoc::Markup::BlankLine.new
1475
+ else
1476
+ out << RDoc::Markup::BlankLine.new
1477
+ out << method.comment
1478
+ out << RDoc::Markup::BlankLine.new
1479
+ end
1480
+ end
1481
+
1482
+ def render_method_superclass out, method # :nodoc:
1483
+ return unless
1484
+ method.respond_to?(:superclass_method) and method.superclass_method
1485
+
1486
+ out << RDoc::Markup::BlankLine.new
1487
+ out << RDoc::Markup::Heading.new(4, "(Uses superclass method #{method.superclass_method})")
1488
+ out << RDoc::Markup::Rule.new(1)
1489
+ end
1490
+
1029
1491
  ##
1030
1492
  # Looks up and displays ri data according to the options given.
1031
1493
 
1032
1494
  def run
1033
1495
  if @list_doc_dirs then
1034
1496
  puts @doc_dirs
1035
- elsif @interactive then
1497
+ elsif @list then
1498
+ list_known_classes @names
1499
+ elsif @server then
1500
+ start_server
1501
+ elsif @interactive or @names.empty? then
1036
1502
  interactive
1037
- elsif @names.empty? then
1038
- list_known_classes
1039
1503
  else
1040
1504
  display_names @names
1041
1505
  end
@@ -1050,18 +1514,28 @@ Options may also be set in the 'RI' environment variable.
1050
1514
  def setup_pager
1051
1515
  return if @use_stdout
1052
1516
 
1517
+ jruby = RUBY_ENGINE == 'jruby'
1518
+
1053
1519
  pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more']
1054
1520
 
1055
1521
  pagers.compact.uniq.each do |pager|
1056
1522
  next unless pager
1057
1523
 
1058
- pager_cmd = pager.split.first
1524
+ pager_cmd = pager.split(' ').first
1059
1525
 
1060
1526
  next unless in_path? pager_cmd
1061
1527
 
1062
- io = IO.popen(pager, 'w') rescue next
1528
+ if jruby then
1529
+ case io = find_pager_jruby(pager)
1530
+ when nil then break
1531
+ when false then next
1532
+ else io
1533
+ end
1534
+ else
1535
+ io = IO.popen(pager, 'w') rescue next
1536
+ end
1063
1537
 
1064
- next if $? and $?.exited? # pager didn't work
1538
+ next if $? and $?.pid == io.pid and $?.exited? # pager didn't work
1065
1539
 
1066
1540
  @paging = true
1067
1541
 
@@ -1073,5 +1547,26 @@ Options may also be set in the 'RI' environment variable.
1073
1547
  nil
1074
1548
  end
1075
1549
 
1076
- end
1550
+ ##
1551
+ # Starts a WEBrick server for ri.
1552
+
1553
+ def start_server
1554
+ begin
1555
+ require 'webrick'
1556
+ rescue LoadError
1557
+ abort "webrick is not found. You may need to `gem install webrick` to install webrick."
1558
+ end
1559
+
1560
+ server = WEBrick::HTTPServer.new :Port => @server
1077
1561
 
1562
+ extra_doc_dirs = @stores.map {|s| s.type == :extra ? s.path : nil}.compact
1563
+
1564
+ server.mount '/', RDoc::Servlet, nil, extra_doc_dirs
1565
+
1566
+ trap 'INT' do server.shutdown end
1567
+ trap 'TERM' do server.shutdown end
1568
+
1569
+ server.start
1570
+ end
1571
+
1572
+ end