module Hoe::ManualGen
Rake tasks for generating a project manual or tutorial.
This was born out of a frustration with other static HTML generation modules and systems. I've tried webby, webgen, rote, staticweb, staticmatic, and nanoc, but I didn't find any of them really suitable (except rote, which was excellent but apparently isn't maintained and has a fundamental incompatibilty with Rake because of some questionable monkeypatching.)
So, since nothing seemed to scratch my itch, I'm going to scratch it myself.
@author Michael Granger <ged@FaerieMUD.org> @author Mahlon E. Smith <mahlon@martini.nu>
Constants
- DEFAULT_BASE_DIR
Configuration defaults
- DEFAULT_LAYOUTS_DIR
- DEFAULT_LIB_DIR
- DEFAULT_MANUAL_SUBDIRS
The subdirectories to create under the manual dir
- DEFAULT_MANUAL_TEMPLATE_DIR
- DEFAULT_METADATA
- DEFAULT_OUTPUT_DIR
- DEFAULT_RESOURCE_DIR
- DEFAULT_SOURCE_DIR
- RESOURCE_EXTNAMES
A glob pattern for matching resource files when copying them around
- RESOURCE_GLOB_PATTERN
- REVISION
Version-control revision constant
- VERSION
Library version constant
Attributes
Public Instance Methods
Copy method for resources – passed as a block to the various file tasks that copy resources to the output directory.
# File lib/hoe/manualgen.rb, line 777 def copy_resource( task ) source = task.prerequisites[ 1 ] target = task.name when_writing do trace " #{source} -> #{target}" mkpath File.dirname( target ), :verbose => $trace unless File.directory?( File.dirname(target) ) install source, target, :mode => 0644, :verbose => $trace end end
Define tasks for generating output for an existing manual.
# File lib/hoe/manualgen.rb, line 668 def define_existing_manual_tasks( paths ) # Read all of the filters, pages, and layouts load_filter_libraries( paths[:libdir] ) trace "Creating the manual page catalog with source at %p, layouts in %p" % paths.values_at( :sourcedir, :layoutsdir ) catalog = PageCatalog.new( paths[:sourcedir], paths[:layoutsdir] ) # Declare the tasks outside the namespace that point in desc "Generate the manual" task :manual => "manual:build" CLEAN.include( paths[:outputdir].to_s ) # Namespace all our tasks namespace :manual do # Set up a file task for each resource, then a conversion task for # each page in the sourcedir so pages re-generate if they're modified setup_resource_copy_tasks( paths[:resourcedir], paths[:outputdir] ) manual_pages = setup_page_conversion_tasks( paths[:sourcedir], paths[:outputdir], catalog ) # The main task desc "Build the manual" task :build => [ :copy_resources, :copy_apidocs, :generate_pages ] task :clean do RakeFileUtils.verbose( $verbose ) do rm_f manual_pages.to_a end remove_dir( paths[:outputdir] ) if ( paths[:outputdir] + '.buildtime' ).exist? end desc "Force a rebuild of the manual" task :rebuild => [ :clean, :build ] desc "Update the resources templates for the manual to the latest versions" task :update do ask_for_confirmation( "Update the resources/templates in the manual directory?" ) do log "Updating..." install_manual_directory( paths[:basedir], paths[:templatedir], false ) end end # task :manual end end
Define tasks for creating a skeleton manual
# File lib/hoe/manualgen.rb, line 610 def define_manual_setup_tasks( paths ) templatedir = paths[:templatedir] trace "Templatedir is: %s" % [ templatedir ] manualdir = paths[:basedir] desc "Create a manual for this project from a template" task :manual do log "No manual directory (#{manualdir}) currently exists." ask_for_confirmation( "Create a new manual directory tree from a template?" ) do log "Generating manual skeleton" install_manual_directory( manualdir, templatedir ) end end # task :manual end
Set up the tasks for building the manual
# File lib/hoe/manualgen.rb, line 584 def define_manualgen_tasks # Make Pathnames of the directories relative to the base_dir basedir = Pathname( self.manual_base_dir ) @manual_paths = { :templatedir => Pathname( self.manual_template_dir ), :basedir => basedir, :sourcedir => basedir + self.manual_source_dir, :layoutsdir => basedir + self.manual_layouts_dir, :resourcedir => basedir + self.manual_resource_dir, :libdir => basedir + self.manual_lib_dir, :outputdir => basedir + self.manual_output_dir, } if basedir.directory? trace "Basedir %s exists, so defining tasks for building the manual" % [ basedir ] define_existing_manual_tasks( @manual_paths ) else trace "Basedir %s doesn't exist, so defining tasks for creating a new manual" % [ basedir ] define_manual_setup_tasks( @manual_paths ) end end
Hoe
callback – set up defaults
# File lib/hoe/manualgen.rb, line 567 def initialize_manualgen @manual_template_dir = DEFAULT_MANUAL_TEMPLATE_DIR @manual_base_dir = DEFAULT_BASE_DIR @manual_source_dir = DEFAULT_SOURCE_DIR @manual_layouts_dir = DEFAULT_LAYOUTS_DIR @manual_output_dir = DEFAULT_OUTPUT_DIR @manual_resource_dir = DEFAULT_RESOURCE_DIR @manual_lib_dir = DEFAULT_LIB_DIR @manual_metadata = DEFAULT_METADATA @manual_paths = {} self.extra_dev_deps << ['hoe-manualgen', "~> #{VERSION}"] unless self.name == 'hoe-manualgen' end
Generate (or refresh) a manual directory from the specified templatedir
.
# File lib/hoe/manualgen.rb, line 629 def install_manual_directory( manualdir, templatedir, include_srcdir=true ) self.manual_paths.each do |key, dir| mkpath( dir, :mode => 0755 ) end Pathname.glob( templatedir + RESOURCE_GLOB_PATTERN ).each do |tmplfile| if tmplfile.to_s =~ %r{/src/} trace "Skipping %s" % [ tmplfile ] next unless include_srcdir end # Render ERB files if tmplfile.extname == '.erb' rname = tmplfile.basename( '.erb' ) target = manualdir + tmplfile.dirname.relative_path_from( templatedir ) + rname template = ERB.new( tmplfile.read, nil, '<>' ) target.dirname.mkpath unless target.dirname.directory? html = template.result( binding() ) log "generating #{target}" target.open( File::WRONLY|File::CREAT|File::TRUNC, 0644 ) do |fh| fh.print( html ) end # Just copy anything else else target = manualdir + tmplfile.relative_path_from( templatedir ) mkpath target.dirname, :mode => 0755, :noop => $dryrun unless target.dirname.directory? install tmplfile, target, :mode => 0644, :noop => $dryrun end end end
Load the filter libraries provided in the given libdir
# File lib/hoe/manualgen.rb, line 718 def load_filter_libraries( libdir ) Pathname.glob( libdir.expand_path + '*.rb' ) do |filterlib| trace " loading filter library #{filterlib}" require( filterlib ) end end
Set up the main HTML-generation task that will convert files in the given sourcedir
to HTML in the outputdir
# File lib/hoe/manualgen.rb, line 728 def setup_page_conversion_tasks( sourcedir, outputdir, catalog ) # we need to figure out what HTML pages need to be generated so we can set up the # dependency that causes the rule to be fired for each one when the task is invoked. manual_sources = Rake::FileList[ catalog.path_index.keys.map(&:to_s) ] trace " found %d source files" % [ manual_sources.length ] # Map .page files to their equivalent .html output html_pathmap = "%%{%s,%s}X.html" % [ sourcedir, outputdir ] manual_pages = manual_sources.pathmap( html_pathmap ) trace "Mapping sources like so: \n %p -> %p" % [ manual_sources.first, manual_pages.first ] # Output directory task directory( outputdir.to_s ) file outputdir.to_s do touch outputdir + '.buildtime' end # Rule to generate .html files from .page files rule( %r{#{outputdir}/.*\.html$} => [ proc {|name| name.sub(/\.[^.]+$/, '.page').sub(outputdir.to_s, sourcedir.to_s) }, outputdir.to_s ]) do |task| source = Pathname.new( task.source ) target = Pathname.new( task.name ) log " #{ source } -> #{ target }" page = catalog.path_index[ source ] html = page.generate( self.manual_metadata ) #trace " page object is: %p" % [ page ] target.dirname.mkpath target.open( File::WRONLY|File::CREAT|File::TRUNC ) do |io| io.write( html ) end end # Group all the manual page output files targets into a containing task desc "Generate any pages of the manual that have changed" task :generate_pages => manual_pages return manual_pages end
Set up a rule for copying files from the resources directory to the output dir.
# File lib/hoe/manualgen.rb, line 791 def setup_resource_copy_tasks( resourcedir, outputdir ) glob = resourcedir + RESOURCE_GLOB_PATTERN resources = FileList[ glob.to_s ] resources.exclude( /\.svn/ ) target_pathmap = "%%{%s,%s}p" % [ resourcedir, outputdir ] targets = resources.pathmap( target_pathmap ) copier = self.method( :copy_resource ).to_proc # Create a file task to copy each file to the output directory resources.each_with_index do |resource, i| file( targets[i] => [ outputdir.to_s, resource ], &copier ) end desc "Copy API documentation to the manual output directory" task :copy_apidocs => [ outputdir.to_s, :docs ] do # Since Hoe hard-codes the 'docs' output dir, it's hard-coded # here too. apidir = outputdir + 'api' self.manual_metadata.api_dir = apidir cp_r( 'doc', apidir ) end # Now group all the resource file tasks into a containing task desc "Copy manual resources to the output directory" task :copy_resources => targets do log "Copying manual resources" end end