class RDoc::Generator::Starkfish
$Id$
Author/s¶ ↑
-
Michael Granger (ged@FaerieMUD.org)
Contributors¶ ↑
-
Mahlon E. Smith (mahlon@martini.nu)
-
Eric Hodel (drbrain@segment7.net)
License¶ ↑
Copyright © 2007-2010, Michael Granger. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-
Neither the name of the author/s, nor the names of the project’s contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Constants
- ANAME_TRANSFORMS
An array of transforms to run on a method name to derive a suitable anchor name. The pairs are used in pairs as arguments to gsub.
- CLASS_DIR
Directory where generated classes live relative to the root
- FILE_DIR
Directory where generated files live relative to the root
- GENERATOR_DIR
Path to this file’s parent directory. Used to find templates and other resources.
- SVNID_PATTERN
%q$Id$“
- SVNId
Subversion ID
- SVNRev
Subversion rev
- VERSION
Release Version
Attributes
The output directory
Public Class Methods
Standard generator factory method
# File lib/rdoc/generator/starkfish.rb, line 96 def self::for( options ) new( options ) end
Initialize a few instance variables before we start
# File lib/rdoc/generator/starkfish.rb, line 106 def initialize( options ) @options = options @template = nil template = options.template || 'starkfish' @template_dir = (template =~ /\A\//) ? Pathname.new( template ) : GENERATOR_DIR + 'template/' + template configfile = @template_dir + 'config.yml' @config = (configfile.file?) ? YAML.load_file( configfile.to_s ) : {} @files = [] @classes = [] @hyperlinks = {} @basedir = Pathname.pwd.expand_path options.diagram = false super() end
Public Instance Methods
Return the data section from the config file (if any)
# File lib/rdoc/generator/starkfish.rb, line 147 def data return @config['data'] end
Output progress information if debugging is enabled
# File lib/rdoc/generator/starkfish.rb, line 153 def debug_msg( *msg ) return unless $DEBUG $stderr.puts( *msg ) end
Create the directories the generated docs will live in if they don’t already exist.
# File lib/rdoc/generator/starkfish.rb, line 161 def gen_sub_directories @outputdir.mkpath end
Build the initial indices and output objects based on an array of TopLevel objects containing the extracted information.
# File lib/rdoc/generator/starkfish.rb, line 182 def generate( toplevels ) @outputdir = Pathname.new( @options.op_dir ).expand_path( @basedir ) if RDoc::Generator::Context.respond_to?( :build_indicies) @files, @classes = RDoc::Generator::Context.build_indicies( toplevels, @options ) else @files, @classes = RDoc::Generator::Context.build_indices( toplevels, @options ) end # Now actually write the output generate_xhtml( @options, @files, @classes ) rescue StandardError => err debug_msg "%s: %s\n %s" % [ err.class.name, err.message, err.backtrace.join("\n ") ] raise end
Generate output
# File lib/rdoc/generator/starkfish.rb, line 205 def generate_xhtml( options, files, classes ) files = gen_into( @files ) classes = gen_into( @classes ) # Make a hash of class info keyed by class name classes_by_classname = classes.inject({}) {|hash, classinfo| hash[ classinfo[:full_name] ] = classinfo hash[ classinfo[:full_name] ][:outfile] = classinfo[:full_name].gsub( /::/, '/' ) + '.html' hash } # Make a hash of file info keyed by path files_by_path = files.inject({}) {|hash, fileinfo| hash[ fileinfo[:full_path] ] = fileinfo hash[ fileinfo[:full_path] ][:outfile] = fileinfo[:full_path] + '.html' hash } self.write_style_sheet self.generate_index( options, files_by_path, classes_by_classname ) self.generate_class_files( options, files_by_path, classes_by_classname ) self.generate_file_files( options, files_by_path, classes_by_classname ) end
Read the spcified To be called from ERB template to import (embed) another template
# File lib/rdoc/generator/starkfish.rb, line 140 def import( erbfile ) erb = File.open( erbfile ) {|fp| ERb.new(fp.read) } return erb.run( binding() ) end
Copy over the stylesheet into the appropriate place in the output directory.
# File lib/rdoc/generator/starkfish.rb, line 168 def write_style_sheet debug_msg "Copying over static files" staticfiles = @config['static'] || %w[rdoc.css js images] staticfiles = staticfiles.split( /\s+/ ) if staticfiles.is_a?( String ) staticfiles.each do |path| FileUtils.cp_r( @template_dir + path, '.', :verbose => $DEBUG, :noop => $dryrun ) end end
Protected Instance Methods
Generate a documentation file for each class present in the given hash of classes
.
# File lib/rdoc/generator/starkfish.rb, line 274 def generate_class_files( options, files, classes ) debug_msg "Generating class documentation in #@outputdir" templatefile = @template_dir + 'classpage.rhtml' outputdir = @outputdir modsort = self.get_sorted_module_list( classes ) classes.sort_by {|k,v| k }.each do |classname, classinfo| debug_msg " working on %s (%s)" % [ classname, classinfo[:outfile] ] outfile = outputdir + classinfo[:outfile] rel_prefix = outputdir.relative_path_from( outfile.dirname ) svninfo = self.get_svninfo( classinfo ) debug_msg " rendering #{outfile}" self.render_template( templatefile, binding(), outfile ) end end
Generate a documentation file for each file present in the given hash of files
.
# File lib/rdoc/generator/starkfish.rb, line 295 def generate_file_files( options, files, classes ) debug_msg "Generating file documentation in #@outputdir" templatefile = @template_dir + 'filepage.rhtml' modsort = self.get_sorted_module_list( classes ) files.sort_by {|k,v| k }.each do |path, fileinfo| outfile = @outputdir + fileinfo[:outfile] debug_msg " working on %s (%s)" % [ path, outfile ] rel_prefix = @outputdir.relative_path_from( outfile.dirname ) context = binding() debug_msg " rendering #{outfile}" self.render_template( templatefile, binding(), outfile ) end end
Generate an index page which lists all the classes which are documented.
# File lib/rdoc/generator/starkfish.rb, line 261 def generate_index( options, files, classes ) debug_msg "Rendering the index page..." templatefile = @template_dir + 'index.rhtml' modsort = self.get_sorted_module_list( classes ) outfile = @basedir + @options.op_dir + 'index.html' self.render_template( templatefile, binding(), outfile ) end
Return a list of the documented modules sorted by salience first, then by name.
# File lib/rdoc/generator/starkfish.rb, line 237 def get_sorted_module_list( classes ) nscounts = classes.keys.inject({}) do |counthash, name| toplevel = name.gsub( /::.*/, '' ) counthash[toplevel] ||= 0 counthash[toplevel] += 1 counthash end # Sort based on how often the toplevel namespace occurs, and then on the name # of the module -- this works for projects that put their stuff into a # namespace, of course, but doesn't hurt if they don't. return classes.keys.sort_by do |name| toplevel = name.gsub( /::.*/, '' ) [ nscounts[ toplevel ] * -1, name ] end end
Try to extract Subversion information out of the first constant whose value looks like a subversion Id tag. If no matching constant is found, and empty hash is returned.
# File lib/rdoc/generator/starkfish.rb, line 343 def get_svninfo( classinfo ) return {} unless classinfo[:sections] constants = classinfo[:sections].first[:constants] or return {} constants.find {|c| c[:value] =~ SVNID_PATTERN } or return {} filename, rev, date, time, committer = $~.captures commitdate = Time.parse( date + ' ' + time ) return { :filename => filename, :rev => Integer( rev ), :commitdate => commitdate, :commitdelta => time_delta_string( Time.now.to_i - commitdate.to_i ), :committer => committer, } end
Load and render the erb template in the given templatefile
within the specified context
(a Binding object) and write it out to outfile
. Both templatefile
and outfile
should be Pathname-like objects.
# File lib/rdoc/generator/starkfish.rb, line 365 def render_template( templatefile, context, outfile ) template_src = templatefile.read template = ERB.new( template_src, nil, '<>' ) template.filename = templatefile.to_s output = begin template.result( context ) rescue NoMethodError => err raise "Error while evaluating %s: %s (at %p)" % [ templatefile.to_s, err.message, eval( "_erbout[-50,50]", context ) ] end output = self.wrap_content( output, context ) unless $dryrun outfile.dirname.mkpath outfile.open( 'w', 0644 ) do |ofh| ofh.print( output ) end else debug_msg " would have written %d bytes to %s" % [ output.length, outfile ] end end
Return a string describing the amount of time in the given number of seconds in terms a human can understand easily.
# File lib/rdoc/generator/starkfish.rb, line 315 def time_delta_string( seconds ) return 'less than a minute' if seconds < 1.minute return (seconds / 1.minute).to_s + ' minute' + (seconds/60 == 1 ? '' : 's') if seconds < 50.minutes return 'about one hour' if seconds < 90.minutes return (seconds / 1.hour).to_s + ' hours' if seconds < 18.hours return 'one day' if seconds < 1.day return 'about one day' if seconds < 2.days return (seconds / 1.day).to_s + ' days' if seconds < 1.week return 'about one week' if seconds < 2.week return (seconds / 1.week).to_s + ' weeks' if seconds < 3.months return (seconds / 1.month).to_s + ' months' if seconds < 1.year return (seconds / 1.year).to_s + ' years' end
Load the configured wrapper file and wrap it around the given content
.
# File lib/rdoc/generator/starkfish.rb, line 395 def wrap_content( output, context ) wrapper = @options.wrapper || @config['wrapper'] || 'wrapper.rhtml' wrapperfile = (wrapper =~ /\A\//) ? Pathname.new( wrapper ) : @template_dir + wrapper if wrapperfile.file? # Add 'content' to the context binding for the wrapper template eval( "content = %p" % [output], context ) template_src = wrapperfile.read template = ERB.new( template_src, nil, '<>' ) template.filename = templatefile.to_s begin return template.result( context ) rescue NoMethodError => err raise "Error while evaluating %s: %s (at %p)" % [ templatefile.to_s, err.message, eval( "_erbout[-50,50]", context ) ] end end end
Private Instance Methods
Given the name of a Ruby method, return a name suitable for use as target names in A tags.
# File lib/rdoc/generator/starkfish.rb, line 429 def aname_from_method( methodname ) return ANAME_TRANSFORMS.enum_slice( 2 ).inject( methodname.to_s ) do |name, xform| name.gsub( *xform ) end end