# 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

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 72
    def self.default_options
      options = {}
      options[:use_stdout] = !$stdout.tty?
      options[:width] = 72
      options[:interactive] = false
      options[:use_cache] = true
      options[:profile] = false

      # 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 93
    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 326
    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]
      @use_stdout  = options[:use_stdout]
    end

process_args(argv) click to toggle source

Parses `argv` and returns a Hash of options

    # File lib/rdoc/ri/driver.rb, line 104
      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 = "Usage: #{opt.program_name} [options] [names...]

    Where name can be:

      Class | Class::method | Class#method | Class.method | method

    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.

    For example:

        #{opt.program_name} Fil
        #{opt.program_name} File
        #{opt.program_name} File.new
        #{opt.program_name} zip

    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.

    Options may also be set in the 'RI' environment variable.
    "

          opt.separator nil
          opt.separator "Options:"

          opt.separator nil

          formatters = RDoc::Markup.constants.grep(%r^To[A-Z][a-z]+$/).sort
          formatters = formatters.sort.map do |formatter|
            formatter.to_s.sub('To', '').downcase
          end

          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.on("--no-pager", "-T",
                 "Send output directly to stdout,",
                 "rather than to a pager.") do
            options[:use_stdout] = true
          end

          opt.separator nil

          opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
                 "Set the width of the output.") do |value|
            options[:width] = value
          end

          opt.separator nil

          opt.on("--interactive", "-i",
                 "In interactive mode you can repeatedly",
                 "look up methods with autocomplete.") do
            options[:interactive] = true
          end

          opt.separator nil

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

          opt.separator nil

          opt.on("--[no-]profile",
                 "Run with the ruby profiler") do |value|
            options[:profile] = value
          end

          opt.separator nil
          opt.separator "Data source options:"
          opt.separator nil

          opt.on("--list-doc-dirs",
                 "List the directories from which ri will",
                 "source documentation on stdout and exit.") do
            options[:list_doc_dirs] = true
          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("--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 311
    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 361
    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 378
    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_from(out, store) click to toggle source

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

    # File lib/rdoc/ri/driver.rb, line 398
    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 405
    def add_includes out, includes
      return if includes.empty?

      out << RDoc::Markup::Rule.new(1)
      out << RDoc::Markup::Heading.new(1, "Includes:")

      includes.each do |modules, store|
        if modules.length == 1 then
          include = modules.first
          name = include.name
          path = store.friendly_path
          out << RDoc::Markup::Paragraph.new("#{name} (from #{path})")

          if include.comment then
            out << RDoc::Markup::BlankLine.new
            out << include.comment
          end
        else
          out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")

          wout, with = modules.partition { |incl| incl.comment.empty? }

          out << RDoc::Markup::BlankLine.new unless with.empty?

          with.each do |incl|
            out << RDoc::Markup::Paragraph.new(incl.name)
            out << RDoc::Markup::BlankLine.new
            out << incl.comment
          end

          unless wout.empty? then
            verb = RDoc::Markup::Verbatim.new

            wout.each do |incl|
              verb.push incl.name, "\n"
            end

            out << verb
          end
        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 451
    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
        out.push(*methods.map do |method|
          RDoc::Markup::Verbatim.new method
        end)
      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 471
    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.push(*klasses)
        unexamined.push(*klasses)
      end

      ancestors.reverse
    end

class_document(name, found, klasses, includes) click to toggle source

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

    # File lib/rdoc/ri/driver.rb, line 508
    def class_document name, found, klasses, includes
      also_in = []

      out = RDoc::Markup::Document.new

      add_class out, name, klasses

      add_includes out, includes

      found.each do |store, klass|
        comment = klass.comment
        # TODO the store's cache should always return an empty Array
        class_methods    = store.class_methods[klass.full_name]    || []
        instance_methods = store.instance_methods[klass.full_name] || []
        attributes       = store.attributes[klass.full_name]       || []

        if comment.empty? and
           instance_methods.empty? and class_methods.empty? then
          also_in << store
          next
        end

        add_from out, store

        unless comment.empty? then
          out << RDoc::Markup::Rule.new(1)

          if comment.merged? then
            parts = comment.parts
            parts = parts.zip [RDoc::Markup::BlankLine.new] * parts.length
            parts.flatten!
            parts.pop

            out.push(*parts)
          else
            out << comment
          end
        end

        if class_methods or instance_methods or not klass.constants.empty? then
          out << RDoc::Markup::Rule.new(1)
        end

        unless klass.constants.empty? then
          out << RDoc::Markup::Heading.new(1, "Constants:")
          out << RDoc::Markup::BlankLine.new
          list = RDoc::Markup::List.new :NOTE

          constants = klass.constants.sort_by { |constant| constant.name }

          list.push(*constants.map do |constant|
            parts = constant.comment.parts if constant.comment
            parts << RDoc::Markup::Paragraph.new('[not documented]') if
              parts.empty?

            RDoc::Markup::ListItem.new(constant.name, *parts)
          end)

          out << list
          out << RDoc::Markup::BlankLine.new
        end

        add_method_list out, class_methods,    'Class methods'
        add_method_list out, instance_methods, 'Instance methods'
        add_method_list out, attributes,       'Attributes'
      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 583
    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_for(name) click to toggle source

Returns the stores wherin `name` is found along with the classes and includes that match it

    # File lib/rdoc/ri/driver.rb, line 603
    def classes_and_includes_for name
      klasses = []
      includes = []

      found = @stores.map do |store|
        begin
          klass = store.load_class name
          klasses  << klass
          includes << [klass.includes, store] if klass.includes
          [store, klass]
        rescue Errno::ENOENT
        end
      end.compact

      includes.reject! do |modules,| modules.empty? end

      [found, klasses, includes]
    end

complete(name) click to toggle source

Completes `name` based on the caches. For Readline

    # File lib/rdoc/ri/driver.rb, line 625
    def complete name
      klasses = classes.keys
      completions = []

      klass, selector, method = parse_name name

      # may need to include Foo when given Foo::
      klass_name = method ? name : klass

      if name !~ %r#|\./ then
        completions = klasses.grep(%r^#{Regexp.escape klass_name}[^:]*$/)
        completions.concat klasses.grep(%r^#{Regexp.escape name}[^:]*$/) if
          name =~ %r::$/

        completions << klass if classes.key? klass # to complete a method name
      elsif selector then
        completions << klass if classes.key? klass
      elsif classes.key? klass_name then
        completions << klass_name
      end

      if completions.include? klass and name =~ %r#|\.|::/ then
        methods = list_methods_matching name

        if not methods.empty? then
          # remove Foo if given Foo:: and a method was found
          completions.delete klass
        elsif selector then
          # replace Foo with Foo:: as given
          completions.delete klass
          completions << "#{klass}#{selector}"
        end

        completions.push(*methods)
      end

      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 667
    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 678
    def display_class name
      return if name =~ %r#|\./

      found, klasses, includes = classes_and_includes_for name

      return if found.empty?

      out = class_document name, found, klasses, includes

      display out
    end

display_method(name) click to toggle source

Outputs formatted RI data for method `name`

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

      raise NotFoundError, name if found.empty?

      filtered = filter_methods found, name

      out = method_document name, filtered

      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 711
    def display_name name
      return true if display_class name

      display_method name if name =~ %r::|#|\./

      true
    rescue NotFoundError
      matches = list_methods_matching name if name =~ %r::|#|\./
      matches = classes.keys.grep(%r^#{name}/) if matches.empty?

      raise if matches.empty?

      page do |io|
        io.puts "#{name} not found, maybe you meant:"
        io.puts
        io.puts matches.join("\n")
      end

      false
    end

display_names(names) click to toggle source

Displays each name in `name`

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

        display_name name
      end
    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 747
    def expand_class klass
      klass.split('::').inject '' do |expanded, klass_part|
        expanded << '::' unless expanded.empty?
        short = expanded << klass_part

        subset = classes.keys.select do |klass_name|
          klass_name =~ %r^#{expanded}[^:]*$/
        end

        abbrevs = Abbrev.abbrev subset

        expanded = abbrevs[short]

        raise NotFoundError, short unless expanded

        expanded.dup
      end
    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 770
    def expand_name name
      klass, selector, method = parse_name name

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

      "#{expand_class klass}#{selector}#{method}"
    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 781
    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 799
    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

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 843
    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 892
    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 856
    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 = expand_name name.strip

        begin
          display_name name
        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 904
    def list_known_classes names = []
      classes = []

      stores.each do |store|
        classes << store.modules
      end

      classes = classes.flatten.uniq.sort

      unless names.empty? then
        filter = Regexp.union names.map { |name| %r^#{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 936
    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(%r^#{Regexp.escape method.to_s}/)

            matches = matches.map do |match|
              "#{klass}##{match}"
            end

            found.push(*matches)
          end
        end

        if types == :class or types == :both then
          methods = store.class_methods[ancestor]

          next unless methods
          matches = methods.grep(%r^#{Regexp.escape method.to_s}/)

          matches = matches.map do |match|
            "#{klass}::#{match}"
          end

          found.push(*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 975
    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}"
    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 992
    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

method_document(name, filtered) click to toggle source

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

    # File lib/rdoc/ri/driver.rb, line 1013
    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|
          out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")

          unless name =~ %r^#{Regexp.escape method.parent_name}/ then
            out << RDoc::Markup::Heading.new(3, "Implementation from #{method.parent_name}")
          end
          out << RDoc::Markup::Rule.new(1)

          if method.arglists then
            arglists = method.arglists.chomp.split "\n"
            arglists = arglists.map { |line| line + "\n" }
            out << RDoc::Markup::Verbatim.new(*arglists)
            out << RDoc::Markup::Rule.new(1)
          end

          out << RDoc::Markup::BlankLine.new
          out << method.comment
          out << RDoc::Markup::BlankLine.new
        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 1047
    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 1059
    def name_regexp name
      klass, type, name = parse_name name

      case type
      when '#', '::' then
        %r^#{klass}#{type}#{Regexp.escape name}$/
      else
        %r^#{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 1073
    def page
      if pager = setup_pager then
        begin
          yield pager
        ensure
          pager.close
        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 1091
    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 1102
    def parse_name name
      parts = name.split(%r(::|#|\.)/)

      if parts.length == 1 then
        if parts.first =~ %r^[a-z]|^([%&*+\/<>^`|~-]|\+@|-@|<<|<=>?|===?|=>|=~|>>|\[\]=?|~@)$/ then
          type = '.'
          meth = parts.pop
        else
          type = nil
          meth = nil
        end
      elsif parts.length == 2 or parts.last =~ %r::|#|\./ then
        type = parts.pop
        meth = nil
      elsif parts[-2] != '::' or parts.last !~ %r^[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 1129
    def run
      if @list_doc_dirs then
        puts @doc_dirs
      elsif @list then
        list_known_classes @names
      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 1147
    def setup_pager
      return if @use_stdout

      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

        io = IO.popen(pager, 'w') rescue next

        next if $? and $?.exited? # pager didn't work

        @paging = true

        return io
      end

      @use_stdout = true

      nil
    end