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

Modules: Logging Classes: ErbFilter, Page, PageCatalog, PageFilter, TextileFilter

Constant Summary collapse

VERSION =

Library version constant

'0.3.0'
REVISION =

Version-control revision constant

%q$Revision: cbd7dd95d043 $
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.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

def manual_base_dir
  @manual_base_dir
end

#manual_layouts_dirObject

Returns the value of attribute manual_layouts_dir.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

def manual_layouts_dir
  @manual_layouts_dir
end

#manual_lib_dirObject

Returns the value of attribute manual_lib_dir.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

def manual_lib_dir
  @manual_lib_dir
end

#manual_metadataObject

Returns the value of attribute manual_metadata.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

def 
  @manual_metadata
end

#manual_output_dirObject

Returns the value of attribute manual_output_dir.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

def manual_output_dir
  @manual_output_dir
end

#manual_pathsObject

Returns the value of attribute manual_paths.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

def manual_paths
  @manual_paths
end

#manual_resource_dirObject

Returns the value of attribute manual_resource_dir.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

def manual_resource_dir
  @manual_resource_dir
end

#manual_source_dirObject

Returns the value of attribute manual_source_dir.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

def manual_source_dir
  @manual_source_dir
end

#manual_template_dirObject

Returns the value of attribute manual_template_dir.



555
556
557
# File 'lib/hoe/manualgen.rb', line 555

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.



777
778
779
780
781
782
783
784
785
786
787
# 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_existing_manual_tasks(paths) ⇒ Object

Define tasks for generating output for an existing manual.



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
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
# 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_manual_setup_tasks(paths) ⇒ Object

Define tasks for creating a skeleton manual



610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
# 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

#define_manualgen_tasksObject

Set up the tasks for building the manual



584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
# 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

#initialize_manualgenObject

Hoe callback – set up defaults



567
568
569
570
571
572
573
574
575
576
577
578
579
580
# 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

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

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



629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
# 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_filter_libraries(libdir) ⇒ Object

Load the filter libraries provided in the given libdir



718
719
720
721
722
723
# 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

#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



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
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
# 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. )
		#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.



791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
# 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..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