# class RDoc::RI::Driver

The RI driver implements the command-line ri tool.

The driver supports:

- loading 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 RI data sources

### Attributes

show_all[RW]

Show all method documentation following a class or module

stores[RW]

An RDoc::RI::Store for each entry in the RI path

use_stdout[RW]

Controls the user of the pager vs $stdout

### Public Class Methods

default_options() click to toggle source

Default options for ri

    # File lib/rdoc/ri/driver.rb, line 78
    def self.default_options
      options = {}
      options[:interactive] = false
      options[:profile]     = false
      options[:show_all]    = false
      options[:use_cache]   = true
      options[:use_stdout]  = !$stdout.tty?
      options[:width]       = 72

      # By default all standard paths are used.
      options[:use_system]     = true
      options[:use_site]       = true
      options[:use_home]       = true
      options[:use_gems]       = true
      options[:extra_doc_dirs] = []

      return options
    end

dump(data_path) click to toggle source

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

new(initial_options = {}) click to toggle source

Creates a new driver using `initial_options` from ::process_args

    # File lib/rdoc/ri/driver.rb, line 370
    def initialize initial_options = {}
      @paging = false
      @classes = nil

      options = self.class.default_options.update(initial_options)

      @formatter_klass = options[:formatter]

      require 'profile' if options[:profile]

      @names = options[:names]
      @list = options[:list]

      @doc_dirs = []
      @stores   = []

      RDoc::RI::Paths.each(options[:use_system], options[:use_site],
                           options[:use_home], options[:use_gems],
                           *options[: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 = options[:list_doc_dirs]

      @interactive = options[:interactive]
      @server      = options[:server]
      @use_stdout  = options[:use_stdout]
      @show_all    = options[:show_all]

      # pager process for jruby
      @jruby_pager_process = nil
    end

process_args(argv) click to toggle source

Parses `argv` and returns a Hash of options

    # File lib/rdoc/ri/driver.rb, line 111
      def self.process_args argv
        options = default_options

        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.banner = <<-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|
            options[:interactive] = interactive
          end

          opt.separator nil

          opt.on("--[no-]all", "-a",
                 "Show all documentation for a class or",
                 "module.") do |show_all|
            options[:show_all] = show_all
          end

          opt.separator nil

          opt.on("--[no-]list", "-l",
                 "List classes ri knows about.") do |list|
            options[:list] = list
          end

          opt.separator nil

          opt.on("--[no-]pager",
                 "Send output directly to stdout,",
                 "rather than to a pager.") do |use_pager|
            options[:use_stdout] = !use_pager
          end

          opt.separator nil

          opt.on("-T",
                 "Synonym for --no-pager") do
            options[:use_stdout] = true
          end

          opt.separator nil

          opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
                 "Set the width of the output.") do |width|
            options[: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|
            options[: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|
            options[: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|
            options[: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

              options[:extra_doc_dirs] << File.expand_path(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
            options[:use_system] = false
            options[:use_site] = false
            options[:use_gems] = false
            options[:use_home] = false
          end

          opt.separator nil

          opt.on("--[no-]system",
                 "Include documentation from Ruby's standard",
                 "library.  Defaults to true.") do |value|
            options[:use_system] = value
          end

          opt.separator nil

          opt.on("--[no-]site",
                 "Include documentation from libraries",
                 "installed in site_lib.",
                 "Defaults to true.") do |value|
            options[:use_site] = value
          end

          opt.separator nil

          opt.on("--[no-]gems",
                 "Include documentation from RubyGems.",
                 "Defaults to true.") do |value|
            options[:use_gems] = value
          end

          opt.separator nil

          opt.on("--[no-]home",
                 "Include documentation stored in ~/.rdoc.",
                 "Defaults to true.") do |value|
            options[: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|
            options[:profile] = value
          end

          opt.separator nil

          opt.on("--dump=CACHE", File,
                 "Dumps data from an ri cache or data file") do |value|
            options[:dump_path] = value
          end
        end

        argv = ENV['RI'].to_s.split.concat argv

        opts.parse! argv

        options[:names] = argv

        options[:use_stdout] ||= !$stdout.tty?
        options[:use_stdout] ||= options[:interactive]
        options[:width] ||= 72

        options

      rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
        puts opts
        puts
        puts e
        exit 1
      end

run(argv = ARGV) click to toggle source

Runs the ri command line executable using `argv`

    # File lib/rdoc/ri/driver.rb, line 355
    def self.run argv = ARGV
      options = process_args argv

      if options[:dump_path] then
        dump options[:dump_path]
        return
      end

      ri = new options
      ri.run
    end

### Public Instance Methods

add_also_in(out, also_in) click to toggle source

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) click to toggle source

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) click to toggle source

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) click to toggle source

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) click to toggle source

Adds “(from …)” to `out` for `store`

    # File lib/rdoc/ri/driver.rb, line 447
    def add_from out, store
      out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
    end

add_includes(out, includes) click to toggle source

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) click to toggle source

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) click to toggle source

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) click to toggle source

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) click to toggle source

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) click to toggle source

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() click to toggle source

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) click to toggle source

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) click to toggle source

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) click to toggle source

