1 require 'rdoc/generator'
2 require 'rdoc/markup/to_flow'
4 require 'rdoc/ri/cache'
5 require 'rdoc/ri/reader'
6 require 'rdoc/ri/writer'
7 require 'rdoc/ri/descriptions'
9 class RDoc::Generator::RI
12 # Generator may need to return specific subclasses depending on the
13 # options they are passed. Because of this we create them using a factory
24 # Set up a new RDoc::Generator::RI.
26 def initialize(options) #:not-new:
28 @ri_writer = RDoc::RI::Writer.new "."
29 @markup = RDoc::Markup.new
30 @to_flow = RDoc::Markup::ToFlow.new
36 # Build the initial indices and output objects based on an array of
37 # TopLevel objects containing the extracted information.
39 def generate(toplevels)
40 RDoc::TopLevel.all_classes_and_modules.each do |cls|
45 def process_class(from_class)
46 generate_class_info(from_class)
48 # now recure into this classes constituent classess
49 from_class.each_classmodule do |mod|
54 def generate_class_info(cls)
55 if cls === RDoc::NormalModule
56 cls_desc = RDoc::RI::ModuleDescription.new
58 cls_desc = RDoc::RI::ClassDescription.new
59 cls_desc.superclass = cls.superclass
62 cls_desc.name = cls.name
63 cls_desc.full_name = cls.full_name
64 cls_desc.comment = markup(cls.comment)
66 cls_desc.attributes = cls.attributes.sort.map do |a|
67 RDoc::RI::Attribute.new(a.name, a.rw, markup(a.comment))
70 cls_desc.constants = cls.constants.map do |c|
71 RDoc::RI::Constant.new(c.name, c.value, markup(c.comment))
74 cls_desc.includes = cls.includes.map do |i|
75 RDoc::RI::IncludedModule.new(i.name)
78 class_methods, instance_methods = method_list(cls)
80 cls_desc.class_methods = class_methods.map do |m|
81 RDoc::RI::MethodSummary.new(m.name)
84 cls_desc.instance_methods = instance_methods.map do |m|
85 RDoc::RI::MethodSummary.new(m.name)
88 update_or_replace(cls_desc)
90 class_methods.each do |m|
91 generate_method_info(cls_desc, m)
94 instance_methods.each do |m|
95 generate_method_info(cls_desc, m)
99 def generate_method_info(cls_desc, method)
100 meth_desc = RDoc::RI::MethodDescription.new
101 meth_desc.name = method.name
102 meth_desc.full_name = cls_desc.full_name
104 meth_desc.full_name += "::"
106 meth_desc.full_name += "#"
108 meth_desc.full_name << method.name
110 meth_desc.comment = markup(method.comment)
111 meth_desc.params = params_of(method)
112 meth_desc.visibility = method.visibility.to_s
113 meth_desc.is_singleton = method.singleton
114 meth_desc.block_params = method.block_params
116 meth_desc.aliases = method.aliases.map do |a|
117 RDoc::RI::AliasName.new(a.name)
120 @ri_writer.add_method(cls_desc, meth_desc)
126 # Returns a list of class and instance methods that we'll be documenting
129 list = cls.method_list
130 unless @options.show_all
131 list = list.find_all do |m|
132 m.visibility == :public || m.visibility == :protected || m.force_documentation
138 list.sort.each do |m|
148 def params_of(method)
152 params = method.params || ""
154 p = params.gsub(/\s*\#.*/, '')
155 p = p.tr("\n", " ").squeeze(" ")
156 p = "(" + p + ")" unless p[0] == ?(
158 if (block = method.block_params)
159 block.gsub!(/\s*\#.*/, '')
160 block = block.tr("\n", " ").squeeze(" ")
162 block.sub!(/^\(/, '').sub!(/\)/, '')
164 p << " {|#{block.strip}| ...}"
171 return nil if !comment || comment.empty?
173 # Convert leading comment markers to spaces, but only
174 # if all non-blank lines have them
176 if comment =~ /^(?>\s*)[^\#]/
179 content = comment.gsub(/^\s*(#+)/) { $1.tr('#',' ') }
181 @markup.convert(content, @to_flow)
185 # By default we replace existing classes with the same name. If the
186 # --merge option was given, we instead merge this definition into an
187 # existing class. We add our methods, aliases, etc to that class, but do
188 # not change the class's description.
190 def update_or_replace(cls_desc)
194 rdr = RDoc::RI::Reader.new RDoc::RI::Cache.new(@options.op_dir)
196 namespace = rdr.top_level_namespace
197 namespace = rdr.lookup_namespace_in(cls_desc.name, namespace)
199 $stderr.puts "You asked me to merge this source into existing "
200 $stderr.puts "documentation. This file references a class or "
201 $stderr.puts "module called #{cls_desc.name} which I don't"
202 $stderr.puts "have existing documentation for."
204 $stderr.puts "Perhaps you need to generate its documentation first"
207 old_cls = namespace[0]
211 prev_cls = @generated[cls_desc.full_name]
213 if old_cls and not prev_cls then
214 old_desc = rdr.get_class old_cls
215 cls_desc.merge_in old_desc
219 cls_desc.merge_in prev_cls
222 @generated[cls_desc.full_name] = cls_desc
224 @ri_writer.remove_class cls_desc
225 @ri_writer.add_class cls_desc