mega-max-hub 0.0.1

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