Class: RDoc::RI::Driver
Relationships & Source Files | |
Namespace Children | |
Exceptions:
| |
Inherits: | Object |
Defined in: | lib/rdoc/ri/driver.rb |
Overview
The RI driver implements the command-line ri tool.
The driver supports:
-
loading ::RDoc::RI data from:
-
Ruby's standard library
-
RubyGems
-
~/.rdoc
-
A user-supplied directory
-
-
Paging output (uses RI_PAGER environment variable, PAGER environment variable or the less, more and pager programs)
-
Interactive mode with tab-completion
-
Abbreviated names (ri Zl shows Zlib documentation)
-
Colorized output
-
Merging output from multiple ::RDoc::RI data sources
Class Method Summary
-
.default_options
Default options for ri.
-
.dump(data_path)
Dump
data_path
using pp. -
.new(initial_options = {}) ⇒ Driver
constructor
Creates a new driver using
initial_options
from .process_args -
.process_args(argv)
Parses
argv
and returns a Hash of options. -
.run(argv = ARGV)
Runs the ri command line executable using
argv
Instance Attribute Summary
-
#show_all
rw
Show all method documentation following a class or module.
-
#stores
rw
An Store for each entry in the ::RDoc::RI path.
-
#use_stdout
rw
Controls the user of the pager vs $stdout.
-
#paging? ⇒ Boolean
readonly
Are we using a pager?
Instance Method Summary
-
#add_also_in(out, also_in)
Adds paths for undocumented classes
also_in
toout
-
#add_class(out, name, classes)
Adds a class header to
out
for classname
which is described in #classes. -
#add_extends(out, extends)
Adds
extends
toout
-
#add_extension_modules(out, type, extensions)
Adds a list of
extensions
to this module of the giventype
toout
. -
#add_from(out, store)
Adds “(from …)” to
out
forstore
-
#add_includes(out, includes)
Adds
includes
toout
-
#add_method(out, name)
Looks up the method
name
and adds it toout
-
#add_method_documentation(out, klass)
Adds documentation for all methods in
klass
toout
-
#add_method_list(out, methods, name)
Adds a list of
methods
toout
with a heading ofname
-
#ancestors_of(klass)
Returns ancestor classes of
klass
-
#class_document(name, found, klasses, includes, extends)
Builds a ::RDoc::Markup::Document from
found
,klasess
andincludes
-
#classes
Hash mapping a known class or module to the stores it can be loaded from.
-
#classes_and_includes_and_extends_for(name)
Returns the stores wherein
name
is found along with the classes, extends and includes that match it. -
#complete(name)
Completes
name
based on the caches. -
#display(document)
Converts
document
to text and writes it to the pager. -
#display_class(name)
Outputs formatted ::RDoc::RI data for class
name
. -
#display_method(name)
Outputs formatted ::RDoc::RI data for method
name
-
#display_name(name)
Outputs formatted ::RDoc::RI data for the class or method
name
. -
#display_names(names)
Displays each name in
name
-
#display_page(name)
Outputs formatted ::RDoc::RI data for page
name
. -
#display_page_list(store, pages = store.cache[:pages], search = nil)
Outputs a formatted ::RDoc::RI page list for the pages in
store
. -
#expand_class(klass)
Expands abbreviated klass
klass
into a fully-qualified class. -
#expand_name(name)
Expands the class portion of
name
into a fully-qualified class. -
#filter_methods(found, name)
Filters the methods in
found
trying to find a match forname
. -
#find_methods(name)
Yields items matching
name
including the store they were found in, the class being searched for, the class they were found in (an ancestor) the types of methods to look up (from #method_type), and the method name being searched for. -
#find_pager_jruby(pager)
Finds the given
pager
for jruby. -
#find_store(name)
Finds a store that matches
name
which can be the name of a gem, “ruby”, “home” or “site”. -
#formatter(io)
Creates a new ::RDoc::Markup::Formatter.
-
#in_path?(file) ⇒ Boolean
Is
file
in ENV? -
#interactive
Runs ri interactively using Readline if it is available.
-
#list_known_classes(names = [])
Lists classes known to ri starting with
names
. -
#list_methods_matching(name)
Returns an Array of methods matching
name
-
#load_method(store, cache, klass, type, name)
Loads RI data for method
name
onklass
fromstore
. -
#load_methods_matching(name)
Returns an Array of ::RDoc::RI data for methods matching
name
-
#lookup_method(name)
Returns a filtered list of methods matching
name
-
#method_document(name, filtered)
Builds a ::RDoc::Markup::Document from
found
,klasses
andincludes
-
#method_type(selector)
Returns the type of method (:both,
:instance
,:class
) forselector
-
#name_regexp(name)
Returns a regular expression for
name
that will match an RDoc::AnyMethod's name. -
#page
Paginates output through a pager program.
-
#parse_name(name)
Extracts the class, selector and method name parts from
name
likeFoo::Bar#baz
. -
#run
Looks up and displays ri data according to the options given.
-
#setup_pager
Sets up a pager program to pass output through.
-
#start_server
Starts a WEBrick server for ri.
Constructor Details
.new(initial_options = {}) ⇒ Driver
Creates a new driver using initial_options
from .process_args
# File 'lib/rdoc/ri/driver.rb', line 370
def initialize = {} @paging = false @classes = nil = self.class. .update( ) @formatter_klass = [:formatter] require 'profile' if [:profile] @names = [:names] @list = [:list] @doc_dirs = [] @stores = [] RDoc::RI::Paths.each( [:use_system], [:use_site], [:use_home], [:use_gems], * [:extra_doc_dirs]) do |path, type| @doc_dirs << path store = RDoc::RI::Store.new path, type store.load_cache @stores << store end @list_doc_dirs = [:list_doc_dirs] @interactive = [:interactive] @server = [:server] @use_stdout = [:use_stdout] @show_all = [:show_all] # pager process for jruby @jruby_pager_process = nil end
Class Method Details
.default_options
Default options for ri
# File 'lib/rdoc/ri/driver.rb', line 78
def self. = {} [:interactive] = false [:profile] = false [:show_all] = false [:use_cache] = true [:use_stdout] = !$stdout.tty? [:width] = 72 # By default all standard paths are used. [:use_system] = true [:use_site] = true [:use_home] = true [:use_gems] = true [:extra_doc_dirs] = [] return end
.dump(data_path)
Dump data_path
using pp
# File 'lib/rdoc/ri/driver.rb', line 100
def self.dump data_path require 'pp' open data_path, 'rb' do |io| pp Marshal.load(io.read) end end
.process_args(argv)
Parses argv
and returns a Hash of options
# File 'lib/rdoc/ri/driver.rb', line 111
def self.process_args argv = opts = OptionParser.new do |opt| opt.accept File do |file,| File.readable?(file) and not File.directory?(file) and file end opt.program_name = File.basename $0 opt.version = RDoc::VERSION opt.release = nil opt.summary_indent = ' ' * 4 opt. = <<-EOT Usage: #{opt.program_name} [options] [names...] Where name can be: Class | Module | Module::Class Class::method | Class#method | Class.method | method gem_name: | gem_name:README | gem_name:History All class names may be abbreviated to their minimum unambiguous form. If a name is ambiguous, all valid options will be listed. A '.' matches either class or instance methods, while #method matches only instance and ::method matches only class methods. README and other files may be displayed by prefixing them with the gem name they're contained in. If the gem name is followed by a ':' all files in the gem will be shown. The file name extension may be omitted where it is unambiguous. For example: #{opt.program_name} Fil #{opt.program_name} File #{opt.program_name} File.new #{opt.program_name} zip #{opt.program_name} rdoc:README Note that shell quoting or escaping may be required for method names containing punctuation: #{opt.program_name} 'Array.[]' #{opt.program_name} compact\\! To see the default directories ri will search, run: #{opt.program_name} --list-doc-dirs Specifying the --system, --site, --home, --gems or --doc-dir options will limit ri to searching only the specified directories. ri options may be set in the 'RI' environment variable. The ri pager can be set with the 'RI_PAGER' environment variable or the 'PAGER' environment variable. EOT opt.separator nil opt.separator "Options:" opt.separator nil opt.on("--[no-]interactive", "-i", "In interactive mode you can repeatedly", "look up methods with autocomplete.") do |interactive| [:interactive] = interactive end opt.separator nil opt.on("--[no-]all", "-a", "Show all documentation for a class or", "module.") do |show_all| [:show_all] = show_all end opt.separator nil opt.on("--[no-]list", "-l", "List classes ri knows about.") do |list| [:list] = list end opt.separator nil opt.on("--[no-]pager", "Send output directly to stdout,", "rather than to a pager.") do |use_pager| [:use_stdout] = !use_pager end opt.separator nil opt.on("-T", "Synonym for --no-pager") do [:use_stdout] = true end opt.separator nil opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger, "Set the width of the output.") do |width| [:width] = width end opt.separator nil opt.on("--server [PORT]", Integer, "Run RDoc server on the given port.", "The default port is 8214.") do |port| [:server] = port || 8214 end opt.separator nil formatters = RDoc::Markup.constants.grep(/^To[A-Z][a-z]+$/).sort formatters = formatters.sort.map do |formatter| formatter.to_s.sub('To', '').downcase end formatters -= %w[html label test] # remove useless output formats opt.on("--format=NAME", "-f", "Uses the selected formatter. The default", "formatter is bs for paged output and ansi", "otherwise. Valid formatters are:", formatters.join(' '), formatters) do |value| [:formatter] = RDoc::Markup.const_get "To#{value.capitalize}" end opt.separator nil opt.separator "Data source options:" opt.separator nil opt.on("--[no-]list-doc-dirs", "List the directories from which ri will", "source documentation on stdout and exit.") do |list_doc_dirs| [:list_doc_dirs] = list_doc_dirs end opt.separator nil opt.on("--doc-dir=DIRNAME", "-d", Array, "List of directories from which to source", "documentation in addition to the standard", "directories. May be repeated.") do |value| value.each do |dir| unless File.directory? dir then raise OptionParser::InvalidArgument, "#{dir} is not a directory" end [:extra_doc_dirs] << File. (dir) end end opt.separator nil opt.on("--no-standard-docs", "Do not include documentation from", "the Ruby standard library, site_lib,", "installed gems, or ~/.rdoc.", "Use with --doc-dir") do [:use_system] = false [:use_site] = false [:use_gems] = false [:use_home] = false end opt.separator nil opt.on("--[no-]system", "Include documentation from Ruby's standard", "library. Defaults to true.") do |value| [:use_system] = value end opt.separator nil opt.on("--[no-]site", "Include documentation from libraries", "installed in site_lib.", "Defaults to true.") do |value| [:use_site] = value end opt.separator nil opt.on("--[no-]gems", "Include documentation from RubyGems.", "Defaults to true.") do |value| [:use_gems] = value end opt.separator nil opt.on("--[no-]home", "Include documentation stored in ~/.rdoc.", "Defaults to true.") do |value| [:use_home] = value end opt.separator nil opt.separator "Debug options:" opt.separator nil opt.on("--[no-]profile", "Run with the ruby profiler") do |value| [:profile] = value end opt.separator nil opt.on("--dump=CACHE", File, "Dumps data from an ri cache or data file") do |value| [:dump_path] = value end end argv = ENV['RI'].to_s.split.concat argv opts.parse! argv [:names] = argv [:use_stdout] ||= !$stdout.tty? [:use_stdout] ||= [:interactive] [:width] ||= 72 rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e puts opts puts puts e exit 1 end
.run(argv = ARGV)
Runs the ri command line executable using argv
# File 'lib/rdoc/ri/driver.rb', line 355
def self.run argv = ARGV = process_args argv if [:dump_path] then dump [:dump_path] return end ri = new ri.run end
Instance Attribute Details
#paging? ⇒ Boolean
(readonly)
Are we using a pager?
# File 'lib/rdoc/ri/driver.rb', line 1309
def paging? @paging end
#show_all (rw)
Show all method documentation following a class or module
# File 'lib/rdoc/ri/driver.rb', line 63
attr_accessor :show_all
#stores (rw)
An Store for each entry in the ::RDoc::RI path
# File 'lib/rdoc/ri/driver.rb', line 68
attr_accessor :stores
#use_stdout (rw)
Controls the user of the pager vs $stdout
# File 'lib/rdoc/ri/driver.rb', line 73
attr_accessor :use_stdout
Instance Method Details
#add_also_in(out, also_in)
Adds paths for undocumented classes also_in
to out
# File 'lib/rdoc/ri/driver.rb', line 410
def add_also_in out, also_in return if also_in.empty? out << RDoc::Markup::Rule.new(1) out << RDoc::Markup::Paragraph.new("Also found in:") paths = RDoc::Markup::Verbatim.new also_in.each do |store| paths.parts.push store.friendly_path, "\n" end out << paths end
#add_class(out, name, classes)
Adds a class header to out
for class name
which is described in #classes.
# File 'lib/rdoc/ri/driver.rb', line 427
def add_class out, name, classes heading = if classes.all? { |klass| klass.module? } then name else superclass = classes.map do |klass| klass.superclass unless klass.module? end.compact.shift || 'Object' superclass = superclass.full_name unless String === superclass "#{name} < #{superclass}" end out << RDoc::Markup::Heading.new(1, heading) out << RDoc::Markup::BlankLine.new end
#add_extends(out, extends)
Adds extends
to out
# File 'lib/rdoc/ri/driver.rb', line 454
def add_extends out, extends add_extension_modules out, 'Extended by', extends end
#add_extension_modules(out, type, extensions)
Adds a list of extensions
to this module of the given type
to out
. add_includes and add_extends call this, so you should use those directly.
# File 'lib/rdoc/ri/driver.rb', line 462
def add_extension_modules out, type, extensions return if extensions.empty? out << RDoc::Markup::Rule.new(1) out << RDoc::Markup::Heading.new(1, "#{type}:") extensions.each do |modules, store| if modules.length == 1 then add_extension_modules_single out, store, modules.first else add_extension_modules_multiple out, store, modules end end end
#add_from(out, store)
Adds “(from …)” to out
for store
#add_includes(out, includes)
Adds includes
to out
# File 'lib/rdoc/ri/driver.rb', line 521
def add_includes out, includes add_extension_modules out, 'Includes', includes end
#add_method(out, name)
Looks up the method name
and adds it to out
# File 'lib/rdoc/ri/driver.rb', line 528
def add_method out, name filtered = lookup_method name method_out = method_document name, filtered out.concat method_out.parts end
#add_method_documentation(out, klass)
Adds documentation for all methods in klass
to out
# File 'lib/rdoc/ri/driver.rb', line 539
def add_method_documentation out, klass klass.method_list.each do |method| begin add_method out, method.full_name rescue NotFoundError next end end end
#add_method_list(out, methods, name)
Adds a list of methods
to out
with a heading of name
# File 'lib/rdoc/ri/driver.rb', line 552
def add_method_list out, methods, name return if methods.empty? out << RDoc::Markup::Heading.new(1, "#{name}:") out << RDoc::Markup::BlankLine.new if @use_stdout and !@interactive then out.concat methods.map { |method| RDoc::Markup::Verbatim.new method } else out << RDoc::Markup::IndentedParagraph.new(2, methods.join(', ')) end out << RDoc::Markup::BlankLine.new end
#ancestors_of(klass)
Returns ancestor classes of klass
# File 'lib/rdoc/ri/driver.rb', line 572
def ancestors_of klass ancestors = [] unexamined = [klass] seen = [] loop do break if unexamined.empty? current = unexamined.shift seen << current stores = classes[current] break unless stores and not stores.empty? klasses = stores.map do |store| store.ancestors[current] end.flatten.uniq klasses = klasses - seen ancestors.concat klasses unexamined.concat klasses end ancestors.reverse end
#class_document(name, found, klasses, includes, extends)
Builds a ::RDoc::Markup::Document from found
, klasess
and includes
# File 'lib/rdoc/ri/driver.rb', line 609
def class_document name, found, klasses, includes, extends also_in = [] out = RDoc::Markup::Document.new add_class out, name, klasses add_includes out, includes add_extends out, extends found.each do |store, klass| render_class out, store, klass, also_in end add_also_in out, also_in out end
#classes
Hash mapping a known class or module to the stores it can be loaded from
# File 'lib/rdoc/ri/driver.rb', line 675
def classes return @classes if @classes @classes = {} @stores.each do |store| store.cache[:modules].each do |mod| # using default block causes searched-for modules to be added @classes[mod] ||= [] @classes[mod] << store end end @classes end
#classes_and_includes_and_extends_for(name)
Returns the stores wherein name
is found along with the classes, extends and includes that match it
# File 'lib/rdoc/ri/driver.rb', line 695
def classes_and_includes_and_extends_for name klasses = [] extends = [] includes = [] found = @stores.map do |store| begin klass = store.load_class name klasses << klass extends << [klass.extends, store] if klass.extends includes << [klass.includes, store] if klass.includes [store, klass] rescue RDoc::Store::MissingFileError end end.compact extends.reject! do |modules,| modules.empty? end includes.reject! do |modules,| modules.empty? end [found, klasses, includes, extends] end
#complete(name)
Completes name
based on the caches. For Readline
# File 'lib/rdoc/ri/driver.rb', line 720
def complete name completions = [] klass, selector, method = parse_name name complete_klass name, klass, selector, method, completions complete_method name, klass, selector, completions completions.sort.uniq end
#display(document)
Converts document
to text and writes it to the pager
#display_class(name)
Outputs formatted ::RDoc::RI data for class name
. Groups undocumented classes
# File 'lib/rdoc/ri/driver.rb', line 781
def display_class name return if name =~ /#|\./ found, klasses, includes, extends = classes_and_includes_and_extends_for name return if found.empty? out = class_document name, found, klasses, includes, extends display out end
#display_method(name)
Outputs formatted ::RDoc::RI data for method name
# File 'lib/rdoc/ri/driver.rb', line 797
def display_method name out = RDoc::Markup::Document.new add_method out, name display out end
#display_name(name)
Outputs formatted ::RDoc::RI data for the class or method name
.
Returns true if name
was found, false if it was not an alternative could be guessed, raises an error if name
couldn't be guessed.
# File 'lib/rdoc/ri/driver.rb', line 811
def display_name name if name =~ /\w:(\w|$)/ then display_page name return true end return true if display_class name display_method name if name =~ /::|#|\./ true rescue NotFoundError matches = list_methods_matching name if name =~ /::|#|\./ matches = classes.keys.grep(/^#{Regexp.escape name}/) if matches.empty? raise if matches.empty? page do |io| io.puts "#{name} not found, maybe you meant:" io.puts io.puts matches.sort.join("\n") end false end
#display_names(names)
Displays each name in name
# File 'lib/rdoc/ri/driver.rb', line 840
def display_names names names.each do |name| name = name display_name name end end
#display_page(name)
Outputs formatted ::RDoc::RI data for page name
.
# File 'lib/rdoc/ri/driver.rb', line 851
def display_page name store_name, page_name = name.split ':', 2 store = @stores.find { |s| s.source == store_name } return display_page_list store if page_name.empty? pages = store.cache[:pages] unless pages.include? page_name then found_names = pages.select do |n| n =~ /#{Regexp.escape page_name}\.[^.]+$/ end if found_names.length.zero? then return display_page_list store, pages elsif found_names.length > 1 then return display_page_list store, found_names, page_name end page_name = found_names.first end page = store.load_page page_name display page.comment end
#display_page_list(store, pages = store.cache[:pages], search = nil)
Outputs a formatted ::RDoc::RI page list for the pages in store
.
# File 'lib/rdoc/ri/driver.rb', line 882
def display_page_list store, pages = store.cache[:pages], search = nil out = RDoc::Markup::Document.new title = if search then "#{search} pages" else 'Pages' end out << RDoc::Markup::Heading.new(1, "#{title} in #{store.friendly_path}") out << RDoc::Markup::BlankLine.new list = RDoc::Markup::List.new(:BULLET) pages.each do |page| list << RDoc::Markup::Paragraph.new(page) end out << list display out end
#expand_class(klass)
Expands abbreviated klass klass
into a fully-qualified class. “Zl::Da” will be expanded to Zlib::DataError
.
# File 'lib/rdoc/ri/driver.rb', line 909
def klass klass.split('::').inject '' do |, klass_part| << '::' unless .empty? short = << klass_part subset = classes.keys.select do |klass_name| klass_name =~ /^#{}[^:]*$/ end abbrevs = Abbrev.abbrev subset = abbrevs[short] raise NotFoundError, short unless .dup end end
#expand_name(name)
Expands the class portion of name
into a fully-qualified class. See #expand_class.
# File 'lib/rdoc/ri/driver.rb', line 932
def name klass, selector, method = parse_name name return [selector, method].join if klass.empty? case selector when ':' then [find_store(klass), selector, method] else [ (klass), selector, method] end.join end
#filter_methods(found, name)
Filters the methods in found
trying to find a match for name
.
# File 'lib/rdoc/ri/driver.rb', line 948
def filter_methods found, name regexp = name_regexp name filtered = found.find_all do |store, methods| methods.any? { |method| method.full_name =~ regexp } end return filtered unless filtered.empty? found end
#find_methods(name)
Yields items matching name
including the store they were found in, the class being searched for, the class they were found in (an ancestor) the types of methods to look up (from #method_type), and the method name being searched for
# File 'lib/rdoc/ri/driver.rb', line 966
def find_methods name klass, selector, method = parse_name name types = method_type selector klasses = nil ambiguous = klass.empty? if ambiguous then klasses = classes.keys else klasses = ancestors_of klass klasses.unshift klass end methods = [] klasses.each do |ancestor| ancestors = classes[ancestor] next unless ancestors klass = ancestor if ambiguous ancestors.each do |store| methods << [store, klass, ancestor, types, method] end end methods = methods.sort_by do |_, k, a, _, m| [k, a, m].compact end methods.each do |item| yield(*item) # :yields: store, klass, ancestor, types, method end self end
#find_pager_jruby(pager)
Finds the given pager
for jruby. Returns an IO if pager
was found.
Returns false if pager
does not exist.
Returns nil if the jruby JVM doesn't support ProcessBuilder redirection (1.6 and older).
# File 'lib/rdoc/ri/driver.rb', line 1014
def find_pager_jruby pager require 'java' require 'shellwords' return nil unless java.lang.ProcessBuilder.constants.include? :Redirect pager = Shellwords.split pager pb = java.lang.ProcessBuilder.new(*pager) pb = pb.redirect_output java.lang.ProcessBuilder::Redirect::INHERIT @jruby_pager_process = pb.start input = @jruby_pager_process.output_stream io = input.to_io io.sync = true io rescue java.io.IOException false end
#find_store(name)
Finds a store that matches name
which can be the name of a gem, “ruby”, “home” or “site”.
See also Store#source
# File 'lib/rdoc/ri/driver.rb', line 1042
def find_store name @stores.each do |store| source = store.source return source if source == name return source if store.type == :gem and source =~ /^#{Regexp.escape name}-\d/ end raise RDoc::RI::Driver::NotFoundError, name end
#formatter(io)
Creates a new ::RDoc::Markup::Formatter. If a formatter is given with -f, use it. If we're outputting to a pager, use bs, otherwise ansi.
#in_path?(file) ⇒ Boolean
Is file
in ENV?
# File 'lib/rdoc/ri/driver.rb', line 1108
def in_path? file return true if file =~ %r%\A/% and File.exist? file ENV['PATH'].split(File::PATH_SEPARATOR).any? do |path| File.exist? File.join(path, file) end end
#interactive
Runs ri interactively using Readline if it is available.
# File 'lib/rdoc/ri/driver.rb', line 1072
def interactive puts "\nEnter the method name you want to look up." if defined? Readline then Readline.completion_proc = method :complete puts "You can use tab to autocomplete." end puts "Enter a blank line to exit.\n\n" loop do name = if defined? Readline then Readline.readline ">> " else print ">> " $stdin.gets end return if name.nil? or name.empty? name = name.strip begin display_name name rescue NotFoundError => e puts e. end end rescue Interrupt exit end
#list_known_classes(names = [])
Lists classes known to ri starting with names
. If names
is empty all known classes are shown.
# File 'lib/rdoc/ri/driver.rb', line 1120
def list_known_classes names = [] classes = [] stores.each do |store| classes << store.module_names end classes = classes.flatten.uniq.sort unless names.empty? then filter = Regexp.union names.map { |name| /^#{name}/ } classes = classes.grep filter end page do |io| if paging? or io.tty? then if names.empty? then io.puts "Classes and Modules known to ri:" else io.puts "Classes and Modules starting with #{names.join ', '}:" end io.puts end io.puts classes.join("\n") end end
#list_methods_matching(name)
Returns an Array of methods matching name
# File 'lib/rdoc/ri/driver.rb', line 1152
def list_methods_matching name found = [] find_methods name do |store, klass, ancestor, types, method| if types == :instance or types == :both then methods = store.instance_methods[ancestor] if methods then matches = methods.grep(/^#{Regexp.escape method.to_s}/) matches = matches.map do |match| "#{klass}##{match}" end found.concat matches end end if types == :class or types == :both then methods = store.class_methods[ancestor] next unless methods matches = methods.grep(/^#{Regexp.escape method.to_s}/) matches = matches.map do |match| "#{klass}::#{match}" end found.concat matches end end found.uniq end
#load_method(store, cache, klass, type, name)
Loads RI data for method name
on klass
from store
. type
and cache
indicate if it is a class or instance method.
# File 'lib/rdoc/ri/driver.rb', line 1191
def load_method store, cache, klass, type, name methods = store.send(cache)[klass] return unless methods method = methods.find do |method_name| method_name == name end return unless method store.load_method klass, "#{type}#{method}" rescue RDoc::Store::MissingFileError => e comment = RDoc::Comment.new("missing documentation at #{e.file}").parse method = RDoc::AnyMethod.new nil, name method.comment = comment method end
#load_methods_matching(name)
Returns an Array of ::RDoc::RI data for methods matching name
# File 'lib/rdoc/ri/driver.rb', line 1214
def load_methods_matching name found = [] find_methods name do |store, klass, ancestor, types, method| methods = [] methods << load_method(store, :class_methods, ancestor, '::', method) if [:class, :both].include? types methods << load_method(store, :instance_methods, ancestor, '#', method) if [:instance, :both].include? types found << [store, methods.compact] end found.reject do |path, methods| methods.empty? end end
#lookup_method(name)
Returns a filtered list of methods matching name
# File 'lib/rdoc/ri/driver.rb', line 1235
def lookup_method name found = load_methods_matching name raise NotFoundError, name if found.empty? filter_methods found, name end
#method_document(name, filtered)
Builds a ::RDoc::Markup::Document from found
, klasses
and includes
# File 'lib/rdoc/ri/driver.rb', line 1246
def method_document name, filtered out = RDoc::Markup::Document.new out << RDoc::Markup::Heading.new(1, name) out << RDoc::Markup::BlankLine.new filtered.each do |store, methods| methods.each do |method| render_method out, store, method, name end end out end
#method_type(selector)
Returns the type of method (:both, :instance
, :class
) for selector
# File 'lib/rdoc/ri/driver.rb', line 1264
def method_type selector case selector when '.', nil then :both when '#' then :instance else :class end end
#name_regexp(name)
Returns a regular expression for name
that will match an RDoc::AnyMethod's name.
# File 'lib/rdoc/ri/driver.rb', line 1276
def name_regexp name klass, type, name = parse_name name case type when '#', '::' then /^#{klass}#{type}#{Regexp.escape name}$/ else /^#{klass}(#|::)#{Regexp.escape name}$/ end end
#page
Paginates output through a pager program.
# File 'lib/rdoc/ri/driver.rb', line 1290
def page if pager = setup_pager then begin yield pager ensure pager.close @jruby_pager_process.wait_for if @jruby_pager_process end else yield $stdout end rescue Errno::EPIPE ensure @paging = false end
#parse_name(name)
Extracts the class, selector and method name parts from name
like Foo::Bar#baz
.
NOTE: Given Foo::Bar
, Bar is considered a class even though it may be a method
# File 'lib/rdoc/ri/driver.rb', line 1320
def parse_name name parts = name.split(/(::?|#|\.)/) if parts.length == 1 then if parts.first =~ /^[a-z]|^([%&*\/<>^`|~-]|\@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/ then type = '.' meth = parts.pop else type = nil meth = nil end elsif parts.length == 2 or parts.last =~ /::|#|\./ then type = parts.pop meth = nil elsif parts[1] == ':' then klass = parts.shift type = parts.shift meth = parts.join elsif parts[-2] != '::' or parts.last !~ /^[A-Z]/ then meth = parts.pop type = parts.pop end klass ||= parts.join [klass, type, meth] end
#run
Looks up and displays ri data according to the options given.
# File 'lib/rdoc/ri/driver.rb', line 1423
def run if @list_doc_dirs then puts @doc_dirs elsif @list then list_known_classes @names elsif @server then start_server elsif @interactive or @names.empty? then interactive else display_names @names end rescue NotFoundError => e abort e. end
#setup_pager
Sets up a pager program to pass output through. Tries the RI_PAGER and PAGER environment variables followed by pager, less then more.
# File 'lib/rdoc/ri/driver.rb', line 1443
def setup_pager return if @use_stdout jruby = Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE == 'jruby' pagers = [ENV['RI_PAGER'], ENV['PAGER'], 'pager', 'less', 'more'] pagers.compact.uniq.each do |pager| next unless pager pager_cmd = pager.split.first next unless in_path? pager_cmd if jruby then case io = find_pager_jruby(pager) when nil then break when false then next else io end else io = IO.popen(pager, 'w') rescue next end next if $? and $?.pid == io.pid and $?.exited? # pager didn't work @paging = true return io end @use_stdout = true nil end
#start_server
Starts a WEBrick server for ri.
# File 'lib/rdoc/ri/driver.rb', line 1482
def start_server require 'webrick' server = WEBrick::HTTPServer.new :Port => @server extra_doc_dirs = @stores.map {|s| s.type == :extra ? s.path : nil}.compact server.mount '/', RDoc::Servlet, nil, extra_doc_dirs trap 'INT' do server.shutdown end trap 'TERM' do server.shutdown end server.start end