rake/manual.rb in linkparser-1.0.4 vs rake/manual.rb in linkparser-1.1.0
- old
+ new
@@ -1,8 +1,8 @@
#
# Manual-generation Rake tasks and classes
-# $Id: manual.rb 95 2009-04-02 15:21:01Z deveiant $
+
#
# Authors:
# * Michael Granger <ged@FaerieMUD.org>
# * Mahlon E. Smith <mahlon@martini.nu>
#
@@ -53,12 +53,12 @@
### Export any static resources required by this filter to the given +output_dir+.
def export_resources( output_dir )
# No-op by default
end
-
+
### Process the +page+'s source with the filter and return the altered content.
def process( source, page, metadata )
raise NotImplementedError,
"%s does not implement the #process method" % [ self.class.name ]
end
@@ -67,11 +67,11 @@
### The default page configuration if none is specified.
DEFAULT_CONFIG = {
'filters' => [ 'erb', 'links', 'textile' ],
'layout' => 'default.page',
- 'cleanup' => true,
+ 'cleanup' => false,
}.freeze
# Pattern to match a source page with a YAML header
PAGE_WITH_YAML_HEADER = /
\A---\s*$ # It should should start with three hyphens
@@ -116,59 +116,64 @@
######
public
######
-
+
# The Manual::PageCatalog to which the page belongs
attr_reader :catalog
-
+
# The relative path to the base directory, for prepending to page paths
attr_reader :basepath
-
+
# The Pathname object that specifys the page source file
attr_reader :sourcefile
-
+
# The configured layouts directory as a Pathname object.
attr_reader :layouts_dir
-
+
# The page configuration, as read from its YAML header
attr_reader :config
-
+
# The raw source of the page
attr_reader :source
-
+
# The filters the page will use to render itself
attr_reader :filters
-
+
### Generate HTML output from the page and return it.
def generate( metadata )
content = self.generate_content( @source, metadata )
layout = self.config['layout'].sub( /\.page$/, '' )
templatepath = @layouts_dir + "#{layout}.page"
- template = ERB.new( templatepath.read )
- page = self
+ template = nil
+ if Object.const_defined?( :Encoding )
+ template = ERB.new( templatepath.read(:encoding => 'UTF-8') )
+ else
+ template = ERB.new( templatepath.read )
+ end
+ page = self
html = template.result( binding() )
# Use Tidy to clean up the html if 'cleanup' is turned on, but remove the Tidy
# meta-generator propaganda/advertising.
html = self.cleanup( html ).sub( %r:<meta name="generator"[^>]*tidy[^>]*/>:im, '' ) if
self.config['cleanup']
-
+
return html
end
### Return the page title as specified in the YAML options
def title
return self.config['title'] || self.sourcefile.basename
end
-
-
+
+
### Run the various filters on the given input and return the transformed
### content.
def generate_content( input, metadata )
return @filters.inject( input ) do |source, filter|
filter.process( source, self, metadata )
@@ -180,18 +185,18 @@
### a Ruby object, and return it.
def read_page_config( source )
unless source =~ PAGE_WITH_YAML_HEADER
return DEFAULT_CONFIG.dup, source
end
-
+
pageconfig = YAML.load( $1 )
source = $2
-
+
return DEFAULT_CONFIG.merge( pageconfig ), source
end
-
+
### Clean up and return the given HTML +source+.
def cleanup( source )
require 'tidy'
Tidy.path = '/usr/lib/libtidy.dylib'
@@ -206,12 +211,12 @@
end
rescue LoadError => err
trace "No cleanup: " + err.message
return source
end
-
+
### Get (singleton) instances of the filters named in +filterlist+ and return them.
def load_filters( filterlist )
filterlist.flatten.collect do |key|
raise ArgumentError, "filter '#{key}' is not loaded" unless
Manual::Page::Filter.derivatives.key?( key )
@@ -228,11 +233,11 @@
case type
when :section
items << %Q{<div class="section">}
items << %Q{<h2><a href="#{self.basepath + path}/">#{title}</a></h2>}
items << '<ul class="index-section">'
-
+
when :current_section
items << %Q{<div class="section current-section">}
items << %Q{<h2><a href="#{self.basepath + path}/">#{title}</a></h2>}
items << '<ul class="index-section current-index-section">'
@@ -265,48 +270,48 @@
### Create a new PageCatalog that will load Manual::Page objects for .page files
### in the specified +sourcedir+.
def initialize( sourcedir, layoutsdir )
@sourcedir = sourcedir
@layoutsdir = layoutsdir
-
+
@pages = []
@path_index = {}
@uri_index = {}
@title_index = {}
@hierarchy = {}
-
+
self.find_and_load_pages
end
-
-
+
+
######
public
######
# An index of the pages in the catalog by Pathname
attr_reader :path_index
-
+
# An index of the pages in the catalog by title
attr_reader :title_index
-
+
# An index of the pages in the catalog by the URI of their source relative to the source
# directory
attr_reader :uri_index
-
+
# The hierarchy of pages in the catalog, suitable for generating an on-page index
attr_reader :hierarchy
-
+
# An Array of all Manual::Page objects found
attr_reader :pages
# The Pathname location of the .page files.
attr_reader :sourcedir
-
+
# The Pathname location of look and feel templates.
attr_reader :layoutsdir
-
+
### Traverse the catalog's #hierarchy, yielding to the given +builder+
### block for each entry, as well as each time a sub-hash is entered or
### exited, setting the +type+ appropriately. Valid values for +type+ are:
###
### :entry, :section, :section_end
@@ -359,11 +364,11 @@
idx.to_s || subpath.to_s
else
trace "Using the path for the sort of directory %p" % [ subpath ]
subpath.to_s
end
-
+
# Page
else
if subpath == INDEX_PATH
trace "Sort index for index page %p is 0" % [ subpath ]
'0'
@@ -374,21 +379,21 @@
end
end
end # sort_by
end
-
+
INDEX_PATH = Pathname.new('index')
### Build up the data structures necessary for calling the +builder+ callback
### for an index section and call it, then recurse into the section contents.
def handle_section_callback( path, section, from=nil, &builder )
from_current = false
trace "Section handler: path=%p, section keys=%p, from=%s" %
[ path, section.keys, from.sourcefile ]
-
+
# Call the callback with :section -- determine the section title from
# the 'index.page' file underneath it, or the directory name if no
# index.page exists.
if section.key?( INDEX_PATH )
if section[INDEX_PATH].sourcefile.dirname == from.sourcefile.dirname
@@ -399,35 +404,35 @@
end
else
title = File.dirname( path ).gsub( /_/, ' ' )
builder.call( :section, title, path )
end
-
+
# Recurse
self.traverse_hierarchy( path, section, from, &builder )
-
+
# Call the callback with :section_end
if from_current
builder.call( :current_section_end, '', path )
else
builder.call( :section_end, '', path )
end
end
-
-
+
+
### Yield the specified +page+ to the builder
def handle_page_callback( path, page, from=nil )
if from == page
yield( :current_entry, page.title, path )
else
yield( :entry, page.title, path )
end
end
-
+
### Find and store
-
+
### Find all .page files under the configured +sourcedir+ and create a new
### Manual::Page object for each one.
def find_and_load_pages
Pathname.glob( @sourcedir + '**/*.page' ).each do |pagefile|
path_to_base = @sourcedir.relative_path_from( pagefile.dirname )
@@ -437,11 +442,11 @@
@pages << page
@path_index[ pagefile ] = page
@title_index[ page.title ] = page
@uri_index[ hierpath.to_s ] = page
-
+
# Place the page in the page hierarchy by using inject to find and/or create the
# necessary subhashes. The last run of inject will return the leaf hash in which
# the page will live
section = hierpath.dirname.split[1..-1].inject( @hierarchy ) do |hier, component|
hier[ component ] ||= {}
@@ -449,11 +454,11 @@
end
section[ pagefile.basename('.page') ] = page
end
end
-
+
end
### A Textile filter for the manual generation tasklib, implemented using RedCloth.
class TextileFilter < Manual::Page::Filter
@@ -461,12 +466,12 @@
### Load RedCloth when the filter is first created
def initialize( *args )
require 'redcloth'
super
end
-
+
### Process the given +source+ as Textile and return the resulting HTML
### fragment.
def process( source, *ignored )
formatter = RedCloth::TextileDoc.new( source )
formatter.hard_breaks = false
@@ -491,39 +496,39 @@
end
### Manual generation task library
class GenTask < Rake::TaskLib
-
+
# Default values for task config variables
DEFAULT_NAME = :manual
DEFAULT_BASE_DIR = Pathname.new( 'docs/manual' )
DEFAULT_SOURCE_DIR = 'source'
DEFAULT_LAYOUTS_DIR = 'layouts'
DEFAULT_OUTPUT_DIR = 'output'
DEFAULT_RESOURCE_DIR = 'resources'
DEFAULT_LIB_DIR = 'lib'
DEFAULT_METADATA = OpenStruct.new
-
+
### Define a new manual-generation task with the given +name+.
def initialize( name=:manual )
@name = name
@source_dir = DEFAULT_SOURCE_DIR
@layouts_dir = DEFAULT_LAYOUTS_DIR
@output_dir = DEFAULT_OUTPUT_DIR
@resource_dir = DEFAULT_RESOURCE_DIR
@lib_dir = DEFAULT_LIB_DIR
@metadata = DEFAULT_METADATA
-
+
yield( self ) if block_given?
-
+
self.define
end
-
-
+
+
######
public
######
attr_accessor :base_dir,
@@ -553,32 +558,32 @@
resourcedir = basedir + @resource_dir
libdir = basedir + @lib_dir
load_filter_libraries( libdir )
catalog = Manual::PageCatalog.new( sourcedir, layoutsdir )
-
+
# Declare the tasks outside the namespace that point in
task @name => "#@name:build"
task "clobber_#@name" => "#@name:clobber"
namespace( self.name ) do
setup_resource_copy_tasks( resourcedir, outputdir )
manual_pages = setup_page_conversion_tasks( sourcedir, outputdir, catalog )
-
+
desc "Build the manual"
- task :build => [ :rdoc, :copy_resources, :copy_apidocs, :generate_pages ]
-
+ task :build => [ :apidocs, :copy_resources, :copy_apidocs, :generate_pages ]
+
task :clobber do
RakeFileUtils.verbose( $verbose ) do
rm_f manual_pages.to_a
end
remove_dir( outputdir ) if ( outputdir + '.buildtime' ).exist?
end
-
+
desc "Remove any previously-generated parts of the manual and rebuild it"
task :rebuild => [ :clobber, self.name ]
-
+
desc "Watch for changes to the source files and rebuild when they change"
task :autobuild do
scope = [ self.name ]
loop do
t = Rake.application.lookup( :build, scope )
@@ -596,12 +601,12 @@
end
end
end
end # def define
-
-
+
+
### Load the filter libraries provided in the given +libdir+
def load_filter_libraries( libdir )
Pathname.glob( libdir + '*.rb' ) do |filterlib|
trace " loading filter library #{filterlib}"
require( filterlib )
@@ -615,11 +620,11 @@
# 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 = FileList[ catalog.path_index.keys.map {|pn| pn.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 ]
@@ -634,88 +639,88 @@
rule(
%r{#{outputdir}/.*\.html$} => [
proc {|name| name.sub(/\.[^.]+$/, '.page').sub( outputdir, sourcedir) },
outputdir.to_s
]) do |task|
-
+
source = Pathname.new( task.source )
target = Pathname.new( task.name )
log " #{ source } -> #{ target }"
-
+
page = catalog.path_index[ source ]
#trace " page object is: %p" % [ page ]
-
+
target.dirname.mkpath
target.open( File::WRONLY|File::CREAT|File::TRUNC ) do |io|
io.write( page.generate(metadata) )
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
-
-
+
+
### Copy method for resources -- passed as a block to the various file tasks that copy
### resources to the output directory.
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
-
-
+
+
### Set up a rule for copying files from the resources directory to the output dir.
def setup_resource_copy_tasks( resourcedir, outputdir )
- resources = FileList[ resourcedir + '**/*.{js,css,png,gif,jpg,html}' ]
+ resources = FileList[ resourcedir + '**/*.{js,css,png,gif,jpg,html,svg,svgz,swf}' ]
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 => :rdoc do
- cp_r( RDOCDIR, outputdir )
+ task :copy_apidocs => :apidocs do
+ cp_r( API_DOCSDIR, outputdir )
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
-
+
end # class Manual::GenTask
-
+
end
### Task: manual generation
if MANUALDIR.exist?
MANUALOUTPUTDIR = MANUALDIR + 'output'
trace "Manual will be generated in: #{MANUALOUTPUTDIR}"
-
+
begin
directory MANUALOUTPUTDIR.to_s
Manual::GenTask.new do |manual|
manual.metadata.version = PKG_VERSION
- manual.metadata.api_dir = RDOCDIR
+ manual.metadata.api_dir = API_DOCSDIR
manual.output_dir = MANUALOUTPUTDIR
manual.base_dir = MANUALDIR
manual.source_dir = 'src'
end
@@ -738,18 +743,18 @@
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
MANUALDIR.mkpath
-
+
%w[layouts lib output resources src].each do |dir|
FileUtils.mkpath( MANUALDIR + dir, :mode => 0755, :verbose => true, :noop => $dryrun )
end
-
+
Pathname.glob( TEMPLATEDIR + '**/*.{rb,css,png,js,erb,page}' ).each do |tmplfile|
trace "extname is: #{tmplfile.extname}"
-
+
# 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, '<>' )
@@ -760,10 +765,10 @@
log "generating #{target}: html => #{html[0,20]}"
target.open( File::WRONLY|File::CREAT|File::EXCL, 0644 ) do |fh|
fh.print( html )
end
-
+
# Just copy anything else
else
target = MANUALDIR + tmplfile.relative_path_from( TEMPLATEDIR )
FileUtils.mkpath target.dirname,
:mode => 0755, :verbose => true, :noop => $dryrun unless target.dirname.directory?