summaryrefslogtreecommitdiff
path: root/ruby_1_9_3/lib/rdoc/ri/driver.rb
diff options
context:
space:
mode:
Diffstat (limited to 'ruby_1_9_3/lib/rdoc/ri/driver.rb')
-rw-r--r--ruby_1_9_3/lib/rdoc/ri/driver.rb1178
1 files changed, 0 insertions, 1178 deletions
diff --git a/ruby_1_9_3/lib/rdoc/ri/driver.rb b/ruby_1_9_3/lib/rdoc/ri/driver.rb
deleted file mode 100644
index 26304dca96..0000000000
--- a/ruby_1_9_3/lib/rdoc/ri/driver.rb
+++ /dev/null
@@ -1,1178 +0,0 @@
-require 'abbrev'
-require 'optparse'
-
-begin
- require 'readline'
-rescue LoadError
-end
-
-begin
- require 'win32console'
-rescue LoadError
-end
-
-require 'rdoc/ri'
-require 'rdoc/ri/paths'
-require 'rdoc/markup'
-require 'rdoc/markup/formatter'
-require 'rdoc/text'
-
-##
-# For RubyGems backwards compatibility
-
-require 'rdoc/ri/formatter'
-
-##
-# 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
-
-class RDoc::RI::Driver
-
- ##
- # Base Driver error class
-
- class Error < RDoc::RI::Error; end
-
- ##
- # Raised when a name isn't found in the ri data stores
-
- class NotFoundError < Error
-
- ##
- # Name that wasn't found
-
- alias name message
-
- def message # :nodoc:
- "Nothing known about #{super}"
- end
- end
-
- ##
- # An RDoc::RI::Store for each entry in the RI path
-
- attr_accessor :stores
-
- ##
- # Controls the user of the pager vs $stdout
-
- attr_accessor :use_stdout
-
- ##
- # Default options for ri
-
- 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+ using pp
-
- def self.dump data_path
- require 'pp'
-
- open data_path, 'rb' do |io|
- pp Marshal.load(io.read)
- end
- end
-
- ##
- # Parses +argv+ and returns a Hash of options
-
- 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 | 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.
- EOT
-
- opt.separator nil
- opt.separator "Options:"
-
- 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
-
- 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
-
- ##
- # Runs the ri command line executable using +argv+
-
- 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
-
- ##
- # Creates a new driver using +initial_options+ from ::process_args
-
- 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
-
- ##
- # Adds paths for undocumented classes +also_in+ to +out+
-
- 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
-
- ##
- # Adds a class header to +out+ for class +name+ which is described in
- # +classes+.
-
- 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
-
- ##
- # Adds "(from ...)" to +out+ for +store+
-
- def add_from out, store
- out << RDoc::Markup::Paragraph.new("(from #{store.friendly_path})")
- end
-
- ##
- # Adds +includes+ to +out+
-
- 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
-
- ##
- # Adds a list of +methods+ to +out+ with a heading of +name+
-
- 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
-
- ##
- # Returns ancestor classes of +klass+
-
- 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
-
- ##
- # For RubyGems backwards compatibility
-
- def class_cache # :nodoc:
- end
-
- ##
- # Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+
-
- 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
-
- ##
- # Hash mapping a known class or module to the stores it can be loaded from
-
- 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
-
- ##
- # Returns the stores wherin +name+ is found along with the classes and
- # includes that match it
-
- 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
-
- ##
- # Completes +name+ based on the caches. For Readline
-
- 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 !~ /#|\./ then
- completions = klasses.grep(/^#{Regexp.escape klass_name}[^:]*$/)
- completions.concat klasses.grep(/^#{Regexp.escape name}[^:]*$/) if
- name =~ /::$/
-
- 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 =~ /#|\.|::/ 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
-
- ##
- # Converts +document+ to text and writes it to the pager
-
- def display document
- page do |io|
- text = document.accept formatter(io)
-
- io.write text
- end
- end
-
- ##
- # Outputs formatted RI data for class +name+. Groups undocumented classes
-
- def display_class name
- return if name =~ /#|\./
-
- found, klasses, includes = classes_and_includes_for name
-
- return if found.empty?
-
- out = class_document name, found, klasses, includes
-
- display out
- end
-
- ##
- # Outputs formatted RI data for method +name+
-
- 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
-
- ##
- # 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.
-
- def display_name name
- 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(/^#{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
-
- ##
- # Displays each name in +name+
-
- def display_names names
- names.each do |name|
- name = expand_name name
-
- display_name name
- end
- end
-
- ##
- # Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da"
- # will be expanded to Zlib::DataError.
-
- 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 =~ /^#{expanded}[^:]*$/
- end
-
- abbrevs = Abbrev.abbrev subset
-
- expanded = abbrevs[short]
-
- raise NotFoundError, short unless expanded
-
- expanded.dup
- end
- end
-
- ##
- # Expands the class portion of +name+ into a fully-qualified class. See
- # #expand_class.
-
- def expand_name name
- klass, selector, method = parse_name name
-
- return [selector, method].join if klass.empty?
-
- "#{expand_class klass}#{selector}#{method}"
- end
-
- ##
- # Filters the methods in +found+ trying to find a match for +name+.
-
- 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
-
- ##
- # 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
-
- 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
-
- ##
- # 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.
-
- 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
-
- ##
- # Runs ri interactively using Readline if it is available.
-
- 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
-
- ##
- # Is +file+ in ENV['PATH']?
-
- 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
-
- ##
- # Lists classes known to ri starting with +names+. If +names+ is empty all
- # known classes are shown.
-
- 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| /^#{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
-
- ##
- # Returns an Array of methods matching +name+
-
- 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.push(*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.push(*matches)
- end
- end
-
- found.uniq
- end
-
- ##
- # Loads RI data for method +name+ on +klass+ from +store+. +type+ and
- # +cache+ indicate if it is a class or instance method.
-
- 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
-
- ##
- # Returns an Array of RI data for methods matching +name+
-
- 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
-
- ##
- # Builds a RDoc::Markup::Document from +found+, +klasess+ and +includes+
-
- 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 =~ /^#{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
-
- ##
- # Returns the type of method (:both, :instance, :class) for +selector+
-
- def method_type selector
- case selector
- when '.', nil then :both
- when '#' then :instance
- else :class
- end
- end
-
- ##
- # Returns a regular expression for +name+ that will match an
- # RDoc::AnyMethod's name.
-
- 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
-
- ##
- # Paginates output through a pager program.
-
- 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
-
- ##
- # Are we using a pager?
-
- def paging?
- @paging
- end
-
- ##
- # 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
-
- 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[-2] != '::' or parts.last !~ /^[A-Z]/ then
- meth = parts.pop
- type = parts.pop
- end
-
- klass = parts.join
-
- [klass, type, meth]
- end
-
- ##
- # Looks up and displays ri data according to the options given.
-
- 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
-
- ##
- # Sets up a pager program to pass output through. Tries the RI_PAGER and
- # PAGER environment variables followed by pager, less then more.
-
- 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
-
-end
-