Class: RDoc::Generator::Babel
- Inherits:
-
Object
- Object
- RDoc::Generator::Babel
- Includes:
- ERB::Util
- Defined in:
- lib/rdoc/generator/babel.rb
Overview
Babel RDoc HTML Generator. (Initially a variation of Darkfish.)
Defined Under Namespace
Modules: Options
Constant Summary collapse
- VERSION =
'1.6.0'- DESCRIPTION =
'Alternate HTML documentation'- TEMPLATE_ROOT =
Directory containing babel templates. Each template is in a subdirectory named after the template.
Pathname.new(__FILE__)..dirname
Class Method Summary collapse
-
.setup_options(rdoc_options) ⇒ Object
Add Babel options to RDoc standard options.
Instance Method Summary collapse
-
#class_dir ⇒ Object
Directory for generated class/module files.
-
#decorated_call_seq(method, method_name_class) ⇒ Object
Decorates a call-seq to highlight the method name.
-
#description(method) ⇒ Object
Returns the HTML for the description of a method, with alias information and link to ancestor method/attribute.
-
#file_dir ⇒ Object
Directory for generated TopLevel files.
-
#first_page ⇒ Object
Returns the first
Contextobject to display in the main frame. -
#generate ⇒ Object
Generates the documentation.
-
#generate_class_and_module_files ⇒ Object
Generates a documentation page for each class.
-
#generate_file_files ⇒ Object
Generates a documentation page for each file.
-
#generate_index(basename) ⇒ Object
Generates an index page.
-
#generate_indexes ⇒ Object
Generates
index.htmlandindexes.html. -
#initialize(store, options) ⇒ Babel
constructor
Saves the options, makes sure the template is found.
-
#section_methods_hash(methods) ⇒ Object
Returns a Hash { section => [methods] } for the current class methods
methods. -
#write_static_files ⇒ Object
Copy static files to the output directory.
Constructor Details
#initialize(store, options) ⇒ Babel
Saves the options, makes sure the template is found.
154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/rdoc/generator/babel.rb', line 154 def initialize(store, ) @store = store @options = @babel_options = . @see_standard_ancestors = @babel_options[:see_standard_ancestors] RDoc::AnyMethod.add_line_numbers = .line_numbers if RDoc::AnyMethod.respond_to? :add_line_numbers @options.template = 'ruby-lang' if @options.template == 'babel' # TODO leave template nil @template_dir = TEMPLATE_ROOT + @options.template @template_dir.directory? or raise RDoc::Error, "template not found: '#@template_dir'" @source_dir = Pathname.pwd. end |
Class Method Details
.setup_options(rdoc_options) ⇒ Object
Add Babel options to RDoc standard options.
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/rdoc/generator/babel.rb', line 90 def () = { :stylesheet_url => nil, #:index_attributes => false, #:ancestor_lists => false, #:list_standard_ancestors => false, :see_standard_ancestors => false, } .extend Options # 1. extend the existing object .class.include Options # 2. make sure #babel_options will be there on #dup'ed objects . = opt = .option_parser opt.separator "Babel options:" opt.separator nil opt.on('--style=URL', '-s', 'Specifies the URL of a stylesheet', 'that the template should use.', 'The default is "rdoc.css".') do |value| [:stylesheet_url] = value end opt.separator nil =begin opt.on('--index-attributes', 'Include attributes in the method index.', 'By default, only methods are included.') do |value| options[:index_attributes] = true end opt.separator nil opt.on('--ancestor-lists', 'Add lists of ancestor methods, attributes,', 'aliases and constants in the documentation', 'of a class/module.') do |value| options[:ancestor_lists] = true end opt.separator nil opt.on('--list-standard-ancestors', 'Include Kernel/Object methods', 'in ancestor methods.') do |value| options[:list_standard_ancestors] = true end opt.separator nil =end opt.on('--see-standard-ancestors', 'Add links to Kernel/Object', 'ancestor methods.') do |value| [:see_standard_ancestors] = true end opt.separator nil end |
Instance Method Details
#class_dir ⇒ Object
Directory for generated class/module files. Used by RDoc::ClassModule to build paths.
169 170 171 |
# File 'lib/rdoc/generator/babel.rb', line 169 def class_dir 'classes' end |
#decorated_call_seq(method, method_name_class) ⇒ Object
Decorates a call-seq to highlight the method name.
The output will have the method name inside HTML
span tags with CSS class method_name_class.
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 |
# File 'lib/rdoc/generator/babel.rb', line 401 def decorated_call_seq(method, method_name_class) # empty call_seq (RDoc bug) if method.call_seq.strip.empty? warn "call-seq empty: #{method.parent.full_name}#{method.name_prefix}#{method.name}" return '' end # I assume it is safe to use \001 \002 \003 \004 to escape & < > " text = method.call_seq.strip.gsub(/->/, "\001rarr;") ospan = "\002span class=\004#{method_name_class}\004\003" cspan = "\002/span\003" # the "or warn" below fire when the alias is not in the call-seq: # ARGF#inspect: nope 1 # Array#size: nope 1 # BasicObject#singleton_method_removed: nope 1 # BasicObject#singleton_method_undefined: nope 1 # Complex#real?: nope 1 # Enumerator::ArithmeticSequence#===: nope 3.2 # Enumerator::ArithmeticSequence#eql?: nope 1 # Enumerator::Lazy#_enumerable_drop: nope 1 # Enumerator::Lazy#_enumerable_drop_while: nope 1 # Enumerator::Lazy#_enumerable_filter_map: nope 1 # Enumerator::Lazy#_enumerable_flat_map: nope 1 # Enumerator::Lazy#_enumerable_grep: nope 1 # Enumerator::Lazy#_enumerable_grep_v: nope 1 # Enumerator::Lazy#_enumerable_map: nope 1 # Enumerator::Lazy#_enumerable_reject: nope 1 # Enumerator::Lazy#_enumerable_select: nope 1 # Enumerator::Lazy#_enumerable_take: nope 1 # Enumerator::Lazy#_enumerable_take_while: nope 1 # Enumerator::Lazy#_enumerable_uniq: nope 1 # Enumerator::Lazy#_enumerable_zip: nope 1 # Enumerator::Lazy#_enumerable_with_index: nope 1 # FalseClass#inspect: nope 1 # Fiber#inspect: nope 1 # File::empty?: nope 1 # File::Stat#size?: nope 1 # FileTest#empty?: nope 1 # Float#===: nope 3.2 # Float#inspect: nope 1 # Hash#initialize_copy: nope 1 # Integer#===: nope 3.2 # Integer#inspect: nope 1 # Method#===: nope 3.2 # Module#extended: nope 1 # Module#inspect: nope 1 # Module#method_added: nope 1 # Module#method_removed: nope 1 # Module#method_undefined: nope 1 # Module#prepended: nope 1 # Numeric#%: nope 3.2 # Proc#===: nope 3.2 # Proc#inspect: nope 1 # Process::Sys::getegid: nope 1 # String#initialize_copy: nope 1 # Struct#deconstruct: nope 1 # Symbol#===: nope 3.2 # Symbol#next: nope 1 # Thread#inspect: nope 1 # TrueClass#inspect: nope 1 if method.name =~ /^\w/ # look for things like 'IO.open' or 'open' at the beginning of lines name = Regexp.escape(method.name.sub(/=$/, '')) re = /^(\s*)([:\w]+\.)?(#{name})/ text.gsub!(re, "\\1\\2#{ospan}\\3#{cspan}") #or warn "#{method.parent.full_name}#{method.name_prefix}#{method.name}: nope 1" elsif method.name =~ /\[\]=?/ # [] and []= re = /[\[\]]/ sub_hash = { '[' => "#{ospan}[#{cspan}", ']' => "#{ospan}]#{cspan}" } text.gsub!(re, sub_hash) #or warn "#{method.parent.full_name}#{method.name_prefix}#{method.name}: nope 2" else # operators: # +(unary) -(unary) ~ ! # ** # * / % # + - # << >> # & # | ^ # > >= < <= # <=> == === =~ # != ` !~ case method.name # -(unary) +(unary) when '+@', '-@' re = /^(\s*)(#{Regexp.escape(method.name[0])})/ text.gsub!(re, "\\1#{ospan}\\2#{cspan}") #or warn "#{method.parent.full_name}#{method.name_prefix}#{method.name}: nope 3.1" else re = /^(.*?)(#{Regexp.escape(method.name)})/ text.gsub!(re, "\\1#{ospan}\\2#{cspan}") #or warn "#{method.parent.full_name}#{method.name_prefix}#{method.name}: nope 3.2" end end h(text).tr("\001\002\003\004", '&<>"').gsub("\n", '<br/>') end |
#description(method) ⇒ Object
Returns the HTML for the description of a method, with alias information and link to ancestor method/attribute.
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'lib/rdoc/generator/babel.rb', line 373 def description(method) desc = method.documented? ? method.description.strip : +'' if method.is_alias_for text = method.is_alias_for.documented? ? +'<p>' : +'<p class="nodoc">' text << 'Alias for ' << link(method, method.is_alias_for) << '</p>' append_with_nl desc, text end if method.see && (@see_standard_ancestors || method.see.parent.full_name !~ /^(Object|Kernel)$/) text = method.see.documented? ? +'<p>' : +'<p class="nodoc">' text << (desc.empty? ? 'See ' : 'See also ') text << link(method, method.see) << '</p>' append_with_nl desc, text end desc = '<p class="nodoc">(not documented)</p>' if desc.empty? unless method.aliases.empty? text = +'<p>Also aliased as ' text << method.aliases.map { |a| link(method, a) }.join(', ') << '</p>' append_with_nl desc, text end desc end |
#file_dir ⇒ Object
Directory for generated TopLevel files. Used by RDoc::TopLevel to build paths.
176 177 178 |
# File 'lib/rdoc/generator/babel.rb', line 176 def file_dir 'files' end |
#first_page ⇒ Object
Returns the first Context object to display in the main frame.
This is, in order:
- The file designated by the
main_pageoption, if there is aTopLevelor class/module with that name. - The first simple file that contains a comment (in the order given on the command line).
- The first class or module that contains a comment.
- The first file that contains a comment (in the order given on the command line).
- The first class or module that has any kind of content.
- The first class or module.
- The first file.
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
# File 'lib/rdoc/generator/babel.rb', line 341 def first_page if @main_page debug_msg "main as --main: #{@main_page}" @main_page elsif (file = @simple_files.first) debug_msg "main as first simple file: #{file}" file elsif (cm = @unique_classes_and_modules.find { |k| !k.comment.empty? }) debug_msg "main as first module/class with comment: #{cm}" cm # this is not a simple file, so currently not displayed in files # elsif (file = @files_with_comment.first) # debug_msg "main as first file with comment: #{file}" # file elsif !@unique_classes_and_modules.empty? cm = @unique_classes_and_modules.find { |k| k.any_content } if cm debug_msg "main as first module/class with any content: #{cm}" else debug_msg "main as first module/class (no content): #{cm}" cm = @unique_classes_and_modules.first end cm else debug_msg "main as first file: #{cm}" @all_files.first end end |
#generate ⇒ Object
Generates the documentation.
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/rdoc/generator/babel.rb', line 182 def generate # rdoc bug fix: public class/module methods appear as external_aliases (unresolved aliases) @store.all_classes_and_modules.each do |cm| next if cm.external_aliases.empty? class_level_names = cm.method_list.select { |m| m.type == 'class' }.map(&:name) cm.external_aliases.dup.each do |a| cm.external_aliases.delete a if class_level_names.include?(a.name) end end # other bug fix: method aliases with singleton mismatch @store.all_classes_and_modules.each do |cm| cm.class_method_list.each do |m| m.is_alias_for.singleton = true if m.is_alias_for m.aliases.each { |a| a.singleton = true } end end # set instance variables @output_dir = Pathname.new(@options.op_dir).(@source_dir) @all_classes_and_modules = @store.all_classes_and_modules.sort @unique_classes_and_modules = @store.unique_classes_and_modules.sort @all_methods = @unique_classes_and_modules. inject([]) { |a,m| a.concat m.method_list }. sort { |a,b| [a, a.parent_name] <=> [b, b.parent_name] } @all_files = @store.all_files # not sorted: keep command line order @files_with_comment = @all_files.reject { |f| f.comment.empty? } @simple_files = @files_with_comment.select { |f| f.parser == RDoc::Parser::Simple || f.parser == RDoc::Parser::Markdown } @files_to_display = if @unique_classes_and_modules.empty? @all_files else @simple_files end if @options.main_page # look for a TopLevel matching the main page @main_page = @all_files.find { |f| f.full_name == @options.main_page } if @main_page # TODO are there cases where main_page = 'README' for 'lib/README'? unless @files_to_display.find { |f| f.full_name == @options.main_page } @files_to_display.unshift @main_page end # look for a class/module with that name else match = @unique_classes_and_modules.find { |cm| cm.full_name == @options.main_page } if match @main_page = match else warn "no such page: --main #{@options.main_page}" end end else @main_page = nil end # write the output write_static_files generate_indexes generate_class_and_module_files generate_file_files rescue StandardError => err debug_msg "%s: %s\n %s" % [ err.class.name, err., err.backtrace.join("\n ") ] raise end |
#generate_class_and_module_files ⇒ Object
Generates a documentation page for each class.
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/rdoc/generator/babel.rb', line 296 def generate_class_and_module_files template_file = @template_dir + 'class-page.html.erb' debug_msg "Generating class documentation" @unique_classes_and_modules.each do |klass| debug_msg " %s %s" % [klass.type, klass.full_name] outfile = @output_dir + klass.path @class = klass @sections = klass.sections if @sections.size > 1 anonymous_section = @sections.find { |s| !s.title } if anonymous_section @sections.delete anonymous_section @sections << anonymous_section end end self.render_template(template_file, binding(), outfile) end end |
#generate_file_files ⇒ Object
Generates a documentation page for each file.
317 318 319 320 321 322 323 324 325 326 |
# File 'lib/rdoc/generator/babel.rb', line 317 def generate_file_files template_file = @template_dir + 'file-page.html.erb' debug_msg "Generating file documentation" @all_files.each do |file| debug_msg " file #{file.path}" outfile = @output_dir + file.path @file = file self.render_template(template_file, binding(), outfile) end end |
#generate_index(basename) ⇒ Object
Generates an index page.
287 288 289 290 291 292 |
# File 'lib/rdoc/generator/babel.rb', line 287 def generate_index(basename) debug_msg "Generating index #{basename}.html" template_file = @template_dir + "#{basename}.html.erb" outfile = @output_dir + "#{basename}.html" render_template(template_file, binding(), outfile) end |
#generate_indexes ⇒ Object
Generates index.html and indexes.html.
279 280 281 282 283 |
# File 'lib/rdoc/generator/babel.rb', line 279 def generate_indexes @first_page = first_page generate_index('index') generate_index('indexes') end |
#section_methods_hash(methods) ⇒ Object
Returns a Hash { section => [methods] } for the current class methods methods.
502 503 504 505 506 507 508 509 |
# File 'lib/rdoc/generator/babel.rb', line 502 def section_methods_hash(methods) h = methods.group_by(&:section) @sections.to_h do |section| [section, h[section]] end .compact end |
#write_static_files ⇒ Object
Copy static files to the output directory. Static files are all files in the template directory that do not have the .erb extension.
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/rdoc/generator/babel.rb', line 261 def write_static_files debug_msg "Copying static files" = { :verbose => $DEBUG_RDOC, :noop => @options.dry_run } static_files = Pathname. glob(@template_dir.to_s + '/**/*'). reject { |f| f.extname == '.erb' } static_files.sort.each do |source_path| out_path = @output_dir + source_path.relative_path_from(@template_dir) if source_path.directory? out_path.mkpath unless @options.dry_run else FileUtils.cp source_path.to_s, out_path.dirname.to_s, ** end end end |