NaturalDocs:: Builder:: Base

A base class for all Builder output formats. 

Summary
A base class for all Builder output formats.
The functions in the build process will always be called in the following order.
Here’s an idea of how to approach making packages for different output types.
All Builder classes must define these functions.
Define this function to call NaturalDocs::Builder::Add() so that NaturalDocs::Builder knows about this package.
Define this function to return the text that should be put in the command line after -o to use this package.
Define this function to convert a parsed file to this package’s output format.
These functions can be implemented but packages are not required to do so.
Define this function if the package needs to do anything at the beginning of the build process.
Define this function if the package needs to do anything at the end of the build process.
Define this function to create an index for the passed topic.
Define this function to make the package remove all output related to the passed files.
Define this function to make the package remove all output related to the passed indexes.
Define this function to make the package update the menu.

Notes

Function Order

The functions in the build process will always be called in the following order. 

  • BeginBuild() will always be called. 
  • PurgeFiles() will be called next only if there’s files that need to be purged. 
  • PurgeIndexes() will be called next only if there’s indexes that need to be purged. 
  • BuildFile() will be called once for each file that needs to be built, if any. 
  • BuildIndex() will be called once for each index that changed and is part of the menu, if any. 
  • UpdateMenu() will be called next only if the menu changed. 
  • EndBuild() will always be called. 

How to Approach

Here’s an idea of how to approach making packages for different output types. 

Multiple Output Files, Embedded Menu

This example is for when you want to build one output file per source file, each with its own copy of the menu within it.  This is how NaturalDocs::Builder::HTML works. 

Make sure you create a function that generates just the menu for a particular source file.  We’ll need to generate menus for both building a file from scratch and for updating the menu on an existing output file, so it’s better to give it its own function.  You may want to surround it with something that can be easily detected in the output file to make replacing easier. 

BeginBuild() isn’t important.  You don’t need to implement it. 

Implement PurgeFiles() to delete the output files associated with the purged files. 

Implement PurgeIndexes() to delete the output files associated with the purged indexes. 

Implement BuildFile() to create an output file for the parsed source file.  Use the menu function described earlier. 

Implement BuildIndex() to create an output file for each index.  Use the menu function described earlier for each page. 

Implement UpdateMenu() to go through the list of unbuilt files and update their menus.  You can get the list from NaturalDocs::Project::UnbuiltFilesWithContent().  You need to open their output files, replace the menu, and save it back to disk.  Yes, it would be simpler from a programmer’s point of view to just rebuild the file completely, but that would be very inefficient since there could potentially be a lot of files in this group.  Plus, NaturalDocs::SymbolTable may not be available to this function, so this is impossible anyway.  (Without changing the main code, that is, and I’m not going to do that because it’s grossly inefficient.  So just suck it up.) 

Also make sure UpdateMenu() goes through the unchanged indexes and updates them as well. 

EndBuild() isn’t important.  You don’t need to implement it. 

Multiple Output Files, Menu in File

This example is for when you want to build one output file per source file, but keep the menu in its own separate file.  An example would be HTML output similar to NaturalDocs::Builder::HTML but using frames. 

BeginBuild() isn’t important.  You don’t need to implement it. 

Implement PurgeFiles() to delete the output files associated with the purged files. 

Implement PurgeIndexes() to delete the output files associated with the purged indexes. 

Implement BuildFile() to generate an output file from the parsed source file. 

Implement BuildIndex() to generate an output file for each index. 

Implement UpdateMenu() to rebuild the menu file. 

EndBuild() isn’t important.  You don’t need to implement it. 

Single Output File using Intermediate Files

This example is for when you want to build one output file, such as a PDF file, but use intermediate files to handle differential building.  This would be much like how a compiler compiles each source file into a object file, and then a linker stiches them all together into the final executable file. 

BeginBuild() isn’t important.  You don’t need to implement it. 

Implement PurgeFiles() to delete the intermediate files associated with the purged files. 

Implement PurgeIndexes() to delete the intermediate files associated with the purged indexes. 

Implement BuildFile() to generate an intermediate file from the parsed source file. 

Implement BuildIndex() to generate an intermediate file for the specified index. 

Implement UpdateMenu() to generate the intermediate file for the menu. 

Implement EndBuild() so that if the project changed, it stiches the intermediate files together into the final output file.  Make sure you check the parameter because the function will be called when nothing changes too. 

Single Output File using Direct Changes

