diff options
Diffstat (limited to 'trunk/lib/rdoc/ri')
-rw-r--r-- | trunk/lib/rdoc/ri/cache.rb | 188 | ||||
-rw-r--r-- | trunk/lib/rdoc/ri/descriptions.rb | 153 | ||||
-rw-r--r-- | trunk/lib/rdoc/ri/display.rb | 274 | ||||
-rw-r--r-- | trunk/lib/rdoc/ri/driver.rb | 551 | ||||
-rw-r--r-- | trunk/lib/rdoc/ri/formatter.rb | 616 | ||||
-rw-r--r-- | trunk/lib/rdoc/ri/paths.rb | 102 | ||||
-rw-r--r-- | trunk/lib/rdoc/ri/reader.rb | 106 | ||||
-rw-r--r-- | trunk/lib/rdoc/ri/util.rb | 81 | ||||
-rw-r--r-- | trunk/lib/rdoc/ri/writer.rb | 68 |
9 files changed, 0 insertions, 2139 deletions
diff --git a/trunk/lib/rdoc/ri/cache.rb b/trunk/lib/rdoc/ri/cache.rb deleted file mode 100644 index 2e267d95fb..0000000000 --- a/trunk/lib/rdoc/ri/cache.rb +++ /dev/null @@ -1,188 +0,0 @@ -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/trunk/lib/rdoc/ri/descriptions.rb b/trunk/lib/rdoc/ri/descriptions.rb deleted file mode 100644 index 0d8560323a..0000000000 --- a/trunk/lib/rdoc/ri/descriptions.rb +++ /dev/null @@ -1,153 +0,0 @@ -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 :instance_methods - 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 - -end - diff --git a/trunk/lib/rdoc/ri/display.rb b/trunk/lib/rdoc/ri/display.rb deleted file mode 100644 index 379cef11b3..0000000000 --- a/trunk/lib/rdoc/ri/display.rb +++ /dev/null @@ -1,274 +0,0 @@ -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 - - 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, ri_reader) - page do - superclass = klass.superclass_string - - 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| - inc_desc = ri_reader.find_class_by_name(inc.name) - if inc_desc - str = inc.name + "(" - str << inc_desc.instance_methods.map{|m| m.name}.join(", ") - str << ")" - incs << str - else - incs << inc.name - end - 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| - if constant.comment then - @formatter.wrap "#{constant.name}:" - - @formatter.indent do - @formatter.display_flow constant.comment - end - else - @formatter.wrap constant.name - end - end - end - - 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.empty? then - @formatter.blankline - - heading = data_type.to_s.split('_').join(' ').capitalize << ':' - @formatter.display_heading heading, 2, '' - - data = data.map { |item| item.name }.sort.join ', ' - @formatter.wrap data - 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})" - end - end - end - end - end - - ## - # 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 - - @formatter.wrap methods.map { |m| m.full_name }.join(", ") - 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 - - if method.source_path then - @formatter.blankline - @formatter.wrap("Extension from #{method.source_path}") - end - end - - ## - # List the classes in +classes+. - - def list_known_classes(classes) - if classes.empty? - warn_no_database - else - page do - @formatter.draw_line "Known classes and modules" - @formatter.blankline - - @formatter.wrap classes.sort.join(', ') - 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/trunk/lib/rdoc/ri/driver.rb b/trunk/lib/rdoc/ri/driver.rb deleted file mode 100644 index dfc5f2f98a..0000000000 --- a/trunk/lib/rdoc/ri/driver.rb +++ /dev/null @@ -1,551 +0,0 @@ -require 'optparse' -require 'yaml' - -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 - - class Hash < ::Hash - def self.convert(hash) - hash = new.update hash - - hash.each do |key, value| - hash[key] = case value - when ::Hash then - convert value - when Array then - value = value.map do |v| - ::Hash === v ? convert(v) : v - end - value - else - value - end - end - - hash - end - - def method_missing method, *args - self[method.to_s] - 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 - end - - class Error < RDoc::RI::Error; end - - class NotFoundError < Error - def message - "Nothing known about #{super}" - end - end - - attr_accessor :homepath # :nodoc: - - def self.process_args(argv) - options = {} - options[:use_stdout] = !$stdout.tty? - options[:width] = 72 - options[:formatter] = RDoc::RI::Formatter.for 'plain' - options[:list_classes] = false - options[:list_names] = false - - # By default all paths are used. If any of these are true, only those - # directories are used. - use_system = false - use_site = false - use_home = false - use_gems = false - doc_dirs = [] - - opts = OptionParser.new do |opt| - opt.program_name = File.basename $0 - opt.version = RDoc::VERSION - 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("--classes", "-c", - "Display the names of classes and modules we", - "know about.") do |value| - options[:list_classes] = value - end - - opt.separator nil - - opt.on("--doc-dir=DIRNAME", "-d", Array, - "List of directories to search for", - "documentation. If not specified, we search", - "the standard rdoc/ri directories. May be", - "repeated.") do |value| - value.each do |dir| - unless File.directory? dir then - raise OptionParser::InvalidArgument, "#{dir} is not a directory" - end - end - - doc_dirs.concat value - end - - 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 - - unless RDoc::RI::Paths::GEMDIRS.empty? then - opt.on("--[no-]gems", - "Include documentation from RubyGems.") do |value| - use_gems = value - end - end - - opt.separator nil - - opt.on("--[no-]home", - "Include documentation stored in ~/.rdoc.") do |value| - use_home = value - end - - opt.separator nil - - opt.on("--[no-]list-names", "-l", - "List all the names known to RDoc, one per", - "line.") do |value| - options[:list_names] = value - end - - opt.separator nil - - opt.on("--no-pager", "-T", - "Send output directly to stdout.") do |value| - options[:use_stdout] = !value - end - - opt.separator nil - - opt.on("--[no-]site", - "Include documentation from libraries", - "installed in site_lib.") do |value| - use_site = value - end - - opt.separator nil - - opt.on("--[no-]system", - "Include documentation from Ruby's standard", - "library.") do |value| - use_system = value - 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[: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 - - rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e - puts opts - puts - puts e - exit 1 - end - - def self.run(argv = ARGV) - options = process_args argv - ri = new options - ri.run - end - - def initialize(options={}) - options[:formatter] ||= RDoc::RI::Formatter.for('plain') - options[:use_stdout] ||= !$stdout.tty? - options[:width] ||= 72 - @names = options[:names] - - @class_cache_name = 'classes' - @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 = 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 = RDoc::RI::DefaultDisplay.new(options[:formatter], - options[:width], - options[:use_stdout]) - end - - def class_cache - return @class_cache if @class_cache - - newest = map_dirs('created.rid', :all) do |f| - File.mtime f if test ?f, f - end.max - - up_to_date = (File.exist?(class_cache_file_path) and - newest and newest < File.mtime(class_cache_file_path)) - - @class_cache = if up_to_date then - load_cache_for @class_cache_name - else - class_cache = RDoc::RI::Driver::Hash.new - - classes = map_dirs('**/cdesc*.yaml', :sys) { |f| Dir[f] } - populate_class_cache class_cache, classes - - classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] } - warn "Updating class cache with #{classes.size} classes..." - - populate_class_cache class_cache, classes, true - write_cache class_cache, class_cache_file_path - end - - @class_cache = RDoc::RI::Driver::Hash.convert @class_cache - @class_cache - end - - def class_cache_file_path - File.join cache_file_path, @class_cache_name - end - - def cache_file_for(klassname) - File.join cache_file_path, klassname.gsub(/:+/, "-") - end - - def cache_file_path - File.join @homepath, 'cache' - end - - def display_class(name) - klass = class_cache[name] - klass = RDoc::RI::Driver::Hash.convert klass - @display.display_class_info klass, class_cache - end - - def get_info_for(arg) - @names = [arg] - run - end - - 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) then - open path, 'rb' do |fp| - cache = Marshal.load fp.read - end - else - class_cache = nil - - open class_cache_file_path, 'rb' do |fp| - class_cache = Marshal.load fp.read - end - - klass = class_cache[klassname] - return nil unless klass - - method_files = klass["sources"] - cache = RDoc::RI::Driver::Hash.new - - sys_dir = @sys_dirs.first - 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 - name = method["full_name"] - ext_path = f - ext_path = "gem #{$1}" if f =~ %r%gems/[\d.]+/doc/([^/]+)% - method["source_path"] = ext_path unless system_file - cache[name] = RDoc::RI::Driver::Hash.convert method - end - end - - write_cache cache, path - end - - RDoc::RI::Driver::Hash.convert cache - end - - ## - # Finds the next ancestor of +orig_klass+ after +klass+. - - def lookup_ancestor(klass, orig_klass) - cache = class_cache[orig_klass] - - return nil unless cache - - ancestors = [orig_klass] - ancestors.push(*cache.includes.map { |inc| inc['name'] }) - ancestors << cache.superclass - - ancestor = ancestors[ancestors.index(klass) + 1] - - return ancestor if ancestor - - 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, system=false) - dirs = if system == :all then - @all_dirs - else - if system then - @sys_dirs - else - @all_dirs - @sys_dirs - end - end - - 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 - - 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 = RDoc::RI::Driver::Hash.convert klass - - klass.merge_enums desc - klass["sources"] << cdesc - end - end - end - - def read_yaml(path) - data = File.read path - data = data.gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '') - data = data.gsub(/ \!ruby\/(object|struct):SM::(\S+)/, - ' !ruby/\1:RDoc::Markup::\2') - YAML.load data - end - - def run - if @names.empty? then - @display.list_known_classes class_cache.keys.sort - else - @names.each do |name| - case name - when /::|\#|\./ then - if class_cache.key? name then - display_class name - else - klass, = parse_name name - - orig_klass = klass - orig_name = name - - until klass == 'Kernel' do - method = lookup_method name, klass - - break method 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.display_method_info method - end - else - if class_cache.key? name then - display_class name - else - methods = select_methods(/^#{name}/) - - if methods.size == 0 - raise NotFoundError, name - elsif methods.size == 1 - @display.display_method_info methods.first - else - @display.display_method_list methods - end - end - end - end - end - rescue NotFoundError => e - abort e.message - end - - 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 - - def write_cache(cache, path) - File.open path, "wb" do |cache_file| - Marshal.dump cache, cache_file - end - - cache - end - -end - diff --git a/trunk/lib/rdoc/ri/formatter.rb b/trunk/lib/rdoc/ri/formatter.rb deleted file mode 100644 index 0a0c3f7380..0000000000 --- a/trunk/lib/rdoc/ri/formatter.rb +++ /dev/null @@ -1,616 +0,0 @@ -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.puts txt - end - - ## - # Convert HTML entities back to ASCII - - def conv_html(txt) - txt = txt.gsub(/>/, '>') - txt.gsub!(/</, '<') - txt.gsub!(/"/, '"') - txt.gsub!(/&/, '&') - 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 - - 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 - @output.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 - @output.puts("<hr>") - end - - def bold_print(txt) - tag("b") { txt } - end - - def blankline() - @output.puts("<p>") - end - - def break_to_newline - @output.puts("<br>") - end - - def display_heading(text, level, indent) - level = 4 if level > 4 - tag("h#{level}") { text } - @output.puts - end - - def display_list(list) - case list.type - when :BULLET then - list_type = "ul" - prefixer = proc { |ignored| "<li>" } - - when :NUMBER, :UPPERALPHA, :LOWERALPHA then - list_type = "ol" - prefixer = proc { |ignored| "<li>" } - - when :LABELED then - list_type = "dl" - prefixer = proc do |li| - "<dt><b>" + escape(li.label) + "</b><dd>" - end - - when :NOTE then - list_type = "table" - prefixer = proc do |li| - %{<tr valign="top"><td>#{li.label.gsub(/ /, ' ')}</td><td>} - end - 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) - else - display_flow_item(item) - end - end - @output.print "</#{list_type}>" - end - - def display_verbatim_flow_item(item, prefix=@indent) - @output.print("<pre>") - item.body.split(/\n/).each do |line| - @output.puts conv_html(line) - end - @output.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 - @output.print str - end - - def tag(code) - @output.print("<#{code}>") - @output.print(yield) - @output.print("</#{code}>") - end - - def escape(str) - str = str.gsub(/&/n, '&') - str.gsub!(/\"/n, '"') - str.gsub!(/>/n, '>') - str.gsub!(/</n, '<') - 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/trunk/lib/rdoc/ri/paths.rb b/trunk/lib/rdoc/ri/paths.rb deleted file mode 100644 index b4b6c64925..0000000000 --- a/trunk/lib/rdoc/ri/paths.rb +++ /dev/null @@ -1,102 +0,0 @@ -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)} - - 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 - GEMDIRS.each { |dir| PATH << dir } - 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) - 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/trunk/lib/rdoc/ri/reader.rb b/trunk/lib/rdoc/ri/reader.rb deleted file mode 100644 index 986bb75954..0000000000 --- a/trunk/lib/rdoc/ri/reader.rb +++ /dev/null @@ -1,106 +0,0 @@ -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| 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/trunk/lib/rdoc/ri/util.rb b/trunk/lib/rdoc/ri/util.rb deleted file mode 100644 index 34277f2594..0000000000 --- a/trunk/lib/rdoc/ri/util.rb +++ /dev/null @@ -1,81 +0,0 @@ -require 'rdoc/ri' - -class RDoc::RI::Error < RuntimeError; end - -## -# 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/trunk/lib/rdoc/ri/writer.rb b/trunk/lib/rdoc/ri/writer.rb deleted file mode 100644 index 92aaa1c2da..0000000000 --- a/trunk/lib/rdoc/ri/writer.rb +++ /dev/null @@ -1,68 +0,0 @@ -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 - |