summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-01-08 10:18:41 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-01-08 10:18:41 +0000
commit1da5b222e289cae8494666b867a340c94763ab26 (patch)
treee82f30dd15c6f0e3d89fbe45c573ad755750e769 /lib
parent5c568c5cb3d91af356631ceb496bd0130e13cbc3 (diff)
downloadruby-1da5b222e289cae8494666b867a340c94763ab26.tar.gz
ruby-1da5b222e289cae8494666b867a340c94763ab26.tar.xz
ruby-1da5b222e289cae8494666b867a340c94763ab26.zip
Clean up namespacing of RI's classes
git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@14953 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/rdoc/generators/ri_generator.rb34
-rw-r--r--lib/rdoc/options.rb8
-rw-r--r--lib/rdoc/rdoc.rb2
-rw-r--r--lib/rdoc/ri/cache.rb188
-rw-r--r--lib/rdoc/ri/descriptions.rb147
-rw-r--r--lib/rdoc/ri/display.rb (renamed from lib/rdoc/ri/ri_display.rb)71
-rw-r--r--lib/rdoc/ri/driver.rb (renamed from lib/rdoc/ri/ri_driver.rb)60
-rw-r--r--lib/rdoc/ri/formatter.rb662
-rw-r--r--lib/rdoc/ri/paths.rb97
-rw-r--r--lib/rdoc/ri/reader.rb106
-rw-r--r--lib/rdoc/ri/ri_cache.rb187
-rw-r--r--lib/rdoc/ri/ri_descriptions.rb154
-rw-r--r--lib/rdoc/ri/ri_formatter.rb673
-rw-r--r--lib/rdoc/ri/ri_paths.rb97
-rw-r--r--lib/rdoc/ri/ri_reader.rb100
-rw-r--r--lib/rdoc/ri/ri_writer.rb62
-rw-r--r--lib/rdoc/ri/util.rb (renamed from lib/rdoc/ri/ri_util.rb)44
-rw-r--r--lib/rdoc/ri/writer.rb64
18 files changed, 1356 insertions, 1400 deletions
diff --git a/lib/rdoc/generators/ri_generator.rb b/lib/rdoc/generators/ri_generator.rb
index 48a66c0d7..111a23285 100644
--- a/lib/rdoc/generators/ri_generator.rb
+++ b/lib/rdoc/generators/ri_generator.rb
@@ -1,10 +1,10 @@
require 'rdoc/generators'
require 'rdoc/markup/simple_markup/to_flow'
-require 'rdoc/ri/ri_cache'
-require 'rdoc/ri/ri_reader'
-require 'rdoc/ri/ri_writer'
-require 'rdoc/ri/ri_descriptions'
+require 'rdoc/ri/cache'
+require 'rdoc/ri/reader'
+require 'rdoc/ri/writer'
+require 'rdoc/ri/descriptions'
class RDoc::Generators::RIGenerator
@@ -25,7 +25,7 @@ class RDoc::Generators::RIGenerator
def initialize(options) #:not-new:
@options = options
- @ri_writer = RI::RiWriter.new(".")
+ @ri_writer = RDoc::RI::Writer.new "."
@markup = SM::SimpleMarkup.new
@to_flow = SM::ToFlow.new
@@ -53,34 +53,35 @@ class RDoc::Generators::RIGenerator
def generate_class_info(cls)
if cls === RDoc::NormalModule
- cls_desc = RI::ModuleDescription.new
+ cls_desc = RDoc::RI::ModuleDescription.new
else
- cls_desc = RI::ClassDescription.new
+ cls_desc = RDoc::RI::ClassDescription.new
cls_desc.superclass = cls.superclass
end
cls_desc.name = cls.name
cls_desc.full_name = cls.full_name
cls_desc.comment = markup(cls.comment)
- cls_desc.attributes =cls.attributes.sort.map do |a|
- RI::Attribute.new(a.name, a.rw, markup(a.comment))
+ cls_desc.attributes = cls.attributes.sort.map do |a|
+ RDoc::RI::Attribute.new(a.name, a.rw, markup(a.comment))
end
cls_desc.constants = cls.constants.map do |c|
- RI::Constant.new(c.name, c.value, markup(c.comment))
+ RDoc::RI::Constant.new(c.name, c.value, markup(c.comment))
end
cls_desc.includes = cls.includes.map do |i|
- RI::IncludedModule.new(i.name)
+ RDoc::RI::IncludedModule.new(i.name)
end
class_methods, instance_methods = method_list(cls)
cls_desc.class_methods = class_methods.map do |m|
- RI::MethodSummary.new(m.name)
+ RDoc::RI::MethodSummary.new(m.name)
end
+
cls_desc.instance_methods = instance_methods.map do |m|
- RI::MethodSummary.new(m.name)
+ RDoc::RI::MethodSummary.new(m.name)
end
update_or_replace(cls_desc)
@@ -94,9 +95,8 @@ class RDoc::Generators::RIGenerator
end
end
-
def generate_method_info(cls_desc, method)
- meth_desc = RI::MethodDescription.new
+ meth_desc = RDoc::RI::MethodDescription.new
meth_desc.name = method.name
meth_desc.full_name = cls_desc.full_name
if method.singleton
@@ -113,7 +113,7 @@ class RDoc::Generators::RIGenerator
meth_desc.block_params = method.block_params
meth_desc.aliases = method.aliases.map do |a|
- RI::AliasName.new(a.name)
+ RDoc::RI::AliasName.new(a.name)
end
@ri_writer.add_method(cls_desc, meth_desc)
@@ -190,7 +190,7 @@ class RDoc::Generators::RIGenerator
old_cls = nil
if @options.merge
- rdr = RI::RiReader.new(RI::RiCache.new(@options.op_dir))
+ rdr = RDoc::RI::Reader.new RDoc::RI::Cache.new(@options.op_dir)
namespace = rdr.top_level_namespace
namespace = rdr.lookup_namespace_in(cls_desc.name, namespace)
diff --git a/lib/rdoc/options.rb b/lib/rdoc/options.rb
index d8dc00d7c..02ee75ee0 100644
--- a/lib/rdoc/options.rb
+++ b/lib/rdoc/options.rb
@@ -1,7 +1,7 @@
# We handle the parsing of options, and subsequently as a singleton
# object to be queried for option values
-require "rdoc/ri/ri_paths"
+require "rdoc/ri/paths"
require 'optparse'
class RDoc::Options
@@ -423,7 +423,7 @@ Usage: #{opt.program_name} [options] [names...]
"subsequent --op parameter, so no special",
"privileges are needed.") do |value|
@generator_name = "ri"
- @op_dir = RI::Paths::HOMEDIR
+ @op_dir = RDoc::RI::Paths::HOMEDIR
setup_generator
end
@@ -435,7 +435,7 @@ Usage: #{opt.program_name} [options] [names...]
"making them accessible to others, so",
"special privileges are needed.") do |value|
@generator_name = "ri"
- @op_dir = RI::Paths::SITEDIR
+ @op_dir = RDoc::RI::Paths::SITEDIR
setup_generator
end
@@ -449,7 +449,7 @@ Usage: #{opt.program_name} [options] [names...]
"option is intended to be used during Ruby",
"installation.") do |value|
@generator_name = "ri"
- @op_dir = RI::Paths::SYSDIR
+ @op_dir = RDoc::RI::Paths::SYSDIR
setup_generator
end
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index 57f8fe08d..115cb69f3 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -36,7 +36,7 @@ module RDoc
##
# Exception thrown by any rdoc error.
- class Error < StandardError; end
+ class Error < RuntimeError; end
RDocError = Error # :nodoc:
diff --git a/lib/rdoc/ri/cache.rb b/lib/rdoc/ri/cache.rb
new file mode 100644
index 000000000..2e267d95f
--- /dev/null
+++ b/lib/rdoc/ri/cache.rb
@@ -0,0 +1,188 @@
+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 tha 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)
+ 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 = RiWriter.external_to_internal(external_name)
+ list = is_class_method ? @class_methods : @instance_methods
+ path = File.join(dir, name)
+ list << 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 = 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 know 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/lib/rdoc/ri/descriptions.rb b/lib/rdoc/ri/descriptions.rb
new file mode 100644
index 000000000..c9b7c9ba7
--- /dev/null
+++ b/lib/rdoc/ri/descriptions.rb
@@ -0,0 +1,147 @@
+require 'yaml'
+require 'rdoc/markup/simple_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::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::RDoc::RI::NamedThing; end
+
+class RDoc::RI::Attribute < RDoc::RI::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 :instance_methods
+ attr_accessor :attributes
+ attr_accessor :constants
+ attr_accessor :includes
+
+ # merge in another class desscription 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
+ @comment << SM::Flow::RULE.new
+ @comment.concat old.comment
+ 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
+
+end
+
diff --git a/lib/rdoc/ri/ri_display.rb b/lib/rdoc/ri/display.rb
index efc892876..21fd488bb 100644
--- a/lib/rdoc/ri/ri_display.rb
+++ b/lib/rdoc/ri/display.rb
@@ -1,54 +1,42 @@
-# This is a kind of 'flag' module. If you want to write your
-# own 'ri' display module (perhaps because you'r writing
-# an IDE or somesuch beast), you simply write a class
-# which implements the various 'display' methods in 'DefaultDisplay',
-# and include the 'RiDisplay' module in that class.
+require 'rdoc/ri'
+
+##
+# This is a kind of 'flag' module. If you want to write your own 'ri' display
+# module (perhaps because you'r writing an IDE or somesuch beast), you simply
+# write a class which implements the various 'display' methods in
+# 'DefaultDisplay', and include the 'RiDisplay' module in that class.
#
# To access your class from the command line, you can do
#
# ruby -r <your source file> ../ri ....
-#
-# If folks _really_ want to do this from the command line,
-# I'll build an option in
-module RiDisplay
+module RDoc::RI::Display
+
@@display_class = nil
- def RiDisplay.append_features(display_class)
+ def self.append_features(display_class)
@@display_class = display_class
end
- def RiDisplay.new(*args)
+ def self.new(*args)
@@display_class.new(*args)
end
+
end
-######################################################################
-#
-# A paging display module. Uses the ri_formatter class to do the
-# actual presentation
-#
+##
+# A paging display module. Uses the RDoc::RI::Formatter class to do the actual
+# presentation
-class DefaultDisplay
+class RDoc::RI::DefaultDisplay
- include RiDisplay
+ include RDoc::RI::Display
def initialize(formatter, width, use_stdout)
@use_stdout = use_stdout
@formatter = formatter.new width, " "
end
- ######################################################################
-
- def display_usage
- page do
- RI::Options::OptionList.usage(short_form=true)
- end
- end
-
-
- ######################################################################
-
def display_method_info(method)
page do
@formatter.draw_line(method.full_name)
@@ -65,8 +53,6 @@ class DefaultDisplay
end
end
- ######################################################################
-
def display_class_info(klass, ri_reader)
page do
superclass = klass.superclass_string
@@ -145,8 +131,7 @@ class DefaultDisplay
end
end
- ######################################################################
-
+ ##
# Display a list of method names
def display_method_list(methods)
@@ -157,8 +142,6 @@ class DefaultDisplay
end
end
- ######################################################################
-
def display_class_list(namespaces)
page do
puts "More than one class or module matched your request. You can refine"
@@ -167,8 +150,6 @@ class DefaultDisplay
end
end
- ######################################################################
-
def list_known_classes(classes)
if classes.empty?
warn_no_database
@@ -181,8 +162,6 @@ class DefaultDisplay
end
end
- ######################################################################
-
def list_known_names(names)
if names.empty?
warn_no_database
@@ -193,12 +172,8 @@ class DefaultDisplay
end
end
- ######################################################################
-
private
- ######################################################################
-
def page
if pager = setup_pager then
begin
@@ -215,8 +190,6 @@ class DefaultDisplay
rescue Errno::EPIPE
end
- ######################################################################
-
def setup_pager
unless @use_stdout then
for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq
@@ -227,8 +200,6 @@ class DefaultDisplay
end
end
- ######################################################################
-
def display_params(method)
params = method.params
@@ -248,7 +219,6 @@ class DefaultDisplay
@formatter.wrap("Extension from #{method.source_path}")
end
end
- ######################################################################
def display_flow(flow)
if !flow || flow.empty?
@@ -258,8 +228,6 @@ class DefaultDisplay
end
end
- ######################################################################
-
def warn_no_database
puts "No ri data found"
puts
@@ -272,4 +240,5 @@ class DefaultDisplay
puts "If you installed Ruby from a packaging system, then you may need to"
puts "install an additional package, or ask the packager to enable ri generation."
end
-end # class RiDisplay
+end
+
diff --git a/lib/rdoc/ri/ri_driver.rb b/lib/rdoc/ri/driver.rb
index 9f07db82c..9b1e3bea3 100644
--- a/lib/rdoc/ri/ri_driver.rb
+++ b/lib/rdoc/ri/driver.rb
@@ -2,20 +2,20 @@ require 'optparse'
require 'yaml'
require 'rdoc/ri'
-require 'rdoc/ri/ri_paths'
-require 'rdoc/ri/ri_formatter'
-require 'rdoc/ri/ri_display'
+require 'rdoc/ri/paths'
+require 'rdoc/ri/formatter'
+require 'rdoc/ri/display'
require 'fileutils'
require 'rdoc/markup/simple_markup'
require 'rdoc/markup/simple_markup/to_flow'
-class RDoc::RI::RiDriver
-
+class RDoc::RI::Driver
+
def self.process_args(argv)
options = {}
options[:use_stdout] = !$stdout.tty?
options[:width] = 72
- options[:formatter] = RI::TextFormatter.for 'plain'
+ options[:formatter] = RDoc::RI::Formatter.for 'plain'
options[:list_classes] = false
options[:list_names] = false
@@ -33,12 +33,12 @@ class RDoc::RI::RiDriver
opt.summary_indent = ' ' * 4
directories = [
- RI::Paths::SYSDIR,
- RI::Paths::SITEDIR,
- RI::Paths::HOMEDIR
+ RDoc::RI::Paths::SYSDIR,
+ RDoc::RI::Paths::SITEDIR,
+ RDoc::RI::Paths::HOMEDIR
]
- if RI::Paths::GEMDIRS then
+ if RDoc::RI::Paths::GEMDIRS then
Gem.path.each do |dir|
directories << "#{dir}/doc/*/ri"
end
@@ -109,19 +109,19 @@ Options may also be set in the 'RI' environment variable.
opt.separator nil
opt.on("--fmt=FORMAT", "--format=FORMAT", "-f",
- RI::TextFormatter.list.split(', '), # HACK
+ RDoc::RI::Formatter::FORMATTERS.keys,
"Format to use when displaying output:",
- " #{RI::TextFormatter.list}",
+ " #{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] = RI::TextFormatter.for value
+ options[:formatter] = RDoc::RI::Formatter.for value
end
opt.separator nil
- if RI::Paths::GEMDIRS then
+ unless RDoc::RI::Paths::GEMDIRS.empty? then
opt.on("--[no-]gems",
"Include documentation from RubyGems.") do |value|
use_gems = value
@@ -180,10 +180,10 @@ Options may also be set in the 'RI' environment variable.
options[:names] = argv
- options[:path] = RI::Paths.path(use_system, use_site, use_home, use_gems,
- *doc_dirs)
- options[:raw_path] = RI::Paths.raw_path(use_system, use_site, use_home,
- use_gems, *doc_dirs)
+ options[:path] = RDoc::RI::Paths.path(use_system, use_site, use_home,
+ use_gems, *doc_dirs)
+ options[:raw_path] = RDoc::RI::Paths.raw_path(use_system, use_site,
+ use_home, use_gems, *doc_dirs)
options
@@ -204,17 +204,18 @@ Options may also be set in the 'RI' environment variable.
@names = options[:names]
@class_cache_name = 'classes'
- @all_dirs = RI::Paths.path(true, true, true, true)
- @homepath = RI::Paths.raw_path(false, false, true, false).first
+ @all_dirs = RDoc::RI::Paths.path(true, true, true, true)
+ @homepath = RDoc::RI::Paths.raw_path(false, false, true, false).first
@homepath = @homepath.sub(/\.rdoc/, '.ri')
- @sys_dirs = RI::Paths.raw_path(true, false, false, false)
+ @sys_dirs = RDoc::RI::Paths.raw_path(true, false, false, false)
FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path
@class_cache = nil
- @display = DefaultDisplay.new(options[:formatter], options[:width],
- options[:use_stdout])
+ @display = RDoc::RI::DefaultDisplay.new(options[:formatter],
+ options[:width],
+ options[:use_stdout])
end
def class_cache
@@ -371,7 +372,7 @@ Options may also be set in the 'RI' environment variable.
end
end
end
-
+
def select_classes(pattern = nil)
classes = class_cache.keys.sort
classes = classes.grep pattern if pattern
@@ -386,17 +387,6 @@ Options may also be set in the 'RI' environment variable.
cache
end
- # Couldn't find documentation in +path+, so tell the user what to do
-
- def report_missing_documentation(path)
- STDERR.puts "No ri documentation found in:"
- path.each do |d|
- STDERR.puts " #{d}"
- end
- STDERR.puts "\nWas rdoc run to create documentation?\n\n"
- RDoc::usage("Installing Documentation")
- end
-
end
class Hash
diff --git a/lib/rdoc/ri/formatter.rb b/lib/rdoc/ri/formatter.rb
new file mode 100644
index 000000000..0a98508dd
--- /dev/null
+++ b/lib/rdoc/ri/formatter.rb
@@ -0,0 +1,662 @@
+require 'rdoc/ri'
+
+class RDoc::RI::Formatter
+
+ attr_reader :indent
+
+ def initialize(width, indent)
+ @width = width
+ @indent = indent
+ end
+
+
+ ######################################################################
+
+ def draw_line(label=nil)
+ len = @width
+ len -= (label.size+1) if label
+ print "-"*len
+ if label
+ print(" ")
+ bold_print(label)
+ end
+ puts
+ 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?
+ puts(prefix + res.join("\n" + next_prefix))
+ end
+
+ ######################################################################
+
+ def blankline
+ puts
+ end
+
+ ######################################################################
+
+ # called when we want to ensure a nbew '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)
+ print txt
+ end
+
+ ######################################################################
+
+ def raw_print_line(txt)
+ puts txt
+ end
+
+ ######################################################################
+
+ # convert HTML entities back to ASCII
+ def conv_html(txt)
+ txt.
+ gsub(/&gt;/, '>').
+ gsub(/&lt;/, '<').
+ gsub(/&quot;/, '"').
+ gsub(/&amp;/, '&')
+
+ end
+
+ # convert markup into display form
+ def conv_markup(txt)
+ txt.
+ gsub(%r{<tt>(.*?)</tt>}) { "+#$1+" } .
+ gsub(%r{<code>(.*?)</code>}) { "+#$1+" } .
+ gsub(%r{<b>(.*?)</b>}) { "*#$1*" } .
+ gsub(%r{<em>(.*?)</em>}) { "_#$1_" }
+ end
+
+ ######################################################################
+
+ def display_list(list)
+ case list.type
+
+ when SM::ListBase::BULLET
+ prefixer = proc { |ignored| @indent + "* " }
+
+ when SM::ListBase::NUMBER,
+ SM::ListBase::UPPERALPHA,
+ SM::ListBase::LOWERALPHA
+
+ start = case list.type
+ when SM::ListBase::NUMBER then 1
+ when SM::ListBase::UPPERALPHA then 'A'
+ when SM::ListBase::LOWERALPHA then 'a'
+ end
+ prefixer = proc do |ignored|
+ res = @indent + "#{start}.".ljust(4)
+ start = start.succ
+ res
+ end
+
+ when SM::ListBase::LABELED
+ prefixer = proc do |li|
+ li.label
+ end
+
+ when SM::ListBase::NOTE
+ longest = 0
+ list.contents.each do |item|
+ if item.kind_of?(SM::Flow::LI) && item.label.length > longest
+ longest = item.label.length
+ end
+ end
+
+ prefixer = proc do |li|
+ @indent + li.label.ljust(longest+1)
+ end
+
+ else
+ fail "unknown list type"
+
+ end
+
+ list.contents.each do |item|
+ if item.kind_of? SM::Flow::LI
+ 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 SM::Flow::P, SM::Flow::LI
+ wrap(conv_html(item.body), prefix)
+ blankline
+
+ when SM::Flow::LIST
+ display_list(item)
+
+ when SM::Flow::VERB
+ display_verbatim_flow_item(item, @indent)
+
+ when SM::Flow::H
+ display_heading(conv_html(item.text), item.level, @indent)
+
+ when SM::Flow::RULE
+ draw_line
+
+ else
+ fail "Unknown flow element: #{item.class}"
+ end
+ end
+
+ ######################################################################
+
+ def display_verbatim_flow_item(item, prefix=@indent)
+ item.body.split(/\n/).each do |line|
+ print @indent, conv_html(line), "\n"
+ end
+ blankline
+ end
+
+ ######################################################################
+
+ def display_heading(text, level, indent)
+ text = strip_attributes(text)
+ case level
+ when 1
+ ul = "=" * text.length
+ puts
+ puts text.upcase
+ puts ul
+ # puts
+
+ when 2
+ ul = "-" * text.length
+ puts
+ puts text
+ puts ul
+ # puts
+ else
+ print indent, text, "\n"
+ end
+ end
+
+
+ def display_flow(flow)
+ flow.each do |f|
+ display_flow_item(f)
+ end
+ end
+
+ def strip_attributes(txt)
+ tokens = txt.split(%r{(</?(?:b|code|em|i|tt)>)})
+ text = []
+ attributes = 0
+ tokens.each do |tok|
+ case tok
+ when %r{^</(\w+)>$}, %r{^<(\w+)>$}
+ ;
+ else
+ text << tok
+ end
+ end
+ text.join
+ 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
+ }
+
+ # TODO: struct?
+ class AttrChar
+ attr_reader :char
+ attr_reader :attr
+
+ def initialize(char, attr)
+ @char = char
+ @attr = attr
+ end
+ end
+
+ 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
+
+ ##
+ # overridden in specific formatters
+
+ def write_attribute_text(prefix, line)
+ print prefix
+ line.each do |achar|
+ print achar.char
+ end
+ puts
+ end
+
+ ##
+ # again, overridden
+
+ def bold_print(txt)
+ 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)
+ print prefix
+ line.each do |achar|
+ attr = achar.attr
+ if (attr & (ITALIC+CODE)) != 0
+ print "_", BS
+ end
+ if (attr & BOLD) != 0
+ print achar.char, BS
+ end
+ print achar.char
+ end
+ puts
+ end
+
+ ##
+ # draw a string in bold
+
+ def bold_print(text)
+ text.split(//).each do |ch|
+ 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)
+ print "\033[0m"
+ super
+ end
+
+ def write_attribute_text(prefix, line)
+ 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
+ print achar.char
+ end
+ update_attributes(0) unless curr_attr.zero?
+ puts
+ end
+
+ def bold_print(txt)
+ 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]
+ print indent
+ print heading[0]
+ print strip_attributes(text)
+ 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
+ print str, "m"
+ end
+
+end
+
+##
+# This formatter uses HTML.
+
+class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter
+
+ def initialize(*args)
+ super
+ end
+
+ def write_attribute_text(prefix, line)
+ curr_attr = 0
+ line.each do |achar|
+ attr = achar.attr
+ if achar.attr != curr_attr
+ update_attributes(curr_attr, achar.attr)
+ curr_attr = achar.attr
+ end
+ print(escape(achar.char))
+ end
+ update_attributes(curr_attr, 0) unless curr_attr.zero?
+ end
+
+ def draw_line(label=nil)
+ if label != nil
+ bold_print(label)
+ end
+ puts("<hr>")
+ end
+
+ def bold_print(txt)
+ tag("b") { txt }
+ end
+
+ def blankline()
+ puts("<p>")
+ end
+
+ def break_to_newline
+ puts("<br>")
+ end
+
+ def display_heading(text, level, indent)
+ level = 4 if level > 4
+ tag("h#{level}") { text }
+ puts
+ end
+
+ def display_list(list)
+ case list.type
+ when SM::ListBase::BULLET
+ list_type = "ul"
+ prefixer = proc { |ignored| "<li>" }
+
+ when SM::ListBase::NUMBER,
+ SM::ListBase::UPPERALPHA,
+ SM::ListBase::LOWERALPHA
+ list_type = "ol"
+ prefixer = proc { |ignored| "<li>" }
+
+ when SM::ListBase::LABELED
+ list_type = "dl"
+ prefixer = proc do |li|
+ "<dt><b>" + escape(li.label) + "</b><dd>"
+ end
+
+ when SM::ListBase::NOTE
+ list_type = "table"
+ prefixer = proc do |li|
+ %{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
+ end
+ else
+ fail "unknown list type"
+ end
+
+ print "<#{list_type}>"
+ list.contents.each do |item|
+ if item.kind_of? SM::Flow::LI
+ prefix = prefixer.call(item)
+ print prefix
+ display_flow_item(item, prefix)
+ else
+ display_flow_item(item)
+ end
+ end
+ print "</#{list_type}>"
+ end
+
+ def display_verbatim_flow_item(item, prefix=@indent)
+ print("<pre>")
+ item.body.split(/\n/).each do |line|
+ puts conv_html(line)
+ end
+ puts("</pre>")
+ 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
+ print str
+ end
+
+ def tag(code)
+ print("<#{code}>")
+ print(yield)
+ print("</#{code}>")
+ end
+
+ def escape(str)
+ str.
+ gsub(/&/n, '&amp;').
+ gsub(/\"/n, '&quot;').
+ gsub(/>/n, '&gt;').
+ gsub(/</n, '&lt;')
+ 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)
+ puts
+ end
+ end
+
+ ##
+ # Place heading level indicators inline with heading.
+
+ def display_heading(text, level, indent)
+ text = strip_attributes(text)
+ case level
+ when 1
+ puts "= " + text.upcase
+ when 2
+ puts "-- " + text
+ else
+ print indent, text, "\n"
+ end
+ end
+
+end
+
+
+##
+# Finally, fill in the list of known formatters
+
+class RDoc::RI::Formatter
+
+ FORMATTERS = {
+ "plain" => RDoc::RI::Formatter,
+ "simple" => RDoc::RI::SimpleFormatter,
+ "bs" => RDoc::RI::OverstrikeFormatter,
+ "ansi" => RDoc::RI::AnsiFormatter,
+ "html" => RDoc::RI::HtmlFormatter,
+ }
+
+ def self.list
+ FORMATTERS.keys.sort.join(", ")
+ end
+
+ def self.for(name)
+ FORMATTERS[name.downcase]
+ end
+
+end
+
diff --git a/lib/rdoc/ri/paths.rb b/lib/rdoc/ri/paths.rb
new file mode 100644
index 000000000..aba9b6f69
--- /dev/null
+++ b/lib/rdoc/ri/paths.rb
@@ -0,0 +1,97 @@
+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
+
+ # This is the search path for 'ri'
+ PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)}
+
+ require 'rubygems' unless defined?(Gem) 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
+ GEMDIRS.each { |dir| PATH << dir }
+
+ # 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)
+ return PATH unless use_system or use_site or use_home or use_gems or
+ not extra_dirs.empty?
+
+ 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/lib/rdoc/ri/reader.rb b/lib/rdoc/ri/reader.rb
new file mode 100644
index 000000000..e56c9fb76
--- /dev/null
+++ b/lib/rdoc/ri/reader.rb
@@ -0,0 +1,106 @@
+require 'rdoc/ri'
+require 'rdoc/ri/descriptions'
+require 'rdoc/ri/writer'
+require 'rdoc/markup/simple_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| RI::Description.deserialize(f) }
+ end
+
+ ##
+ # Return a class description
+
+ def get_class(class_entry)
+ result = nil
+ for path in class_entry.path_names
+ path = RiWriter.class_desc_path(path, class_entry)
+ desc = File.open(path) {|f| 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/lib/rdoc/ri/ri_cache.rb b/lib/rdoc/ri/ri_cache.rb
deleted file mode 100644
index 1844ac969..000000000
--- a/lib/rdoc/ri/ri_cache.rb
+++ /dev/null
@@ -1,187 +0,0 @@
-module RI
-
- class 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 tha 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)
- 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 = RiWriter.external_to_internal(external_name)
- list = is_class_method ? @class_methods : @instance_methods
- path = File.join(dir, name)
- list << 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 = 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 TopLevelEntry < 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 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 know about all 'ri' files
- # accessible to this program
-
- class RiCache
-
- attr_reader :toplevel
-
- def initialize(dirs)
- # At the top level we have a dummy module holding the
- # overall namespace
- @toplevel = TopLevelEntry.new('', '::', nil)
-
- dirs.each do |dir|
- @toplevel.load_from(dir)
- end
- end
-
- end
-end
diff --git a/lib/rdoc/ri/ri_descriptions.rb b/lib/rdoc/ri/ri_descriptions.rb
deleted file mode 100644
index e5ea9f2fb..000000000
--- a/lib/rdoc/ri/ri_descriptions.rb
+++ /dev/null
@@ -1,154 +0,0 @@
-require 'yaml'
-require 'rdoc/markup/simple_markup/fragments'
-
-# 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
-
-module RI
- class 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
-
-# Alias = Struct.new(:old_name, :new_name)
-
- class AliasName < NamedThing
- end
-
- class Attribute < NamedThing
- attr_reader :rw, :comment
- def initialize(name, rw, comment)
- super(name)
- @rw = rw
- @comment = comment
- end
- end
-
- class Constant < NamedThing
- attr_reader :value, :comment
- def initialize(name, value, comment)
- super(name)
- @value = value
- @comment = comment
- end
- end
-
- class IncludedModule < NamedThing
- end
-
-
- class MethodSummary < NamedThing
- def initialize(name="")
- super
- end
- end
-
-
-
- class Description
- attr_accessor :name
- attr_accessor :full_name
- attr_accessor :comment
-
- def serialize
- self.to_yaml
- end
-
- def Description.deserialize(from)
- YAML.load(from)
- end
-
- def <=>(other)
- @name <=> other.name
- end
- end
-
- class ModuleDescription < Description
-
- attr_accessor :class_methods
- attr_accessor :instance_methods
- attr_accessor :attributes
- attr_accessor :constants
- attr_accessor :includes
-
- # merge in another class desscription 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
- @comment << SM::Flow::RULE.new
- @comment.concat old.comment
- 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 ClassDescription < ModuleDescription
- attr_accessor :superclass
-
- def display_name
- "Class"
- end
-
- def superclass_string
- if @superclass && @superclass != "Object"
- @superclass
- else
- nil
- end
- end
- end
-
-
- class MethodDescription < 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
-
- end
-
-end
diff --git a/lib/rdoc/ri/ri_formatter.rb b/lib/rdoc/ri/ri_formatter.rb
deleted file mode 100644
index d317170b7..000000000
--- a/lib/rdoc/ri/ri_formatter.rb
+++ /dev/null
@@ -1,673 +0,0 @@
-module RI
- class TextFormatter
-
- attr_reader :indent
-
- def initialize(width, indent)
- @width = width
- @indent = indent
- end
-
-
- ######################################################################
-
- def draw_line(label=nil)
- len = @width
- len -= (label.size+1) if label
- print "-"*len
- if label
- print(" ")
- bold_print(label)
- end
- puts
- 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?
- puts(prefix + res.join("\n" + next_prefix))
- end
-
- ######################################################################
-
- def blankline
- puts
- end
-
- ######################################################################
-
- # called when we want to ensure a nbew '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)
- print txt
- end
-
- ######################################################################
-
- def raw_print_line(txt)
- puts txt
- end
-
- ######################################################################
-
- # convert HTML entities back to ASCII
- def conv_html(txt)
- txt.
- gsub(/&gt;/, '>').
- gsub(/&lt;/, '<').
- gsub(/&quot;/, '"').
- gsub(/&amp;/, '&')
-
- end
-
- # convert markup into display form
- def conv_markup(txt)
- txt.
- gsub(%r{<tt>(.*?)</tt>}) { "+#$1+" } .
- gsub(%r{<code>(.*?)</code>}) { "+#$1+" } .
- gsub(%r{<b>(.*?)</b>}) { "*#$1*" } .
- gsub(%r{<em>(.*?)</em>}) { "_#$1_" }
- end
-
- ######################################################################
-
- def display_list(list)
- case list.type
-
- when SM::ListBase::BULLET
- prefixer = proc { |ignored| @indent + "* " }
-
- when SM::ListBase::NUMBER,
- SM::ListBase::UPPERALPHA,
- SM::ListBase::LOWERALPHA
-
- start = case list.type
- when SM::ListBase::NUMBER then 1
- when SM::ListBase::UPPERALPHA then 'A'
- when SM::ListBase::LOWERALPHA then 'a'
- end
- prefixer = proc do |ignored|
- res = @indent + "#{start}.".ljust(4)
- start = start.succ
- res
- end
-
- when SM::ListBase::LABELED
- prefixer = proc do |li|
- li.label
- end
-
- when SM::ListBase::NOTE
- longest = 0
- list.contents.each do |item|
- if item.kind_of?(SM::Flow::LI) && item.label.length > longest
- longest = item.label.length
- end
- end
-
- prefixer = proc do |li|
- @indent + li.label.ljust(longest+1)
- end
-
- else
- fail "unknown list type"
-
- end
-
- list.contents.each do |item|
- if item.kind_of? SM::Flow::LI
- 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 SM::Flow::P, SM::Flow::LI
- wrap(conv_html(item.body), prefix)
- blankline
-
- when SM::Flow::LIST
- display_list(item)
-
- when SM::Flow::VERB
- display_verbatim_flow_item(item, @indent)
-
- when SM::Flow::H
- display_heading(conv_html(item.text), item.level, @indent)
-
- when SM::Flow::RULE
- draw_line
-
- else
- fail "Unknown flow element: #{item.class}"
- end
- end
-
- ######################################################################
-
- def display_verbatim_flow_item(item, prefix=@indent)
- item.body.split(/\n/).each do |line|
- print @indent, conv_html(line), "\n"
- end
- blankline
- end
-
- ######################################################################
-
- def display_heading(text, level, indent)
- text = strip_attributes(text)
- case level
- when 1
- ul = "=" * text.length
- puts
- puts text.upcase
- puts ul
-# puts
-
- when 2
- ul = "-" * text.length
- puts
- puts text
- puts ul
-# puts
- else
- print indent, text, "\n"
- end
- end
-
-
- def display_flow(flow)
- flow.each do |f|
- display_flow_item(f)
- end
- end
-
- def strip_attributes(txt)
- tokens = txt.split(%r{(</?(?:b|code|em|i|tt)>)})
- text = []
- attributes = 0
- tokens.each do |tok|
- case tok
- when %r{^</(\w+)>$}, %r{^<(\w+)>$}
- ;
- else
- text << tok
- end
- end
- text.join
- 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 AttributeFormatter < TextFormatter
-
- BOLD = 1
- ITALIC = 2
- CODE = 4
-
- ATTR_MAP = {
- "b" => BOLD,
- "code" => CODE,
- "em" => ITALIC,
- "i" => ITALIC,
- "tt" => CODE
- }
-
- # TODO: struct?
- class AttrChar
- attr_reader :char
- attr_reader :attr
-
- def initialize(char, attr)
- @char = char
- @attr = attr
- end
- end
-
-
- 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
-
- # overridden in specific formatters
-
- def write_attribute_text(prefix, line)
- print prefix
- line.each do |achar|
- print achar.char
- end
- puts
- end
-
- # again, overridden
-
- def bold_print(txt)
- 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 OverstrikeFormatter < AttributeFormatter
-
- BS = "\C-h"
-
- def write_attribute_text(prefix, line)
- print prefix
- line.each do |achar|
- attr = achar.attr
- if (attr & (ITALIC+CODE)) != 0
- print "_", BS
- end
- if (attr & BOLD) != 0
- print achar.char, BS
- end
- print achar.char
- end
- puts
- end
-
- # draw a string in bold
- def bold_print(text)
- text.split(//).each do |ch|
- print ch, BS, ch
- end
- end
- end
-
- ##################################################
-
- # This formatter uses ANSI escape sequences
- # to colorize stuff
- # works with pages such as man and less.
-
- class AnsiFormatter < AttributeFormatter
-
- def initialize(*args)
- print "\033[0m"
- super
- end
-
- def write_attribute_text(prefix, line)
- 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
- print achar.char
- end
- update_attributes(0) unless curr_attr.zero?
- puts
- end
-
-
- def bold_print(txt)
- 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]
- print indent
- print heading[0]
- print strip_attributes(text)
- 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
- print str, "m"
- end
- end
-
- ##################################################
-
- # This formatter uses HTML.
-
- class HtmlFormatter < AttributeFormatter
-
- def initialize(*args)
- super
- end
-
- def write_attribute_text(prefix, line)
- curr_attr = 0
- line.each do |achar|
- attr = achar.attr
- if achar.attr != curr_attr
- update_attributes(curr_attr, achar.attr)
- curr_attr = achar.attr
- end
- print(escape(achar.char))
- end
- update_attributes(curr_attr, 0) unless curr_attr.zero?
- end
-
- def draw_line(label=nil)
- if label != nil
- bold_print(label)
- end
- puts("<hr>")
- end
-
- def bold_print(txt)
- tag("b") { txt }
- end
-
- def blankline()
- puts("<p>")
- end
-
- def break_to_newline
- puts("<br>")
- end
-
- def display_heading(text, level, indent)
- level = 4 if level > 4
- tag("h#{level}") { text }
- puts
- end
-
- ######################################################################
-
- def display_list(list)
-
- case list.type
- when SM::ListBase::BULLET
- list_type = "ul"
- prefixer = proc { |ignored| "<li>" }
-
- when SM::ListBase::NUMBER,
- SM::ListBase::UPPERALPHA,
- SM::ListBase::LOWERALPHA
- list_type = "ol"
- prefixer = proc { |ignored| "<li>" }
-
- when SM::ListBase::LABELED
- list_type = "dl"
- prefixer = proc do |li|
- "<dt><b>" + escape(li.label) + "</b><dd>"
- end
-
- when SM::ListBase::NOTE
- list_type = "table"
- prefixer = proc do |li|
- %{<tr valign="top"><td>#{li.label.gsub(/ /, '&nbsp;')}</td><td>}
- end
- else
- fail "unknown list type"
- end
-
- print "<#{list_type}>"
- list.contents.each do |item|
- if item.kind_of? SM::Flow::LI
- prefix = prefixer.call(item)
- print prefix
- display_flow_item(item, prefix)
- else
- display_flow_item(item)
- end
- end
- print "</#{list_type}>"
- end
-
- def display_verbatim_flow_item(item, prefix=@indent)
- print("<pre>")
- item.body.split(/\n/).each do |line|
- puts conv_html(line)
- end
- puts("</pre>")
- 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
- print str
- end
-
- def tag(code)
- print("<#{code}>")
- print(yield)
- print("</#{code}>")
- end
-
- def escape(str)
- str.
- gsub(/&/n, '&amp;').
- gsub(/\"/n, '&quot;').
- gsub(/>/n, '&gt;').
- gsub(/</n, '&lt;')
- end
-
- end
-
- ##################################################
-
- # This formatter reduces extra lines for a simpler output.
- # It improves way output looks for tools like IRC bots.
-
- class SimpleFormatter < TextFormatter
-
- ######################################################################
-
- # No extra blank lines
-
- def blankline
- end
-
- ######################################################################
-
- # Display labels only, no lines
-
- def draw_line(label=nil)
- unless label.nil? then
- bold_print(label)
- puts
- end
- end
-
- ######################################################################
-
- # Place heading level indicators inline with heading.
-
- def display_heading(text, level, indent)
- text = strip_attributes(text)
- case level
- when 1
- puts "= " + text.upcase
- when 2
- puts "-- " + text
- else
- print indent, text, "\n"
- end
- end
-
- end
-
-
- # Finally, fill in the list of known formatters
-
- class TextFormatter
-
- FORMATTERS = {
- "ansi" => AnsiFormatter,
- "bs" => OverstrikeFormatter,
- "html" => HtmlFormatter,
- "plain" => TextFormatter,
- "simple" => SimpleFormatter,
- }
-
- def TextFormatter.list
- FORMATTERS.keys.sort.join(", ")
- end
-
- def TextFormatter.for(name)
- FORMATTERS[name.downcase]
- end
-
- end
-
-end
-
-
diff --git a/lib/rdoc/ri/ri_paths.rb b/lib/rdoc/ri/ri_paths.rb
deleted file mode 100644
index 095721679..000000000
--- a/lib/rdoc/ri/ri_paths.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-module 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 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
- HOMEDIR = File.join(homedir, ".rdoc")
- else
- HOMEDIR = nil
- end
-
- # This is the search path for 'ri'
- PATH = [ SYSDIR, SITEDIR, HOMEDIR ].find_all {|p| p && File.directory?(p)}
-
- require 'rubygems' unless defined?(Gem) 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
- GEMDIRS.each { |dir| RI::Paths::PATH << dir }
-
- # 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)
- return PATH unless use_system or use_site or use_home or use_gems or
- not extra_dirs.empty?
-
- path = []
- path << extra_dirs unless extra_dirs.empty?
- path << RI::Paths::SYSDIR if use_system
- path << RI::Paths::SITEDIR if use_site
- path << RI::Paths::HOMEDIR if use_home
- path << RI::Paths::GEMDIRS if use_gems
-
- return path.flatten.compact
- end
-
- end
-end
diff --git a/lib/rdoc/ri/ri_reader.rb b/lib/rdoc/ri/ri_reader.rb
deleted file mode 100644
index fb2c373e3..000000000
--- a/lib/rdoc/ri/ri_reader.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-require 'rdoc/ri/ri_descriptions'
-require 'rdoc/ri/ri_writer'
-require 'rdoc/markup/simple_markup/to_flow'
-
-module RI
- class RiReader
-
- 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| RI::Description.deserialize(f) }
- end
-
- # Return a class description
- def get_class(class_entry)
- result = nil
- for path in class_entry.path_names
- path = RiWriter.class_desc_path(path, class_entry)
- desc = File.open(path) {|f| 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
-end
diff --git a/lib/rdoc/ri/ri_writer.rb b/lib/rdoc/ri/ri_writer.rb
deleted file mode 100644
index 032558ed1..000000000
--- a/lib/rdoc/ri/ri_writer.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require 'fileutils'
-
-module RI
- class RiWriter
-
- def RiWriter.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 RiWriter.internal_to_external(name)
- name.gsub(/\W/) { "%%%02x" % $&[0].ord }
- end
-
- # And the reverse operation
- def RiWriter.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 = RiWriter.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 = RiWriter.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
-end
diff --git a/lib/rdoc/ri/ri_util.rb b/lib/rdoc/ri/util.rb
index 8a0125589..c4e6af47f 100644
--- a/lib/rdoc/ri/ri_util.rb
+++ b/lib/rdoc/ri/util.rb
@@ -1,29 +1,34 @@
-######################################################################
+require 'rdoc/ri'
-class RiError < Exception; end
-#
+class RDoc::RI::Error < RuntimeError; end
+
+##
# Break argument into its constituent class or module names, an
# optional method type, and a method name
-class NameDescriptor
+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
+ ##
+ # +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
+ # 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 = []
@@ -38,7 +43,7 @@ class NameDescriptor
# 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?
@@ -46,9 +51,8 @@ class NameDescriptor
break unless separator == "::"
end
end
-
- # Now must have a single token, the method name, or an empty
- # array
+
+ # 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
@@ -66,10 +70,12 @@ class NameDescriptor
end
end
- # Return the full class name (with '::' between the components)
- # or "" if there's no class name
+ # 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/lib/rdoc/ri/writer.rb b/lib/rdoc/ri/writer.rb
new file mode 100644
index 000000000..2d14942bd
--- /dev/null
+++ b/lib/rdoc/ri/writer.rb
@@ -0,0 +1,64 @@
+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)
+ name.gsub(/\W/) { "%%%02x" % $&[0].ord }
+ 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
+