Module: Hoe::ManualGen

Includes:
FileUtils, FileUtils::DryRun, FileUtils::Verbose
Defined in:
lib/hoe/manualgen.rb

Overview

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:

Defined Under Namespace

Classes: ErbFilter, Page, PageCatalog, PageFilter, TextileFilter

Constant Summary collapse

VERSION =

Library version constant

'0.1.0'
REVISION =

Version-control revision constant

%q$Revision: 0d6137980766 $
DEFAULT_BASE_DIR =

Configuration defaults

Pathname( 'manual' )
DEFAULT_SOURCE_DIR =
'src'
DEFAULT_LAYOUTS_DIR =
'layouts'
DEFAULT_OUTPUT_DIR =
'output'
DEFAULT_RESOURCE_DIR =
'resources'
DEFAULT_LIB_DIR =
'lib'
DEFAULT_METADATA =
OpenStruct.new
DEFAULT_MANUAL_TEMPLATE_DIR =
Pathname( Gem.datadir('hoe-manualgen') || 'data/hoe-manualgen' )
RESOURCE_EXTNAMES =

A glob pattern for matching resource files when copying them around

%w[ css erb gif html jpg js otf page png rb svg svgz swf ]
RESOURCE_GLOB_PATTERN =
"**/*.{%s}" % [ RESOURCE_EXTNAMES.join(',') ]
DEFAULT_MANUAL_SUBDIRS =

The subdirectories to create under the manual dir

[
	DEFAULT_SOURCE_DIR,
	DEFAULT_LAYOUTS_DIR,
	DEFAULT_OUTPUT_DIR,
	DEFAULT_RESOURCE_DIR,
	DEFAULT_LIB_DIR,
]

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#manual_base_dirObject

Returns the value of attribute manual_base_dir.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def manual_base_dir
  @manual_base_dir
end

#manual_layouts_dirObject

Returns the value of attribute manual_layouts_dir.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def manual_layouts_dir
  @manual_layouts_dir
end

#manual_lib_dirObject

Returns the value of attribute manual_lib_dir.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def manual_lib_dir
  @manual_lib_dir
end

#manual_metadataObject

Returns the value of attribute manual_metadata.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def 
  @manual_metadata
end

#manual_output_dirObject

Returns the value of attribute manual_output_dir.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def manual_output_dir
  @manual_output_dir
end

#manual_pathsObject

Returns the value of attribute manual_paths.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def manual_paths
  @manual_paths
end

#manual_resource_dirObject

Returns the value of attribute manual_resource_dir.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def manual_resource_dir
  @manual_resource_dir
end

#manual_source_dirObject

Returns the value of attribute manual_source_dir.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def manual_source_dir
  @manual_source_dir
end

#manual_template_dirObject

Returns the value of attribute manual_template_dir.



539
540
541
# File 'lib/hoe/manualgen.rb', line 539

def manual_template_dir
  @manual_template_dir
end

Instance Method Details

#copy_resource(task) ⇒ Object

Copy method for resources – passed as a block to the various file tasks that copy resources to the output directory.



761
762
763
764
765
766
767
768
769
770
771
# File 'lib/hoe/manualgen.rb', line 761

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_existing_manual_tasks(paths) ⇒ Object

Define tasks for generating output for an existing manual.



652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
# File 'lib/hoe/manualgen.rb', line 652

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_manual_setup_tasks(paths) ⇒ Object

Define tasks for creating a skeleton manual



594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
# File 'lib/hoe/manualgen.rb', line 594

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

#define_manualgen_tasksObject

Set up the tasks for building the manual



568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
# File 'lib/hoe/manualgen.rb', line 568

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

#initialize_manualgenObject

Hoe callback – set up defaults



551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/hoe/manualgen.rb', line 551

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

#install_manual_directory(manualdir, templatedir, include_srcdir = true) ⇒ Object

Generate (or refresh) a manual directory from the specified templatedir.



613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
# File 'lib/hoe/manualgen.rb', line 613

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_filter_libraries(libdir) ⇒ Object

Load the filter libraries provided in the given libdir



702
703
704
705
706
707
# File 'lib/hoe/manualgen.rb', line 702

def load_filter_libraries( libdir )
	Pathname.glob( libdir.expand_path + '*.rb' ) do |filterlib|
		trace "  loading filter library #{filterlib}"
		require( filterlib )
	end
end

#setup_page_conversion_tasks(sourcedir, outputdir, catalog) ⇒ Object

Set up the main HTML-generation task that will convert files in the given sourcedir to HTML in the outputdir



712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
# File 'lib/hoe/manualgen.rb', line 712

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. )
		#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

#setup_resource_copy_tasks(resourcedir, outputdir) ⇒ Object

Set up a rule for copying files from the resources directory to the output dir.



775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
# File 'lib/hoe/manualgen.rb', line 775

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..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