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