Converts `document` to text and writes it to the pager

    # File lib/rdoc/ri/driver.rb, line 770
    def display document
      page do |io|
        text = document.accept formatter(io)

        io.write text
      end
    end

display_class(name) click to toggle source

Outputs formatted 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) click to toggle source

Outputs formatted 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) click to toggle source

Outputs formatted 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) click to toggle source

Displays each name in `name`

    # File lib/rdoc/ri/driver.rb, line 840
    def display_names names
      names.each do |name|
        name = expand_name name

        display_name name
      end
    end

display_page(name) click to toggle source

Outputs formatted 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) click to toggle source

Outputs a formatted 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) click to toggle source

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 expand_class klass
      ary = classes.keys.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z"))
      raise NotFoundError, klass if ary.length != 1 && ary.first != klass
      ary.first
    end

expand_name(name) click to toggle source

Expands the class portion of `name` into a fully-qualified class. See expand_class.

    # File lib/rdoc/ri/driver.rb, line 919
    def expand_name name
      klass, selector, method = parse_name name

      return [selector, method].join if klass.empty?

      case selector
      when ':' then
        [find_store(klass),   selector, method]
      else
        [expand_class(klass), selector, method]
      end.join
    end

filter_methods(found, name) click to toggle source

Filters the methods in `found` trying to find a match for `name`.

    # File lib/rdoc/ri/driver.rb, line 935
    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) { |*item| ... } click to toggle source

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 953
    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) click to toggle source

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 1001
    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) click to toggle source

Finds a store that matches `name` which can be the name of a gem, “ruby”, “home” or “site”.

See also RDoc::Store#source

    # File lib/rdoc/ri/driver.rb, line 1029
    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) click to toggle source

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.

    # File lib/rdoc/ri/driver.rb, line 1046
    def formatter(io)
      if @formatter_klass then
        @formatter_klass.new
      elsif paging? or !io.tty? then
        RDoc::Markup::ToBs.new
      else
        RDoc::Markup::ToAnsi.new
      end
    end

in_path?(file) click to toggle source

Is `file` in ENV?

    # File lib/rdoc/ri/driver.rb, line 1093
    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() click to toggle source

Runs ri interactively using Readline if it is available.

    # File lib/rdoc/ri/driver.rb, line 1059
    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?

        begin
          display_name expand_name(name.strip)
        rescue NotFoundError => e
          puts e.message
        end
      end

    rescue Interrupt
      exit
    end

list_known_classes(names = []) click to toggle source

Lists classes known to ri starting with `names`. If `names` is empty all known classes are shown.

    # File lib/rdoc/ri/driver.rb, line 1105
    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) click to toggle source

Returns an Array of methods matching `name`

    # File lib/rdoc/ri/driver.rb, line 1137
    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) click to toggle source

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 1176
    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) click to toggle source

Returns an Array of RI data for methods matching `name`

    # File lib/rdoc/ri/driver.rb, line 1199
    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) click to toggle source

Returns a filtered list of methods matching `name`

    # File lib/rdoc/ri/driver.rb, line 1220
    def lookup_method name
      found = load_methods_matching name

      raise NotFoundError, name if found.empty?

      filter_methods found, name
    end

method_document(name, filtered) click to toggle source

Builds a RDoc::Markup::Document from `found`, `klasses` and `includes`

    # File lib/rdoc/ri/driver.rb, line 1231
    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) click to toggle source

Returns the type of method (:both, :instance, :class) for `selector`

    # File lib/rdoc/ri/driver.rb, line 1249
    def method_type selector
      case selector
      when '.', nil then :both
      when '#'      then :instance
      else               :class
      end
    end

name_regexp(name) click to toggle source

Returns a regular expression for `name` that will match an RDoc::AnyMethod's name.

    # File lib/rdoc/ri/driver.rb, line 1261
    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() { |pager| ... } click to toggle source

Paginates output through a pager program.

    # File lib/rdoc/ri/driver.rb, line 1275
    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

paging?() click to toggle source

Are we using a pager?

    # File lib/rdoc/ri/driver.rb, line 1294
    def paging?
      @paging
    end

parse_name(name) click to toggle source

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 1305
    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() click to toggle source

Looks up and displays ri data according to the options given.

    # File lib/rdoc/ri/driver.rb, line 1408
    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.message
    end

setup_pager() click to toggle source

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 1428
    def setup_pager
      return if @use_stdout

      jruby = 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() click to toggle source

Starts a WEBrick server for ri.

    # File lib/rdoc/ri/driver.rb, line 1467
    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