Class | Generators::RIGenerator |
In: |
generators/ri_generator.rb
|
Parent: | Object |
Generators may need to return specific subclasses depending on the options they are passed. Because of this we create them using a factory
# File generators/ri_generator.rb, line 59 59: def RIGenerator.for(options) 60: new(options) 61: end
Set up a new HTML generator. Basically all we do here is load up the correct output temlate
# File generators/ri_generator.rb, line 70 70: def initialize(options) #:not-new: 71: @options = options 72: @ri_writer = RI::RiWriter.new(options.op_dir) 73: @markup = SM::SimpleMarkup.new 74: @to_flow = SM::ToFlow.new 75: end
# File generators/ri_generator.rb, line 98 98: def generate_class_info(cls) 99: if cls === RDoc::NormalModule 100: cls_desc = RI::ModuleDescription.new 101: else 102: cls_desc = RI::ClassDescription.new 103: cls_desc.superclass = cls.superclass 104: end 105: cls_desc.name = cls.name 106: cls_desc.full_name = cls.full_name 107: cls_desc.comment = markup(cls.comment) 108: 109: cls_desc.attributes =cls.attributes.sort.map do |a| 110: RI::Attribute.new(a.name, a.rw, markup(a.comment)) 111: end 112: 113: cls_desc.constants = cls.constants.map do |c| 114: RI::Constant.new(c.name, c.value, markup(c.comment)) 115: end 116: 117: cls_desc.includes = cls.includes.map do |i| 118: RI::IncludedModule.new(i.name) 119: end 120: 121: class_methods, instance_methods = method_list(cls) 122: 123: cls_desc.class_methods = class_methods.map do |m| 124: RI::MethodSummary.new(m.name) 125: end 126: cls_desc.instance_methods = instance_methods.map do |m| 127: RI::MethodSummary.new(m.name) 128: end 129: 130: update_or_replace(cls_desc) 131: 132: class_methods.each do |m| 133: generate_method_info(cls_desc, m) 134: end 135: 136: instance_methods.each do |m| 137: generate_method_info(cls_desc, m) 138: end 139: end
# File generators/ri_generator.rb, line 142 142: def generate_method_info(cls_desc, method) 143: meth_desc = RI::MethodDescription.new 144: meth_desc.name = method.name 145: meth_desc.full_name = cls_desc.full_name 146: if method.singleton 147: meth_desc.full_name += "::" 148: else 149: meth_desc.full_name += "#" 150: end 151: meth_desc.full_name << method.name 152: 153: meth_desc.comment = markup(method.comment) 154: meth_desc.params = params_of(method) 155: meth_desc.visibility = method.visibility.to_s 156: meth_desc.is_singleton = method.singleton 157: meth_desc.block_params = method.block_params 158: 159: meth_desc.aliases = method.aliases.map do |a| 160: RI::AliasName.new(a.name) 161: end 162: 163: @ri_writer.add_method(cls_desc, meth_desc) 164: end
# File generators/ri_generator.rb, line 213 213: def markup(comment) 214: return nil if !comment || comment.empty? 215: 216: # Convert leading comment markers to spaces, but only 217: # if all non-blank lines have them 218: 219: if comment =~ /^(?>\s*)[^\#]/ 220: content = comment 221: else 222: content = comment.gsub(/^\s*(#+)/) { $1.tr('#',' ') } 223: end 224: @markup.convert(content, @to_flow) 225: end
return a list of class and instance methods that we‘ll be documenting
# File generators/ri_generator.rb, line 171 171: def method_list(cls) 172: list = cls.method_list 173: unless @options.show_all 174: list = list.find_all do |m| 175: m.visibility == :public || m.visibility == :protected || m.force_documentation 176: end 177: end 178: 179: c = [] 180: i = [] 181: list.sort.each do |m| 182: if m.singleton 183: c << m 184: else 185: i << m 186: end 187: end 188: return c,i 189: end
# File generators/ri_generator.rb, line 191 191: def params_of(method) 192: if method.call_seq 193: method.call_seq 194: else 195: params = method.params || "" 196: 197: p = params.gsub(/\s*\#.*/, '') 198: p = p.tr("\n", " ").squeeze(" ") 199: p = "(" + p + ")" unless p[0] == ?( 200: 201: if (block = method.block_params) 202: block.gsub!(/\s*\#.*/, '') 203: block = block.tr("\n", " ").squeeze(" ") 204: if block[0] == ?( 205: block.sub!(/^\(/, '').sub!(/\)/, '') 206: end 207: p << " {|#{block.strip}| ...}" 208: end 209: p 210: end 211: end
# File generators/ri_generator.rb, line 89 89: def process_class(from_class) 90: generate_class_info(from_class) 91: 92: # now recure into this classes constituent classess 93: from_class.each_classmodule do |mod| 94: process_class(mod) 95: end 96: 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.
# File generators/ri_generator.rb, line 234 234: def update_or_replace(cls_desc) 235: old_cls = nil 236: 237: if @options.merge 238: rdr = RI::RiReader.new(RI::RiCache.new(@options.op_dir)) 239: 240: namespace = rdr.top_level_namespace 241: namespace = rdr.lookup_namespace_in(cls_desc.name, namespace) 242: if namespace.empty? 243: $stderr.puts "You asked me to merge this source into existing " 244: $stderr.puts "documentation. This file references a class or " 245: $stderr.puts "module called #{cls_desc.name} which I don't" 246: $stderr.puts "have existing documentation for." 247: $stderr.puts 248: $stderr.puts "Perhaps you need to generate its documentation first" 249: exit 1 250: else 251: old_cls = namespace[0] 252: end 253: end 254: 255: if old_cls.nil? 256: # no merge: simply overwrite 257: @ri_writer.remove_class(cls_desc) 258: @ri_writer.add_class(cls_desc) 259: else 260: # existing class: merge in 261: old_desc = rdr.get_class(old_cls) 262: 263: old_desc.merge_in(cls_desc) 264: @ri_writer.add_class(old_desc) 265: end 266: end