This example is for when you want to build one output file, such as a PDF file, but engineering it in such a way that you don’t need to use intermediate files.  In other words, you’re able to add, delete, and modify entries directly in the output file. 

Implement BeginBuild() so that if the project changed, it opens the output file and does anything it needs to do to get ready for editing. 

Implement PurgeFiles() to remove the entries associated with the purged files. 

Implement PurgeIndexes() to remove the entries associated with the purged indexes. 

Implement BuildFile() to add or replace a section of the output file with a new one generated from the parsed file.  You can detect whether the file is new or has changed via NaturalDocs::Project::StatusOf()

Implement BuildIndex() to add or replace an index in the output file with a new one generated from the specified index. 

Implement EndBuild() so that if the project changed, it saves the output file to disk. 

How you handle the menu depends on how the output file references other sections of itself.  If it can do so by name, then you can implement UpdateMenu() to update the menu section of the file and you’re done.  If it has to reference itself by address or offset, it gets trickier.  You should skip UpdateMenu() and instead rebuild the menu in EndBuild() if any of the parameters are true.  This lets you do it whenever anything changes in a file, rather than just when the menu visibly changes.  How you keep track of the locations and how they change is your problem. 

Required Interface Functions

All Builder classes must define these functions. 

All interface functions will be called with package->Function() notation, so remember to account for the $self parameter. 

INIT

Define this function to call NaturalDocs::Builder::Add() so that NaturalDocs::Builder knows about this package.  Packages are defined this way so that new ones can be added without messing around in other code. 

CommandLineOption

sub CommandLineOption

Define this function to return the text that should be put in the command line after -o to use this package.  It cannot have spaces and is not case sensitive. 

For example, NaturalDocs::Builder::HTML returns ‘html’ so someone could use -o html [directory] to use that package. 

BuildFile

sub BuildFile #(sourceFile, parsedFile)

Define this function to convert a parsed file to this package’s output format.  This function will be called once for every source file that needs to be rebuilt.  However, if a file hasn’t changed since the last time Natural Docs was run, it will not be sent to this function.  All packages must support differential build. 

Parameters

sourceFileThe name of the source file. 
parsedFileThe parsed source file, as an arrayref of NaturalDocs::Parser::ParsedTopic objects. 

Optional Interface Functions

These functions can be implemented but packages are not required to do so. 

All interface functios will be called with package->Function() notation, so remember to account for the $self parameter. 

BeginBuild

sub BeginBuild #(hasChanged)

Define this function if the package needs to do anything at the beginning of the build process.  This function will be called every time Natural Docs is run, even if the project hasn’t changed.  This allows you to manage dependencies specific to the output format that may change independently from the source tree and menu.  For example, NaturalDocs::Builder::HTML needs to keep the CSS files in sync regardless of whether the source tree changed or not. 

Parameters

hasChangedWhether the project has changed, such as source files or the menu file.  If false, NaturalDocs::SymbolTable and NaturalDocs::Menu won’t be available and nothing else is going to be called except EndBuild()

EndBuild

sub EndBuild #(hasChanged)

Define this function if the package needs to do anything at the end of the build process.  This function will be called every time Natural Docs is run, even if the project hasn’t changed.  This allows you to manage dependencies specific to the output format that may change independently from the source tree.  For example, NaturalDocs::Builder::HTML needs to keep the CSS files in sync regardless of whether the source tree changed or not. 

Parameters

hasChangedWhether the project has changed, such as source files or the menu file.  If false, NaturalDocs::SymbolTable and NaturalDocs::Menu won’t be available and the only other function that was called was BeginBuild()

BuildIndex

sub BuildIndex #(topic)

Define this function to create an index for the passed topic.  You can get the index from NaturalDocs::SymbolTable::Index()

The reason it’s not passed directly to this function is because indexes may be time-consuming to create.  As such, they’re generated on demand because some output packages may choose not to implement them. 

Parameters

topicThe topic to limit the index by, or undef if none.  If specified, will be one of the Topic Types

PurgeFiles

sub PurgeFiles #(files)

Define this function to make the package remove all output related to the passed files.  These files no longer have Natural Docs content. 

Parameters

filesAn existence hashref of the files to purge. 

PurgeIndexes

sub PurgeIndexes #(indexes)

Define this function to make the package remove all output related to the passed indexes.  These indexes are no longer part of the menu. 

Parameters

indexesAn existence hashref of the indexes to purge.  Each entry will be either one of the Topic Types or * for the general index. 

UpdateMenu

sub UpdateMenu

Define this function to make the package update the menu.  It will only be called if the menu changed.