summaryrefslogtreecommitdiff
path: root/lib/rdoc/generator/ri.rb
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-01-13 03:13:37 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-01-13 03:13:37 +0000
commitec519b9b43db7756fcc2c19020ece2d7e2263fe4 (patch)
treedf6a1e6827f788c68e430d44a5ff913a62af6cf7 /lib/rdoc/generator/ri.rb
parent937b7ab8b59346f02da81ef324b8955b01d7cc25 (diff)
Complete RDoc namespace change
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15018 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rdoc/generator/ri.rb')
-rw-r--r--lib/rdoc/generator/ri.rb228
1 files changed, 228 insertions, 0 deletions
diff --git a/lib/rdoc/generator/ri.rb b/lib/rdoc/generator/ri.rb
new file mode 100644
index 0000000000..bb0c4f4021
--- /dev/null
+++ b/lib/rdoc/generator/ri.rb
@@ -0,0 +1,228 @@
+require 'rdoc/generator'
+require 'rdoc/markup/simple_markup/to_flow'
+
+require 'rdoc/ri/cache'
+require 'rdoc/ri/reader'
+require 'rdoc/ri/writer'
+require 'rdoc/ri/descriptions'
+
+class RDoc::Generator::RI
+
+ ##
+ # Generator may need to return specific subclasses depending on the
+ # options they are passed. Because of this we create them using a factory
+
+ def self.for(options)
+ new(options)
+ end
+
+ class << self
+ protected :new
+ end
+
+ ##
+ # Set up a new RDoc::Generator::RI.
+
+ def initialize(options) #:not-new:
+ @options = options
+ @ri_writer = RDoc::RI::Writer.new "."
+ @markup = SM::SimpleMarkup.new
+ @to_flow = SM::ToFlow.new
+
+ @generated = {}
+ end
+
+ ##
+ # Build the initial indices and output objects based on an array of
+ # TopLevel objects containing the extracted information.
+
+ def generate(toplevels)
+ RDoc::TopLevel.all_classes_and_modules.each do |cls|
+ process_class(cls)
+ end
+ end
+
+ def process_class(from_class)
+ generate_class_info(from_class)
+
+ # now recure into this classes constituent classess
+ from_class.each_classmodule do |mod|
+ process_class(mod)
+ end
+ end
+
+ def generate_class_info(cls)
+ if cls === RDoc::NormalModule
+ cls_desc = RDoc::RI::ModuleDescription.new
+ else
+ 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|
+ RDoc::RI::Attribute.new(a.name, a.rw, markup(a.comment))
+ end
+
+ cls_desc.constants = cls.constants.map do |c|
+ RDoc::RI::Constant.new(c.name, c.value, markup(c.comment))
+ end
+
+ cls_desc.includes = cls.includes.map do |i|
+ RDoc::RI::IncludedModule.new(i.name)
+ end
+
+ class_methods, instance_methods = method_list(cls)
+
+ cls_desc.class_methods = class_methods.map do |m|
+ RDoc::RI::MethodSummary.new(m.name)
+ end
+
+ cls_desc.instance_methods = instance_methods.map do |m|
+ RDoc::RI::MethodSummary.new(m.name)
+ end
+
+ update_or_replace(cls_desc)
+
+ class_methods.each do |m|
+ generate_method_info(cls_desc, m)
+ end
+
+ instance_methods.each do |m|
+ generate_method_info(cls_desc, m)
+ end
+ end
+
+ def generate_method_info(cls_desc, method)
+ meth_desc = RDoc::RI::MethodDescription.new
+ meth_desc.name = method.name
+ meth_desc.full_name = cls_desc.full_name
+ if method.singleton
+ meth_desc.full_name += "::"
+ else
+ meth_desc.full_name += "#"
+ end
+ meth_desc.full_name << method.name
+
+ meth_desc.comment = markup(method.comment)
+ meth_desc.params = params_of(method)
+ meth_desc.visibility = method.visibility.to_s
+ meth_desc.is_singleton = method.singleton
+ meth_desc.block_params = method.block_params
+
+ meth_desc.aliases = method.aliases.map do |a|
+ RDoc::RI::AliasName.new(a.name)
+ end
+
+ @ri_writer.add_method(cls_desc, meth_desc)
+ end
+
+ private
+
+ ##
+ # Returns a list of class and instance methods that we'll be documenting
+
+ def method_list(cls)
+ list = cls.method_list
+ unless @options.show_all
+ list = list.find_all do |m|
+ m.visibility == :public || m.visibility == :protected || m.force_documentation
+ end
+ end
+
+ c = []
+ i = []
+ list.sort.each do |m|
+ if m.singleton
+ c << m
+ else
+ i << m
+ end
+ end
+ return c,i
+ end
+
+ def params_of(method)
+ if method.call_seq
+ method.call_seq
+ else
+ params = method.params || ""
+
+ p = params.gsub(/\s*\#.*/, '')
+ p = p.tr("\n", " ").squeeze(" ")
+ p = "(" + p + ")" unless p[0] == ?(
+
+ if (block = method.block_params)
+ block.gsub!(/\s*\#.*/, '')
+ block = block.tr("\n", " ").squeeze(" ")
+ if block[0] == ?(
+ block.sub!(/^\(/, '').sub!(/\)/, '')
+ end
+ p << " {|#{block.strip}| ...}"
+ end
+ p
+ end
+ end
+
+ def markup(comment)
+ return nil if !comment || comment.empty?
+
+ # Convert leading comment markers to spaces, but only
+ # if all non-blank lines have them
+
+ if comment =~ /^(?>\s*)[^\#]/
+ content = comment
+ else
+ content = comment.gsub(/^\s*(#+)/) { $1.tr('#',' ') }
+ end
+ @markup.convert(content, @to_flow)
+ end
+
+ ##
+ # By default we replace existing classes with the same name. If the
+ # --merge option was given, we instead merge this definition into an
+ # existing class. We add our methods, aliases, etc to that class, but do
+ # not change the class's description.
+
+ def update_or_replace(cls_desc)
+ old_cls = nil
+
+ if @options.merge
+ 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)
+ if namespace.empty?
+ $stderr.puts "You asked me to merge this source into existing "
+ $stderr.puts "documentation. This file references a class or "
+ $stderr.puts "module called #{cls_desc.name} which I don't"
+ $stderr.puts "have existing documentation for."
+ $stderr.puts
+ $stderr.puts "Perhaps you need to generate its documentation first"
+ exit 1
+ else
+ old_cls = namespace[0]
+ end
+ end
+
+ prev_cls = @generated[cls_desc.full_name]
+
+ if old_cls and not prev_cls then
+ old_desc = rdr.get_class old_cls
+ cls_desc.merge_in old_desc
+ end
+
+ if prev_cls then
+ cls_desc.merge_in prev_cls
+ end
+
+ @generated[cls_desc.full_name] = cls_desc
+
+ @ri_writer.remove_class cls_desc
+ @ri_writer.add_class cls_desc
+ end
+
+end
+