aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gems/rdoc-2.4.3/lib/rdoc/ri
diff options
context:
space:
mode:
authorRobin Houston <robin@lenny.robin>2011-08-24 18:09:33 +0100
committerRobin Houston <robin@lenny.robin>2011-08-24 18:09:33 +0100
commit95ed2bc24312699cfce9bb6f9bc1418b15718bb1 (patch)
tree6639e8b140b0d74a8f93c2ab00d7a7faba41d6d7 /vendor/gems/rdoc-2.4.3/lib/rdoc/ri
parent68a5989094f63a7e32fd6745b1c5739e038339f3 (diff)
Add rdoc 2.4.3 to vendor/gems
Diffstat (limited to 'vendor/gems/rdoc-2.4.3/lib/rdoc/ri')
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/cache.rb187
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/descriptions.rb156
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/display.rb340
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/driver.rb828
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/formatter.rb654
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/paths.rb93
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/reader.rb106
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/util.rb79
-rw-r--r--vendor/gems/rdoc-2.4.3/lib/rdoc/ri/writer.rb68
9 files changed, 2511 insertions, 0 deletions
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/cache.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/cache.rb
new file mode 100644
index 000000000..15935abb1
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/cache.rb
@@ -0,0 +1,187 @@
+require 'rdoc/ri'
+
+class RDoc::RI::ClassEntry
+
+ attr_reader :name
+ attr_reader :path_names
+
+ def initialize(path_name, name, in_class)
+ @path_names = [ path_name ]
+ @name = name
+ @in_class = in_class
+ @class_methods = []
+ @instance_methods = []
+ @inferior_classes = []
+ end
+
+ # We found this class in more than one place, so add
+ # in the name from there.
+ def add_path(path)
+ @path_names << path
+ end
+
+ ##
+ # read in our methods and any classes and modules in our namespace. Methods
+ # are stored in files called name-c|i.yaml, where the 'name' portion is the
+ # external form of the method name and the c|i is a class|instance flag
+
+ def load_from(dir)
+ return unless File.exist? dir
+
+ Dir.foreach(dir) do |name|
+ next if name =~ /^\./
+
+ # convert from external to internal form, and
+ # extract the instance/class flag
+
+ if name =~ /^(.*?)-(c|i).yaml$/
+ external_name = $1
+ is_class_method = $2 == "c"
+ internal_name = RDoc::RI::Writer.external_to_internal(external_name)
+ list = is_class_method ? @class_methods : @instance_methods
+ path = File.join(dir, name)
+ list << RDoc::RI::MethodEntry.new(path, internal_name, is_class_method, self)
+ else
+ full_name = File.join(dir, name)
+ if File.directory?(full_name)
+ inf_class = @inferior_classes.find {|c| c.name == name }
+ if inf_class
+ inf_class.add_path(full_name)
+ else
+ inf_class = RDoc::RI::ClassEntry.new(full_name, name, self)
+ @inferior_classes << inf_class
+ end
+ inf_class.load_from(full_name)
+ end
+ end
+ end
+ end
+
+ # Return a list of any classes or modules that we contain
+ # that match a given string
+
+ def contained_modules_matching(name)
+ @inferior_classes.find_all {|c| c.name[name]}
+ end
+
+ def classes_and_modules
+ @inferior_classes
+ end
+
+ # Return an exact match to a particular name
+ def contained_class_named(name)
+ @inferior_classes.find {|c| c.name == name}
+ end
+
+ # return the list of local methods matching name
+ # We're split into two because we need distinct behavior
+ # when called from the _toplevel_
+ def methods_matching(name, is_class_method)
+ local_methods_matching(name, is_class_method)
+ end
+
+ # Find methods matching 'name' in ourselves and in
+ # any classes we contain
+ def recursively_find_methods_matching(name, is_class_method)
+ res = local_methods_matching(name, is_class_method)
+ @inferior_classes.each do |c|
+ res.concat(c.recursively_find_methods_matching(name, is_class_method))
+ end
+ res
+ end
+
+
+ # Return our full name
+ def full_name
+ res = @in_class.full_name
+ res << "::" unless res.empty?
+ res << @name
+ end
+
+ # Return a list of all out method names
+ def all_method_names
+ res = @class_methods.map {|m| m.full_name }
+ @instance_methods.each {|m| res << m.full_name}
+ res
+ end
+
+ private
+
+ # Return a list of all our methods matching a given string.
+ # Is +is_class_methods+ if 'nil', we don't care if the method
+ # is a class method or not, otherwise we only return
+ # those methods that match
+ def local_methods_matching(name, is_class_method)
+
+ list = case is_class_method
+ when nil then @class_methods + @instance_methods
+ when true then @class_methods
+ when false then @instance_methods
+ else fail "Unknown is_class_method: #{is_class_method.inspect}"
+ end
+
+ list.find_all {|m| m.name; m.name[name]}
+ end
+end
+
+##
+# A TopLevelEntry is like a class entry, but when asked to search for methods
+# searches all classes, not just itself
+
+class RDoc::RI::TopLevelEntry < RDoc::RI::ClassEntry
+ def methods_matching(name, is_class_method)
+ res = recursively_find_methods_matching(name, is_class_method)
+ end
+
+ def full_name
+ ""
+ end
+
+ def module_named(name)
+
+ end
+
+end
+
+class RDoc::RI::MethodEntry
+ attr_reader :name
+ attr_reader :path_name
+
+ def initialize(path_name, name, is_class_method, in_class)
+ @path_name = path_name
+ @name = name
+ @is_class_method = is_class_method
+ @in_class = in_class
+ end
+
+ def full_name
+ res = @in_class.full_name
+ unless res.empty?
+ if @is_class_method
+ res << "::"
+ else
+ res << "#"
+ end
+ end
+ res << @name
+ end
+end
+
+##
+# We represent everything known about all 'ri' files accessible to this program
+
+class RDoc::RI::Cache
+
+ attr_reader :toplevel
+
+ def initialize(dirs)
+ # At the top level we have a dummy module holding the
+ # overall namespace
+ @toplevel = RDoc::RI::TopLevelEntry.new('', '::', nil)
+
+ dirs.each do |dir|
+ @toplevel.load_from(dir)
+ end
+ end
+
+end
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/descriptions.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/descriptions.rb
new file mode 100644
index 000000000..99a7cb11f
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/descriptions.rb
@@ -0,0 +1,156 @@
+require 'yaml'
+require 'rdoc/markup/fragments'
+require 'rdoc/ri'
+
+##
+# Descriptions are created by RDoc (in ri_generator) and written out in
+# serialized form into the documentation tree. ri then reads these to generate
+# the documentation
+
+class RDoc::RI::NamedThing
+ attr_reader :name
+ def initialize(name)
+ @name = name
+ end
+
+ def <=>(other)
+ @name <=> other.name
+ end
+
+ def hash
+ @name.hash
+ end
+
+ def eql?(other)
+ @name.eql?(other)
+ end
+end
+
+class RDoc::RI::AliasName < RDoc::RI::NamedThing; end
+
+class RDoc::RI::Attribute < RDoc::RI::NamedThing
+ attr_reader :rw, :comment
+
+ def initialize(name, rw, comment)
+ super(name)
+ @rw = rw
+ @comment = comment
+ end
+end
+
+class RDoc::RI::Constant < RDoc::RI::NamedThing
+ attr_reader :value, :comment
+
+ def initialize(name, value, comment)
+ super(name)
+ @value = value
+ @comment = comment
+ end
+end
+
+class RDoc::RI::IncludedModule < RDoc::RI::NamedThing; end
+
+class RDoc::RI::MethodSummary < RDoc::RI::NamedThing
+ def initialize(name="")
+ super
+ end
+end
+
+class RDoc::RI::Description
+ attr_accessor :name
+ attr_accessor :full_name
+ attr_accessor :comment
+
+ def serialize
+ self.to_yaml
+ end
+
+ def self.deserialize(from)
+ YAML.load(from)
+ end
+
+ def <=>(other)
+ @name <=> other.name
+ end
+end
+
+class RDoc::RI::ModuleDescription < RDoc::RI::Description
+
+ attr_accessor :class_methods
+ attr_accessor :class_method_extensions
+ attr_accessor :instance_methods
+ attr_accessor :instance_method_extensions
+ attr_accessor :attributes
+ attr_accessor :constants
+ attr_accessor :includes
+
+ # merge in another class description into this one
+ def merge_in(old)
+ merge(@class_methods, old.class_methods)
+ merge(@instance_methods, old.instance_methods)
+ merge(@attributes, old.attributes)
+ merge(@constants, old.constants)
+ merge(@includes, old.includes)
+ if @comment.nil? || @comment.empty?
+ @comment = old.comment
+ else
+ unless old.comment.nil? or old.comment.empty? then
+ if @comment.nil? or @comment.empty? then
+ @comment = old.comment
+ else
+ @comment << RDoc::Markup::Flow::RULE.new
+ @comment.concat old.comment
+ end
+ end
+ end
+ end
+
+ def display_name
+ "Module"
+ end
+
+ # the 'ClassDescription' subclass overrides this
+ # to format up the name of a parent
+ def superclass_string
+ nil
+ end
+
+ private
+
+ def merge(into, from)
+ names = {}
+ into.each {|i| names[i.name] = i }
+ from.each {|i| names[i.name] = i }
+ into.replace(names.keys.sort.map {|n| names[n]})
+ end
+end
+
+class RDoc::RI::ClassDescription < RDoc::RI::ModuleDescription
+ attr_accessor :superclass
+
+ def display_name
+ "Class"
+ end
+
+ def superclass_string
+ if @superclass && @superclass != "Object"
+ @superclass
+ else
+ nil
+ end
+ end
+end
+
+class RDoc::RI::MethodDescription < RDoc::RI::Description
+
+ attr_accessor :is_class_method
+ attr_accessor :visibility
+ attr_accessor :block_params
+ attr_accessor :is_singleton
+ attr_accessor :aliases
+ attr_accessor :is_alias_for
+ attr_accessor :params
+ attr_accessor :source_path
+
+end
+
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/display.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/display.rb
new file mode 100644
index 000000000..173995943
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/display.rb
@@ -0,0 +1,340 @@
+require 'rdoc/ri'
+
+##
+# This is a kind of 'flag' module. If you want to write your own 'ri' display
+# module (perhaps because you're writing an IDE), you write a class which
+# implements the various 'display' methods in RDoc::RI::DefaultDisplay, and
+# include the RDoc::RI::Display module in that class.
+#
+# To access your class from the command line, you can do
+#
+# ruby -r <your source file> ../ri ....
+
+module RDoc::RI::Display
+
+ @@display_class = nil
+
+ def self.append_features(display_class)
+ @@display_class = display_class
+ end
+
+ def self.new(*args)
+ @@display_class.new(*args)
+ end
+
+end
+
+##
+# A paging display module. Uses the RDoc::RI::Formatter class to do the actual
+# presentation.
+
+class RDoc::RI::DefaultDisplay
+
+ include RDoc::RI::Display
+
+ attr_reader :formatter
+
+ def initialize(formatter, width, use_stdout, output = $stdout)
+ @use_stdout = use_stdout
+ @formatter = formatter.new output, width, " "
+ end
+
+ ##
+ # Display information about +klass+. Fetches additional information from
+ # +ri_reader+ as necessary.
+
+ def display_class_info(klass)
+ page do
+ superclass = klass.superclass
+
+ if superclass
+ superclass = " < " + superclass
+ else
+ superclass = ""
+ end
+
+ @formatter.draw_line(klass.display_name + ": " +
+ klass.full_name + superclass)
+
+ display_flow(klass.comment)
+ @formatter.draw_line
+
+ unless klass.includes.empty?
+ @formatter.blankline
+ @formatter.display_heading("Includes:", 2, "")
+ incs = []
+
+ klass.includes.each do |inc|
+ incs << inc.name
+ end
+
+ @formatter.wrap(incs.sort.join(', '))
+ end
+
+ unless klass.constants.empty?
+ @formatter.blankline
+ @formatter.display_heading("Constants:", 2, "")
+
+ constants = klass.constants.sort_by { |constant| constant.name }
+
+ constants.each do |constant|
+ @formatter.wrap "#{constant.name} = #{constant.value}"
+ if constant.comment then
+ @formatter.indent do
+ @formatter.display_flow constant.comment
+ end
+ else
+ @formatter.break_to_newline
+ end
+ end
+ end
+
+ unless klass.attributes.empty? then
+ @formatter.blankline
+ @formatter.display_heading 'Attributes:', 2, ''
+
+ attributes = klass.attributes.sort_by { |attribute| attribute.name }
+
+ attributes.each do |attribute|
+ if attribute.comment then
+ @formatter.wrap "#{attribute.name} (#{attribute.rw}):"
+ @formatter.indent do
+ @formatter.display_flow attribute.comment
+ end
+ else
+ @formatter.wrap "#{attribute.name} (#{attribute.rw})"
+ @formatter.break_to_newline
+ end
+ end
+ end
+
+ return display_class_method_list(klass)
+ end
+ end
+
+ ##
+ # Given a Hash mapping a class' methods to method types (returned by
+ # display_class_method_list), this method allows the user to choose one of
+ # the methods.
+
+ def get_class_method_choice(method_map)
+ end
+
+ ##
+ # Display methods on +klass+. Returns a hash mapping method name to method
+ # contents
+
+ def display_class_method_list(klass)
+ method_map = {}
+
+ class_data = [
+ :class_methods,
+ :class_method_extensions,
+ :instance_methods,
+ :instance_method_extensions,
+ ]
+
+ class_data.each do |data_type|
+ data = klass.send data_type
+
+ unless data.nil? or data.empty? then
+ @formatter.blankline
+
+ heading = data_type.to_s.split('_').join(' ').capitalize << ':'
+ @formatter.display_heading heading, 2, ''
+
+ method_names = []
+ data.each do |item|
+ method_names << item.name
+
+ if(data_type == :class_methods ||
+ data_type == :class_method_extensions) then
+ method_map["::#{item.name}"] = :class
+ method_map[item.name] = :class
+ else
+ #
+ # Since we iterate over instance methods after class methods,
+ # an instance method always will overwrite the unqualified
+ # class method entry for a class method of the same name.
+ #
+ method_map["##{item.name}"] = :instance
+ method_map[item.name] = :instance
+ end
+ end
+ method_names.sort!
+
+ @formatter.wrap method_names.join(', ')
+ end
+ end
+
+ method_map
+ end
+ private :display_class_method_list
+
+ ##
+ # Display an Array of RDoc::Markup::Flow objects, +flow+.
+
+ def display_flow(flow)
+ if flow and not flow.empty? then
+ @formatter.display_flow flow
+ else
+ @formatter.wrap '[no description]'
+ end
+ end
+
+ ##
+ # Display information about +method+.
+
+ def display_method_info(method)
+ page do
+ @formatter.draw_line(method.full_name)
+ display_params(method)
+
+ @formatter.draw_line
+ display_flow(method.comment)
+
+ if method.aliases and not method.aliases.empty? then
+ @formatter.blankline
+ aka = "(also known as #{method.aliases.map { |a| a.name }.join(', ')})"
+ @formatter.wrap aka
+ end
+ end
+ end
+
+ ##
+ # Display the list of +methods+.
+
+ def display_method_list(methods)
+ page do
+ @formatter.wrap "More than one method matched your request. You can refine your search by asking for information on one of:"
+ @formatter.blankline
+
+ methods.each do |method|
+ @formatter.raw_print_line "#{method.full_name} [#{method.source_path}]\n"
+ end
+ end
+ end
+
+ ##
+ # Display a list of +methods+ and allow the user to select one of them.
+
+ def display_method_list_choice(methods)
+ page do
+ @formatter.wrap "More than one method matched your request. Please choose one of the possible matches."
+ @formatter.blankline
+
+ methods.each_with_index do |method, index|
+ @formatter.raw_print_line "%3d %s [%s]\n" % [index + 1, method.full_name, method.source_path]
+ end
+
+ @formatter.raw_print_line ">> "
+
+ choice = $stdin.gets.strip!
+
+ if(choice == '')
+ return
+ end
+
+ choice = choice.to_i
+
+ if ((choice == 0) || (choice > methods.size)) then
+ @formatter.raw_print_line "Invalid choice!\n"
+ else
+ method = methods[choice - 1]
+ display_method_info(method)
+ end
+ end
+ end
+
+ ##
+ # Display the params for +method+.
+
+ def display_params(method)
+ params = method.params
+
+ if params[0,1] == "(" then
+ if method.is_singleton
+ params = method.full_name + params
+ else
+ params = method.name + params
+ end
+ end
+
+ params.split(/\n/).each do |param|
+ @formatter.wrap param
+ @formatter.break_to_newline
+ end
+
+ @formatter.blankline
+ @formatter.wrap("From #{method.source_path}")
+ end
+
+ ##
+ # List the classes in +classes+.
+
+ def list_known_classes(classes)
+ if classes.empty? then
+ warn_no_database
+ else
+ page do
+ @formatter.draw_line "Known classes and modules"
+ @formatter.blankline
+
+ classes.sort.each do |klass|
+ @formatter.wrap klass
+ end
+ end
+ end
+ end
+
+ ##
+ # Paginates output through a pager program.
+
+ def page
+ if pager = setup_pager then
+ begin
+ orig_output = @formatter.output
+ @formatter.output = pager
+ yield
+ ensure
+ @formatter.output = orig_output
+ pager.close
+ end
+ else
+ yield
+ end
+ rescue Errno::EPIPE
+ end
+
+ ##
+ # Sets up a pager program to pass output through.
+
+ def setup_pager
+ unless @use_stdout then
+ for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
+ return IO.popen(pager, "w") rescue nil
+ end
+ @use_stdout = true
+ nil
+ end
+ end
+
+ ##
+ # Displays a message that describes how to build RI data.
+
+ def warn_no_database
+ output = @formatter.output
+
+ output.puts "No ri data found"
+ output.puts
+ output.puts "If you've installed Ruby yourself, you need to generate documentation using:"
+ output.puts
+ output.puts " make install-doc"
+ output.puts
+ output.puts "from the same place you ran `make` to build ruby."
+ output.puts
+ output.puts "If you installed Ruby from a packaging system, then you may need to"
+ output.puts "install an additional package, or ask the packager to enable ri generation."
+ end
+
+end
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/driver.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/driver.rb
new file mode 100644
index 000000000..310ff8487
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/driver.rb
@@ -0,0 +1,828 @@
+require 'abbrev'
+require 'optparse'
+require 'yaml'
+
+begin
+ require 'readline'
+rescue LoadError
+end
+
+require 'rdoc/ri'
+require 'rdoc/ri/paths'
+require 'rdoc/ri/formatter'
+require 'rdoc/ri/display'
+require 'fileutils'
+require 'rdoc/markup'
+require 'rdoc/markup/to_flow'
+
+class RDoc::RI::Driver
+
+ ##
+ # This class offers both Hash and OpenStruct functionality. We convert from
+ # the Core Hash to this before calling any of the display methods, in order
+ # to give the display methods a cleaner API for accessing the data.
+
+ class OpenStructHash < Hash
+
+ ##
+ # This method converts from a Hash to an OpenStructHash.
+
+ def self.convert(object)
+ case object
+ when Hash then
+ new_hash = new # Convert Hash -> OpenStructHash
+
+ object.each do |key, value|
+ new_hash[key] = convert value
+ end
+
+ new_hash
+ when Array then
+ object.map do |element|
+ convert element
+ end
+ else
+ object
+ end
+ end
+
+ def merge_enums(other)
+ other.each do |k, v|
+ if self[k] then
+ case v
+ when Array then
+ # HACK dunno
+ if String === self[k] and self[k].empty? then
+ self[k] = v
+ else
+ self[k] += v
+ end
+ when Hash then
+ self[k].update v
+ else
+ # do nothing
+ end
+ else
+ self[k] = v
+ end
+ end
+ end
+
+ def method_missing method, *args
+ self[method.to_s]
+ end
+ end
+
+ class Error < RDoc::RI::Error; end
+
+ class NotFoundError < Error
+ def message
+ "Nothing known about #{super}"
+ end
+ end
+
+ attr_accessor :homepath # :nodoc:
+
+ ##
+ # Default options for ri
+
+ def self.default_options
+ options = {}
+ options[:use_stdout] = !$stdout.tty?
+ options[:width] = 72
+ options[:formatter] = RDoc::RI::Formatter.for 'plain'
+ options[:interactive] = false
+ options[:use_cache] = true
+
+ # 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
+
+ ##
+ # Parses +argv+ and returns a Hash of options
+
+ def self.process_args(argv)
+ options = default_options
+
+ opts = OptionParser.new do |opt|
+ opt.program_name = File.basename $0
+ opt.version = RDoc::VERSION
+ opt.release = nil
+ opt.summary_indent = ' ' * 4
+
+ directories = [
+ RDoc::RI::Paths::SYSDIR,
+ RDoc::RI::Paths::SITEDIR,
+ RDoc::RI::Paths::HOMEDIR
+ ]
+
+ if RDoc::RI::Paths::GEMDIRS then
+ Gem.path.each do |dir|
+ directories << "#{dir}/doc/*/ri"
+ end
+ end
+
+ 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.
+
+The form '.' method 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 may be required for method names containing
+punctuation:
+
+ #{opt.program_name} 'Array.[]'
+ #{opt.program_name} compact\\!
+
+By default ri searches for documentation in the following directories:
+
+ #{directories.join "\n "}
+
+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
+
+ opt.on("--fmt=FORMAT", "--format=FORMAT", "-f",
+ RDoc::RI::Formatter::FORMATTERS.keys,
+ "Format to use when displaying output:",
+ " #{RDoc::RI::Formatter.list}",
+ "Use 'bs' (backspace) with most pager",
+ "programs. To use ANSI, either disable the",
+ "pager or tell the pager to allow control",
+ "characters.") do |value|
+ options[:formatter] = RDoc::RI::Formatter.for value
+ 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-]use-cache",
+ "Whether or not to use ri's cache.",
+ "True by default.") do |value|
+ options[:use_cache] = value
+ end
+
+ opt.separator nil
+
+ opt.on("--no-standard-docs",
+ "Do not include documentation from",
+ "the Ruby standard library, site_lib,",
+ "installed gems, or ~/.rdoc.",
+ "Equivalent to specifying",
+ "the options --no-system, --no-site, --no-gems,",
+ "and --no-home") 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.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("--no-pager", "-T",
+ "Send output directly to stdout,",
+ "rather than to a pager.") do
+ options[:use_stdout] = true
+ end
+
+ opt.on("--interactive", "-i",
+ "This makes ri go into interactive mode.",
+ "When ri is in interactive mode it will",
+ "allow the user to disambiguate lists of",
+ "methods in case multiple methods match",
+ "against a method search string. It also",
+ "will allow the user to enter in a method",
+ "name (with auto-completion, if readline",
+ "is supported) when viewing a class.") do
+ options[:interactive] = true
+ end
+
+ opt.separator nil
+
+ opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger,
+ "Set the width of the output.") do |value|
+ options[:width] = value
+ end
+ end
+
+ argv = ENV['RI'].to_s.split.concat argv
+
+ opts.parse! argv
+
+ options[:names] = argv
+
+ options[:formatter] ||= RDoc::RI::Formatter.for('plain')
+ 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
+ ri = new options
+ ri.run
+ end
+
+ def initialize(initial_options={})
+ options = self.class.default_options.update(initial_options)
+
+ @names = options[:names]
+ @class_cache_name = 'classes'
+
+ @doc_dirs = RDoc::RI::Paths.path(options[:use_system],
+ options[:use_site],
+ options[:use_home],
+ options[:use_gems],
+ options[:extra_doc_dirs])
+
+ @homepath = RDoc::RI::Paths.raw_path(false, false, true, false).first
+ @homepath = @homepath.sub(/\.rdoc/, '.ri')
+ @sys_dir = RDoc::RI::Paths.raw_path(true, false, false, false).first
+ @list_doc_dirs = options[:list_doc_dirs]
+
+ FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path
+ @cache_doc_dirs_path = File.join cache_file_path, ".doc_dirs"
+
+ @use_cache = options[:use_cache]
+ @class_cache = nil
+
+ @interactive = options[:interactive]
+ @display = RDoc::RI::DefaultDisplay.new(options[:formatter],
+ options[:width],
+ options[:use_stdout])
+ end
+
+ ##
+ # Cache of classes ri knows about
+
+ def class_cache
+ return @class_cache if @class_cache
+
+ # Get the documentation directories used to make the cache in order to see
+ # whether the cache is valid for the current ri instantiation.
+ if(File.readable?(@cache_doc_dirs_path))
+ cache_doc_dirs = IO.read(@cache_doc_dirs_path).split("\n")
+ else
+ cache_doc_dirs = []
+ end
+
+ newest = map_dirs('created.rid') do |f|
+ File.mtime f if test ?f, f
+ end.max
+
+ # An up to date cache file must have been created more recently than
+ # the last modification of any of the documentation directories. It also
+ # must have been created with the same documentation directories
+ # as those from which ri currently is sourcing documentation.
+ up_to_date = (File.exist?(class_cache_file_path) and
+ newest and newest < File.mtime(class_cache_file_path) and
+ (cache_doc_dirs == @doc_dirs))
+
+ if up_to_date and @use_cache then
+ open class_cache_file_path, 'rb' do |fp|
+ begin
+ @class_cache = Marshal.load fp.read
+ rescue
+ #
+ # This shouldn't be necessary, since the up_to_date logic above
+ # should force the cache to be recreated when a new version of
+ # rdoc is installed. This seems like a worthwhile enhancement
+ # to ri's robustness, however.
+ #
+ $stderr.puts "Error reading the class cache; recreating the class cache!"
+ @class_cache = create_class_cache
+ end
+ end
+ else
+ @class_cache = create_class_cache
+ end
+
+ @class_cache
+ end
+
+ ##
+ # Creates the class cache if it is empty
+
+ def create_class_cache
+ class_cache = OpenStructHash.new
+
+ if(@use_cache)
+ # Dump the documentation directories to a file in the cache, so that
+ # we only will use the cache for future instantiations with identical
+ # documentation directories.
+ File.open @cache_doc_dirs_path, "wb" do |fp|
+ fp << @doc_dirs.join("\n")
+ end
+ end
+
+ classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] }
+ warn "Updating ri class cache with #{classes.size} classes..."
+ populate_class_cache class_cache, classes
+
+ write_cache class_cache, class_cache_file_path
+
+ class_cache
+ end
+
+ ##
+ # Populates +class_cache+ with +classes+, adding +extension+ data for found
+ # methods when asked
+
+ def populate_class_cache(class_cache, classes, extension = false)
+ classes.each do |cdesc|
+ desc = read_yaml cdesc
+ klassname = desc["full_name"]
+
+ unless class_cache.has_key? klassname then
+ desc["display_name"] = "Class"
+ desc["sources"] = [cdesc]
+ desc["instance_method_extensions"] = []
+ desc["class_method_extensions"] = []
+ class_cache[klassname] = desc
+ else
+ klass = class_cache[klassname]
+
+ if extension then
+ desc["instance_method_extensions"] = desc.delete "instance_methods"
+ desc["class_method_extensions"] = desc.delete "class_methods"
+ end
+
+ klass.merge_enums desc
+ klass["sources"] << cdesc
+ end
+ end
+ end
+
+ ##
+ # Path to the class_cache
+
+ def class_cache_file_path
+ File.join cache_file_path, @class_cache_name
+ end
+
+ ##
+ # Path to the cache file for +klassname+
+
+ def cache_file_for(klassname)
+ File.join cache_file_path, klassname.gsub(/:+/, "-")
+ end
+
+ ##
+ # Directory where cache files live
+
+ def cache_file_path
+ File.join @homepath, 'cache'
+ end
+
+ ##
+ # Displays the module, class or method +name+. For methods, locates the
+ # method in the ancestors list if it isn't in the named module.
+
+ def display_name(name)
+ if class_cache.key? name then
+ method_map = display_class name
+ elsif name =~ /::|\#|\./ then
+ method = nil
+ klass, = parse_name name
+
+ klass = expand_klass klass unless class_cache.key? klass
+
+ orig_klass = klass
+ orig_name = name
+
+ loop do
+ method = lookup_method name, klass
+
+ break if method
+
+ ancestor = lookup_ancestor klass, orig_klass
+
+ break unless ancestor
+
+ name = name.sub klass, ancestor
+ klass = ancestor
+ end
+
+ raise NotFoundError, orig_name unless method
+
+ display_method method
+ else
+ methods = select_methods(/#{name}/)
+
+ if methods.size == 0
+ raise NotFoundError, name
+ elsif methods.size == 1
+ display_method methods[0]
+ else
+ @display.display_method_list methods
+ end
+ end
+ end
+
+ ##
+ # Displays info for class or module +name+
+
+ def display_class(name)
+ klass = class_cache[name]
+ @display.display_class_info klass
+ end
+
+ ##
+ # Displays info for method +method+
+
+ def display_method(method)
+ @display.display_method_info method
+ end
+
+ ##
+ # Runs ri interactively using Readline if it is available.
+
+ def interactive
+ formatter = @display.formatter
+
+ if defined? Readline then
+ # prepare abbreviations for tab completion
+ klasses = class_cache.keys
+
+ Readline.completion_proc = proc do |name|
+ case name
+ when /(#|\.|::)([^A-Z]|$)/ then
+ methods = []
+ method_type = $1 == '.' ? '#|::' : $1
+
+ klass, method = if $2.empty? then
+ [$`, '']
+ else
+ parse_name name
+ end
+
+ cache = load_cache_for klass
+
+ methods += cache.keys.select do |method_name|
+ method_name =~ /^#{klass}#{method_type}#{method}/
+ end
+
+ # TODO ancestor lookup
+
+ if method_type == '::' and method.empty? then
+ methods += klasses.grep(/^#{klass}::/)
+ end
+
+ methods
+ when /^[A-Z]\w*/ then
+ klasses.grep(/^#{name}/)
+ else
+ []
+ end
+ end
+ end
+
+ formatter.raw_print_line "\nEnter the method name you want to look up.\n"
+
+ if defined? Readline then
+ formatter.raw_print_line "You can use tab to autocomplete.\n"
+ end
+
+ formatter.raw_print_line "Enter a blank line to exit.\n\n"
+
+ loop do
+ name = if defined? Readline then
+ Readline.readline ">> "
+ else
+ formatter.raw_print_line ">> "
+ $stdin.gets
+ end
+
+ return if name.nil? or name.empty?
+
+ name = name.strip
+
+ begin
+ display_name name
+ rescue NotFoundError => e
+ formatter.raw_print_line "#{e.message}\n"
+ end
+ end
+
+ rescue Interrupt
+ exit
+ end
+
+ ##
+ # Expands abbreviated klass +klass+ into a fully-qualified klass. "Zl::Da"
+ # will be expanded to Zlib::DataError.
+
+ def expand_klass(klass)
+ klass.split('::').inject '' do |expanded, klass_part|
+ expanded << '::' unless expanded.empty?
+ short = expanded << klass_part
+
+ subset = class_cache.keys.select do |klass_name|
+ klass =~ /^#{expanded}[^:]*$/
+ end
+
+ abbrevs = Abbrev.abbrev subset
+
+ expanded = abbrevs[short]
+
+ raise NotFoundError, short unless expanded
+
+ expanded.dup
+ end
+ end
+
+ ##
+ # Loads the cache for +klassname+
+
+ def load_cache_for(klassname)
+ path = cache_file_for klassname
+
+ cache = nil
+
+ if File.exist? path and
+ File.mtime(path) >= File.mtime(class_cache_file_path) and
+ @use_cache then
+ open path, 'rb' do |fp|
+ begin
+ cache = Marshal.load fp.read
+ rescue
+ #
+ # The cache somehow is bad. Recreate the cache.
+ #
+ $stderr.puts "Error reading the cache for #{klassname}; recreating the cache!"
+ cache = create_cache_for klassname, path
+ end
+ end
+ else
+ cache = create_cache_for klassname, path
+ end
+
+ cache
+ end
+
+ ##
+ # Writes a cache file for +klassname+ to +path+
+
+ def create_cache_for(klassname, path)
+ klass = class_cache[klassname]
+ return nil unless klass
+
+ method_files = klass["sources"]
+ cache = OpenStructHash.new
+
+ method_files.each do |f|
+ system_file = f.index(@sys_dir) == 0
+ Dir[File.join(File.dirname(f), "*")].each do |yaml|
+ next unless yaml =~ /yaml$/
+ next if yaml =~ /cdesc-[^\/]+yaml$/
+
+ method = read_yaml yaml
+
+ if system_file then
+ method["source_path"] = "Ruby #{RDoc::RI::Paths::VERSION}"
+ else
+ gem = Gem.path.any? do |gem_path|
+ pattern = File.join Regexp.escape(gem_path), 'doc', '(.*?)', ''
+
+ f =~ /^#{pattern}/
+ end
+
+ method["source_path"] = if gem then
+ "gem #{$1}"
+ else
+ f
+ end
+ end
+
+ name = method["full_name"]
+ cache[name] = method
+ end
+ end
+
+ write_cache cache, path
+ end
+
+ ##
+ # Finds the next ancestor of +orig_klass+ after +klass+.
+
+ def lookup_ancestor(klass, orig_klass)
+ # This is a bit hacky, but ri will go into an infinite loop otherwise,
+ # since Object has an Object ancestor for some reason. Depending on the
+ # documentation state, I've seen Kernel as an ancestor of Object and not
+ # as an ancestor of Object.
+ if orig_klass == "Object" && (klass == "Kernel" || klass == "Object") then
+ return nil
+ end
+
+ cache = class_cache[orig_klass]
+
+ return nil unless cache
+
+ ancestors = [orig_klass]
+ ancestors.push(*cache.includes.map { |inc| inc['name'] })
+ ancestors << cache.superclass
+
+ ancestor_index = ancestors.index klass
+
+ if ancestor_index
+ ancestor = ancestors[ancestors.index(klass) + 1]
+ return ancestor if ancestor
+ end
+
+ lookup_ancestor klass, cache.superclass
+ end
+
+ ##
+ # Finds the method
+
+ def lookup_method(name, klass)
+ cache = load_cache_for klass
+ return nil unless cache
+
+ method = cache[name.gsub('.', '#')]
+ method = cache[name.gsub('.', '::')] unless method
+ method
+ end
+
+ def map_dirs(file_name)
+ @doc_dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact
+ end
+
+ ##
+ # Extract the class and method name parts from +name+ like Foo::Bar#baz
+
+ def parse_name(name)
+ parts = name.split(/(::|\#|\.)/)
+
+ if parts[-2] != '::' or parts.last !~ /^[A-Z]/ then
+ meth = parts.pop
+ parts.pop
+ end
+
+ klass = parts.join
+
+ [klass, meth]
+ end
+
+ ##
+ # Reads ri YAML data from +path+, converting RDoc 1.x classes to RDoc 2.x
+ # classes
+
+ def read_yaml(path)
+ data = File.read path
+
+ # Necessary to be backward-compatible with documentation generated
+ # by earliar RDoc versions.
+ data = data.gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '')
+ data = data.gsub(/ \!ruby\/(object|struct):SM::(\S+)/,
+ ' !ruby/\1:RDoc::Markup::\2')
+
+ OpenStructHash.convert YAML.load(data)
+ end
+
+ ##
+ # Looks up and displays ri data according to the options given.
+
+ def run
+ if @list_doc_dirs then
+ puts @doc_dirs
+ elsif @interactive then
+ interactive
+ elsif @names.empty? then
+ @display.list_known_classes class_cache.keys.sort
+ else
+ @names.each do |name|
+ display_name name
+ end
+ end
+ rescue NotFoundError => e
+ abort e.message
+ end
+
+ ##
+ # Selects methods matching +pattern+ from all modules
+
+ def select_methods(pattern)
+ methods = []
+ class_cache.keys.sort.each do |klass|
+ class_cache[klass]["instance_methods"].map{|h|h["name"]}.grep(pattern) do |name|
+ method = load_cache_for(klass)[klass+'#'+name]
+ methods << method if method
+ end
+ class_cache[klass]["class_methods"].map{|h|h["name"]}.grep(pattern) do |name|
+ method = load_cache_for(klass)[klass+'::'+name]
+ methods << method if method
+ end
+ end
+ methods
+ end
+
+ ##
+ # Writes +cache+ to +path+
+
+ def write_cache(cache, path)
+ if @use_cache then
+ File.open path, "wb" do |cache_file|
+ Marshal.dump cache, cache_file
+ end
+ end
+
+ cache
+ rescue Errno::EISDIR # HACK toplevel, replace with main
+ cache
+ end
+
+end
+
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/formatter.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/formatter.rb
new file mode 100644
index 000000000..b2c9d07b3
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/formatter.rb
@@ -0,0 +1,654 @@
+require 'rdoc/ri'
+require 'rdoc/markup'
+
+class RDoc::RI::Formatter
+
+ attr_writer :indent
+ attr_accessor :output
+
+ FORMATTERS = { }
+
+ def self.for(name)
+ FORMATTERS[name.downcase]
+ end
+
+ def self.list
+ FORMATTERS.keys.sort.join ", "
+ end
+
+ def initialize(output, width, indent)
+ @output = output
+ @width = width
+ @indent = indent
+ @original_indent = indent.dup
+ end
+
+ def draw_line(label=nil)
+ len = @width
+ len -= (label.size + 1) if label
+
+ if len > 0 then
+ @output.print '-' * len
+ if label
+ @output.print ' '
+ bold_print label
+ end
+
+ @output.puts
+ else
+ @output.print '-' * @width
+ @output.puts
+
+ @output.puts label
+ end
+ end
+
+ def indent
+ return @indent unless block_given?
+
+ begin
+ indent = @indent.dup
+ @indent += @original_indent
+ yield
+ ensure
+ @indent = indent
+ end
+ end
+
+ def wrap(txt, prefix=@indent, linelen=@width)
+ return unless txt && !txt.empty?
+
+ work = conv_markup(txt)
+ textLen = linelen - prefix.length
+ patt = Regexp.new("^(.{0,#{textLen}})[ \n]")
+ next_prefix = prefix.tr("^ ", " ")
+
+ res = []
+
+ while work.length > textLen
+ if work =~ patt
+ res << $1
+ work.slice!(0, $&.length)
+ else
+ res << work.slice!(0, textLen)
+ end
+ end
+ res << work if work.length.nonzero?
+ @output.puts(prefix + res.join("\n" + next_prefix))
+ end
+
+ def blankline
+ @output.puts
+ end
+
+ ##
+ # Called when we want to ensure a new 'wrap' starts on a newline. Only
+ # needed for HtmlFormatter, because the rest do their own line breaking.
+
+ def break_to_newline
+ end
+
+ def bold_print(txt)
+ @output.print txt
+ end
+
+ def raw_print_line(txt)
+ @output.print txt
+ end
+
+ ##
+ # Convert HTML entities back to ASCII
+
+ def conv_html(txt)
+ txt = txt.gsub(/&gt;/, '>')
+ txt.gsub!(/&lt;/, '<')
+ txt.gsub!(/&quot;/, '"')
+ txt.gsub!(/&amp;/, '&')
+ txt
+ end
+
+ ##
+ # Convert markup into display form
+
+ def conv_markup(txt)
+ txt = txt.gsub(%r{<tt>(.*?)</tt>}, '+\1+')
+ txt.gsub!(%r{<code>(.*?)</code>}, '+\1+')
+ txt.gsub!(%r{<b>(.*?)</b>}, '*\1*')
+ txt.gsub!(%r{<em>(.*?)</em>}, '_\1_')
+ txt
+ end
+
+ def display_list(list)
+ case list.type
+ when :BULLET
+ prefixer = proc { |ignored| @indent + "* " }
+
+ when :NUMBER, :UPPERALPHA, :LOWERALPHA then
+ start = case list.type
+ when :NUMBER then 1
+ when :UPPERALPHA then 'A'
+ when :LOWERALPHA then 'a'
+ end
+
+ prefixer = proc do |ignored|
+ res = @indent + "#{start}.".ljust(4)
+ start = start.succ
+ res
+ end
+
+ when :LABELED, :NOTE then
+ longest = 0
+
+ list.contents.each do |item|
+ if RDoc::Markup::Flow::LI === item and item.label.length > longest then
+ longest = item.label.length
+ end
+ end
+
+ longest += 1
+
+ prefixer = proc { |li| @indent + li.label.ljust(longest) }
+
+ else
+ raise ArgumentError, "unknown list type #{list.type}"
+ end
+
+ list.contents.each do |item|
+ if RDoc::Markup::Flow::LI === item then
+ prefix = prefixer.call item
+ display_flow_item item, prefix
+ else
+ display_flow_item item
+ end
+ end
+ end
+
+ def display_flow_item(item, prefix = @indent)
+ case item
+ when RDoc::Markup::Flow::P, RDoc::Markup::Flow::LI
+ wrap(conv_html(item.body), prefix)
+ blankline
+
+ when RDoc::Markup::Flow::LIST
+ display_list(item)
+
+ when RDoc::Markup::Flow::VERB
+ display_verbatim_flow_item(item, @indent)
+
+ when RDoc::Markup::Flow::H
+ display_heading(conv_html(item.text), item.level, @indent)
+
+ when RDoc::Markup::Flow::RULE
+ draw_line
+
+ else
+ raise RDoc::Error, "Unknown flow element: #{item.class}"
+ end
+ end
+
+ def display_verbatim_flow_item(item, prefix=@indent)
+ item.body.split(/\n/).each do |line|
+ @output.print @indent, conv_html(line), "\n"
+ end
+ blankline
+ end
+
+ def display_heading(text, level, indent)
+ text = strip_attributes text
+
+ case level
+ when 1 then
+ ul = "=" * text.length
+ @output.puts
+ @output.puts text.upcase
+ @output.puts ul
+
+ when 2 then
+ ul = "-" * text.length
+ @output.puts
+ @output.puts text
+ @output.puts ul
+ else
+ @output.print indent, text, "\n"
+ end
+
+ @output.puts
+ end
+
+ def display_flow(flow)
+ flow.each do |f|
+ display_flow_item(f)
+ end
+ end
+
+ def strip_attributes(text)
+ text.gsub(/(<\/?(?:b|code|em|i|tt)>)/, '')
+ end
+
+end
+
+##
+# Handle text with attributes. We're a base class: there are different
+# presentation classes (one, for example, uses overstrikes to handle bold and
+# underlining, while another using ANSI escape sequences.
+
+class RDoc::RI::AttributeFormatter < RDoc::RI::Formatter
+
+ BOLD = 1
+ ITALIC = 2
+ CODE = 4
+
+ ATTR_MAP = {
+ "b" => BOLD,
+ "code" => CODE,
+ "em" => ITALIC,
+ "i" => ITALIC,
+ "tt" => CODE
+ }
+
+ AttrChar = Struct.new :char, :attr
+
+ class AttributeString
+ attr_reader :txt
+
+ def initialize
+ @txt = []
+ @optr = 0
+ end
+
+ def <<(char)
+ @txt << char
+ end
+
+ def empty?
+ @optr >= @txt.length
+ end
+
+ # accept non space, then all following spaces
+ def next_word
+ start = @optr
+ len = @txt.length
+
+ while @optr < len && @txt[@optr].char != " "
+ @optr += 1
+ end
+
+ while @optr < len && @txt[@optr].char == " "
+ @optr += 1
+ end
+
+ @txt[start...@optr]
+ end
+ end
+
+ ##
+ # Overrides base class. Looks for <tt>...</tt> etc sequences and generates
+ # an array of AttrChars. This array is then used as the basis for the
+ # split.
+
+ def wrap(txt, prefix=@indent, linelen=@width)
+ return unless txt && !txt.empty?
+
+ txt = add_attributes_to(txt)
+ next_prefix = prefix.tr("^ ", " ")
+ linelen -= prefix.size
+
+ line = []
+
+ until txt.empty?
+ word = txt.next_word
+ if word.size + line.size > linelen
+ write_attribute_text(prefix, line)
+ prefix = next_prefix
+ line = []
+ end
+ line.concat(word)
+ end
+
+ write_attribute_text(prefix, line) if line.length > 0
+ end
+
+ protected
+
+ def write_attribute_text(prefix, line)
+ @output.print prefix
+ line.each do |achar|
+ @output.print achar.char
+ end
+ @output.puts
+ end
+
+ def bold_print(txt)
+ @output.print txt
+ end
+
+ private
+
+ def add_attributes_to(txt)
+ tokens = txt.split(%r{(</?(?:b|code|em|i|tt)>)})
+ text = AttributeString.new
+ attributes = 0
+ tokens.each do |tok|
+ case tok
+ when %r{^</(\w+)>$} then attributes &= ~(ATTR_MAP[$1]||0)
+ when %r{^<(\w+)>$} then attributes |= (ATTR_MAP[$1]||0)
+ else
+ tok.split(//).each {|ch| text << AttrChar.new(ch, attributes)}
+ end
+ end
+ text
+ end
+
+end
+
+##
+# This formatter generates overstrike-style formatting, which works with
+# pagers such as man and less.
+
+class RDoc::RI::OverstrikeFormatter < RDoc::RI::AttributeFormatter
+
+ BS = "\C-h"
+
+ def write_attribute_text(prefix, line)
+ @output.print prefix
+
+ line.each do |achar|
+ attr = achar.attr
+ @output.print "_", BS if (attr & (ITALIC + CODE)) != 0
+ @output.print achar.char, BS if (attr & BOLD) != 0
+ @output.print achar.char
+ end
+
+ @output.puts
+ end
+
+ ##
+ # Draw a string in bold
+
+ def bold_print(text)
+ text.split(//).each do |ch|
+ @output.print ch, BS, ch
+ end
+ end
+
+end
+
+##
+# This formatter uses ANSI escape sequences to colorize stuff works with
+# pagers such as man and less.
+
+class RDoc::RI::AnsiFormatter < RDoc::RI::AttributeFormatter
+
+ def initialize(*args)
+ super
+ @output.print "\033[0m"
+ end
+
+ def write_attribute_text(prefix, line)
+ @output.print prefix
+ curr_attr = 0
+ line.each do |achar|
+ attr = achar.attr
+ if achar.attr != curr_attr
+ update_attributes(achar.attr)
+ curr_attr = achar.attr
+ end
+ @output.print achar.char
+ end
+ update_attributes(0) unless curr_attr.zero?
+ @output.puts
+ end
+
+ def bold_print(txt)
+ @output.print "\033[1m#{txt}\033[m"
+ end
+
+ HEADINGS = {
+ 1 => ["\033[1;32m", "\033[m"],
+ 2 => ["\033[4;32m", "\033[m"],
+ 3 => ["\033[32m", "\033[m"],
+ }
+
+ def display_heading(text, level, indent)
+ level = 3 if level > 3
+ heading = HEADINGS[level]
+ @output.print indent
+ @output.print heading[0]
+ @output.print strip_attributes(text)
+ @output.puts heading[1]
+ end
+
+ private
+
+ ATTR_MAP = {
+ BOLD => "1",
+ ITALIC => "33",
+ CODE => "36"
+ }
+
+ def update_attributes(attr)
+ str = "\033["
+ for quality in [ BOLD, ITALIC, CODE]
+ unless (attr & quality).zero?
+ str << ATTR_MAP[quality]
+ end
+ end
+ @output.print str, "m"
+ end
+
+end
+
+##
+# This formatter uses HTML.
+
+class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter
+
+ ##
+ # We depend on HTML4-conforming user agents to ignore an empty p element
+
+ def blankline
+ @output.puts '<p />'
+ end
+
+ ##
+ # Emboldens +text+
+
+ def bold_print(text)
+ tag("b") { text }
+ end
+
+ ##
+ # Outputs a forced line break element
+
+ def break_to_newline
+ @output.puts '<br />'
+ end
+
+ ##
+ # Outputs heading elements for +text+ with +level+ up to 4. Ignores
+ # +indent+.
+
+ def display_heading(text, level, indent)
+ level = 4 if level > 4
+ tag("h#{level}") { text }
+ @output.puts
+ end
+
+ ##
+ # Outputs +list+ which is displayed as follows:
+ #
+ # BULLET:: unordered list
+ # NUMBER:: ordered list
+ # LABELED:: definition list
+ # NOTE:: table
+
+ def display_list(list)
+ case list.type
+ when :BULLET then
+ list_type = "ul"
+ prefixer = proc { |ignored| '<li>' }
+ suffix = '</li>'
+
+ when :NUMBER, :UPPERALPHA, :LOWERALPHA then
+ list_type = "ol"
+ prefixer = proc { |ignored| '<li>' }
+ suffix = '</li>'
+
+ when :LABELED then
+ list_type = "dl"
+ prefixer = proc do |li|
+ "<dt><b>#{escape li.label}</b></dt><dd>"
+ end
+ suffix = '</dd>'
+
+ when :NOTE then
+ list_type = "table"
+ prefixer = proc do |li|
+ %{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
+ end
+ suffix = '</td></tr>'
+ else
+ fail "unknown list type"
+ end
+
+ @output.print "<#{list_type}>"
+
+ list.contents.each do |item|
+ if item.kind_of? RDoc::Markup::Flow::LI
+ prefix = prefixer.call item
+ @output.print prefix
+ display_flow_item item, prefix
+ @output.print suffix
+ else
+ display_flow_item item
+ end
+ end
+
+ @output.print "</#{list_type}>"
+ end
+
+ ##
+ # Outputs a preformatted section for +item+. +prefix+ is ignored.
+
+ def display_verbatim_flow_item(item, prefix=@indent)
+ @output.print '<pre>'
+
+ item.body.split(/\n/).each do |line|
+ @output.puts escape(line)
+ end
+
+ @output.puts '</pre>'
+ end
+
+ ##
+ # Outputs a horizontal rule element, optionally labeled above with +label+ in
+ # bold.
+
+ def draw_line(label = nil)
+ bold_print label if label
+
+ @output.puts "<hr />"
+ end
+
+ def write_attribute_text(prefix, line)
+ curr_attr = 0
+
+ line.each do |achar|
+ attr = achar.attr
+ if achar.attr != curr_attr then
+ update_attributes curr_attr, achar.attr
+ curr_attr = achar.attr
+ end
+ @output.print escape(achar.char)
+ end
+
+ update_attributes curr_attr, 0 unless curr_attr.zero?
+ end
+
+ private
+
+ ATTR_MAP = {
+ BOLD => "b>",
+ ITALIC => "i>",
+ CODE => "tt>"
+ }
+
+ def update_attributes(current, wanted)
+ str = ""
+ # first turn off unwanted ones
+ off = current & ~wanted
+ for quality in [ BOLD, ITALIC, CODE]
+ if (off & quality) > 0
+ str << "</" + ATTR_MAP[quality]
+ end
+ end
+
+ # now turn on wanted
+ for quality in [ BOLD, ITALIC, CODE]
+ unless (wanted & quality).zero?
+ str << "<" << ATTR_MAP[quality]
+ end
+ end
+ @output.print str
+ end
+
+ def tag(code)
+ @output.print("<#{code}>")
+ @output.print(yield)
+ @output.print("</#{code}>")
+ end
+
+ def escape(str)
+ str = str.gsub(/&/n, '&amp;')
+ str.gsub!(/\"/n, '&quot;')
+ str.gsub!(/>/n, '&gt;')
+ str.gsub!(/</n, '&lt;')
+ str
+ end
+
+end
+
+##
+# This formatter reduces extra lines for a simpler output. It improves way
+# output looks for tools like IRC bots.
+
+class RDoc::RI::SimpleFormatter < RDoc::RI::Formatter
+
+ ##
+ # No extra blank lines
+
+ def blankline
+ end
+
+ ##
+ # Display labels only, no lines
+
+ def draw_line(label=nil)
+ unless label.nil? then
+ bold_print(label)
+ @output.puts
+ end
+ end
+
+ ##
+ # Place heading level indicators inline with heading.
+
+ def display_heading(text, level, indent)
+ text = strip_attributes(text)
+ case level
+ when 1
+ @output.puts "= " + text.upcase
+ when 2
+ @output.puts "-- " + text
+ else
+ @output.print indent, text, "\n"
+ end
+ end
+
+end
+
+RDoc::RI::Formatter::FORMATTERS['plain'] = RDoc::RI::Formatter
+RDoc::RI::Formatter::FORMATTERS['simple'] = RDoc::RI::SimpleFormatter
+RDoc::RI::Formatter::FORMATTERS['bs'] = RDoc::RI::OverstrikeFormatter
+RDoc::RI::Formatter::FORMATTERS['ansi'] = RDoc::RI::AnsiFormatter
+RDoc::RI::Formatter::FORMATTERS['html'] = RDoc::RI::HtmlFormatter
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/paths.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/paths.rb
new file mode 100644
index 000000000..2f72b9dfd
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/paths.rb
@@ -0,0 +1,93 @@
+require 'rdoc/ri'
+
+##
+# Encapsulate all the strangeness to do with finding out where to find RDoc
+# files
+#
+# We basically deal with three directories:
+#
+# 1. The 'system' documentation directory, which holds the documentation
+# distributed with Ruby, and which is managed by the Ruby install process
+# 2. The 'site' directory, which contains site-wide documentation added
+# locally.
+# 3. The 'user' documentation directory, stored under the user's own home
+# directory.
+#
+# There's contention about all this, but for now:
+#
+# system:: $datadir/ri/<ver>/system/...
+# site:: $datadir/ri/<ver>/site/...
+# user:: ~/.rdoc
+
+module RDoc::RI::Paths
+
+ #:stopdoc:
+ require 'rbconfig'
+
+ DOC_DIR = "doc/rdoc"
+
+ VERSION = RbConfig::CONFIG['ruby_version']
+
+ base = File.join(RbConfig::CONFIG['datadir'], "ri", VERSION)
+ SYSDIR = File.join(base, "system")
+ SITEDIR = File.join(base, "site")
+ homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH']
+
+ if homedir then
+ HOMEDIR = File.join(homedir, ".rdoc")
+ else
+ HOMEDIR = nil
+ end
+
+ begin
+ require 'rubygems' unless defined?(Gem) and defined?(Gem::Enable) and
+ Gem::Enable
+
+ # HACK dup'd from Gem.latest_partials and friends
+ all_paths = []
+
+ all_paths = Gem.path.map do |dir|
+ Dir[File.join(dir, 'doc', '*', 'ri')]
+ end.flatten
+
+ ri_paths = {}
+
+ all_paths.each do |dir|
+ base = File.basename File.dirname(dir)
+ if base =~ /(.*)-((\d+\.)*\d+)/ then
+ name, version = $1, $2
+ ver = Gem::Version.new version
+ if ri_paths[name].nil? or ver > ri_paths[name][0] then
+ ri_paths[name] = [ver, dir]
+ end
+ end
+ end
+
+ GEMDIRS = ri_paths.map { |k,v| v.last }.sort
+ rescue LoadError
+ GEMDIRS = []
+ end
+
+ # Returns the selected documentation directories as an Array, or PATH if no
+ # overriding directories were given.
+
+ def self.path(use_system, use_site, use_home, use_gems, *extra_dirs)
+ path = raw_path(use_system, use_site, use_home, use_gems, *extra_dirs)
+ return path.select { |directory| File.directory? directory }
+ end
+
+ # Returns the selected documentation directories including nonexistent
+ # directories. Used to print out what paths were searched if no ri was
+ # found.
+
+ def self.raw_path(use_system, use_site, use_home, use_gems, *extra_dirs)
+ path = []
+ path << extra_dirs unless extra_dirs.empty?
+ path << SYSDIR if use_system
+ path << SITEDIR if use_site
+ path << HOMEDIR if use_home
+ path << GEMDIRS if use_gems
+
+ return path.flatten.compact
+ end
+end
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/reader.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/reader.rb
new file mode 100644
index 000000000..de3c8d9af
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/reader.rb
@@ -0,0 +1,106 @@
+require 'rdoc/ri'
+require 'rdoc/ri/descriptions'
+require 'rdoc/ri/writer'
+require 'rdoc/markup/to_flow'
+
+class RDoc::RI::Reader
+
+ def initialize(ri_cache)
+ @cache = ri_cache
+ end
+
+ def top_level_namespace
+ [ @cache.toplevel ]
+ end
+
+ def lookup_namespace_in(target, namespaces)
+ result = []
+ for n in namespaces
+ result.concat(n.contained_modules_matching(target))
+ end
+ result
+ end
+
+ def find_class_by_name(full_name)
+ names = full_name.split(/::/)
+ ns = @cache.toplevel
+ for name in names
+ ns = ns.contained_class_named(name)
+ return nil if ns.nil?
+ end
+ get_class(ns)
+ end
+
+ def find_methods(name, is_class_method, namespaces)
+ result = []
+ namespaces.each do |ns|
+ result.concat ns.methods_matching(name, is_class_method)
+ end
+ result
+ end
+
+ ##
+ # Return the MethodDescription for a given MethodEntry by deserializing the
+ # YAML
+
+ def get_method(method_entry)
+ path = method_entry.path_name
+ File.open(path) { |f| RDoc::RI::Description.deserialize(f) }
+ end
+
+ ##
+ # Return a class description
+
+ def get_class(class_entry)
+ result = nil
+ for path in class_entry.path_names
+ path = RDoc::RI::Writer.class_desc_path(path, class_entry)
+ desc = File.open(path) {|f| RDoc::RI::Description.deserialize(f) }
+ if result
+ result.merge_in(desc)
+ else
+ result = desc
+ end
+ end
+ result
+ end
+
+ ##
+ # Return the names of all classes and modules
+
+ def full_class_names
+ res = []
+ find_classes_in(res, @cache.toplevel)
+ end
+
+ ##
+ # Return a list of all classes, modules, and methods
+
+ def all_names
+ res = []
+ find_names_in(res, @cache.toplevel)
+ end
+
+ private
+
+ def find_classes_in(res, klass)
+ classes = klass.classes_and_modules
+ for c in classes
+ res << c.full_name
+ find_classes_in(res, c)
+ end
+ res
+ end
+
+ def find_names_in(res, klass)
+ classes = klass.classes_and_modules
+ for c in classes
+ res << c.full_name
+ res.concat c.all_method_names
+ find_names_in(res, c)
+ end
+ res
+ end
+
+end
+
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/util.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/util.rb
new file mode 100644
index 000000000..4e91eb978
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/util.rb
@@ -0,0 +1,79 @@
+require 'rdoc/ri'
+
+##
+# Break argument into its constituent class or module names, an
+# optional method type, and a method name
+
+class RDoc::RI::NameDescriptor
+
+ attr_reader :class_names
+ attr_reader :method_name
+
+ ##
+ # true and false have the obvious meaning. nil means we don't care
+
+ attr_reader :is_class_method
+
+ ##
+ # +arg+ may be
+ #
+ # 1. A class or module name (optionally qualified with other class or module
+ # names (Kernel, File::Stat etc)
+ # 2. A method name
+ # 3. A method name qualified by a optionally fully qualified class or module
+ # name
+ #
+ # We're fairly casual about delimiters: folks can say Kernel::puts,
+ # Kernel.puts, or Kernel\#puts for example. There's one exception: if you
+ # say IO::read, we look for a class method, but if you say IO.read, we look
+ # for an instance method
+
+ def initialize(arg)
+ @class_names = []
+ separator = nil
+
+ tokens = arg.split(/(\.|::|#)/)
+
+ # Skip leading '::', '#' or '.', but remember it might
+ # be a method name qualifier
+ separator = tokens.shift if tokens[0] =~ /^(\.|::|#)/
+
+ # Skip leading '::', but remember we potentially have an inst
+
+ # leading stuff must be class names
+
+ while tokens[0] =~ /^[A-Z]/
+ @class_names << tokens.shift
+ unless tokens.empty?
+ separator = tokens.shift
+ break unless separator == "::"
+ end
+ end
+
+ # Now must have a single token, the method name, or an empty array
+ unless tokens.empty?
+ @method_name = tokens.shift
+ # We may now have a trailing !, ?, or = to roll into
+ # the method name
+ if !tokens.empty? && tokens[0] =~ /^[!?=]$/
+ @method_name << tokens.shift
+ end
+
+ if @method_name =~ /::|\.|#/ or !tokens.empty?
+ raise RDoc::RI::Error.new("Bad argument: #{arg}")
+ end
+ if separator && separator != '.'
+ @is_class_method = separator == "::"
+ end
+ end
+ end
+
+ # Return the full class name (with '::' between the components) or "" if
+ # there's no class name
+
+ def full_class_name
+ @class_names.join("::")
+ end
+
+end
+
diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/writer.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/writer.rb
new file mode 100644
index 000000000..92aaa1c2d
--- /dev/null
+++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/writer.rb
@@ -0,0 +1,68 @@
+require 'fileutils'
+require 'rdoc/ri'
+
+class RDoc::RI::Writer
+
+ def self.class_desc_path(dir, class_desc)
+ File.join(dir, "cdesc-" + class_desc.name + ".yaml")
+ end
+
+ ##
+ # Convert a name from internal form (containing punctuation) to an external
+ # form (where punctuation is replaced by %xx)
+
+ def self.internal_to_external(name)
+ if ''.respond_to? :ord then
+ name.gsub(/\W/) { "%%%02x" % $&[0].ord }
+ else
+ name.gsub(/\W/) { "%%%02x" % $&[0] }
+ end
+ end
+
+ ##
+ # And the reverse operation
+
+ def self.external_to_internal(name)
+ name.gsub(/%([0-9a-f]{2,2})/) { $1.to_i(16).chr }
+ end
+
+ def initialize(base_dir)
+ @base_dir = base_dir
+ end
+
+ def remove_class(class_desc)
+ FileUtils.rm_rf(path_to_dir(class_desc.full_name))
+ end
+
+ def add_class(class_desc)
+ dir = path_to_dir(class_desc.full_name)
+ FileUtils.mkdir_p(dir)
+ class_file_name = self.class.class_desc_path(dir, class_desc)
+ File.open(class_file_name, "w") do |f|
+ f.write(class_desc.serialize)
+ end
+ end
+
+ def add_method(class_desc, method_desc)
+ dir = path_to_dir(class_desc.full_name)
+ file_name = self.class.internal_to_external(method_desc.name)
+ meth_file_name = File.join(dir, file_name)
+ if method_desc.is_singleton
+ meth_file_name += "-c.yaml"
+ else
+ meth_file_name += "-i.yaml"
+ end
+
+ File.open(meth_file_name, "w") do |f|
+ f.write(method_desc.serialize)
+ end
+ end
+
+ private
+
+ def path_to_dir(class_name)
+ File.join(@base_dir, *class_name.split('::'))
+ end
+
+end
+