############################################################################### # # Class: NaturalDocs::Builder::Base # ############################################################################### # # A base class for all Builder output formats. # ############################################################################### # This file is part of Natural Docs, which is Copyright (C) 2003-2005 Greg Valure # Natural Docs is licensed under the GPL use strict; use integer; package NaturalDocs::Builder::Base; ############################################################################### # Group: Notes # # Topic: Implementation # # Builder packages are implemented as blessed arrayrefs, not hashrefs. This is done for all objects in Natural Docs for # efficiency reasons. You create members by defining constants via and using them as # indexes into the array. # # # Topic: Function Order # # The functions in the build process will always be called in the following order. # # - will always be called. # - will be called next only if there's files that need to be purged. # - will be called next only if there's indexes that need to be purged. # - will be called once for each file that needs to be built, if any. # - will be called once for each index that changed and is part of the menu, if any. # - will be called next only if the menu changed. # - will always be called. # # # Topic: 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 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. # # isn't important. You don't need to implement it. # # Implement to delete the output files associated with the purged files. # # Implement to delete the output files associated with the purged indexes. # # Implement to create an output file for the parsed source file. Use the menu function described earlier. # # Implement to create an output file for each index. Use the menu function described earlier for each page. # # Implement to go through the list of unbuilt files and update their menus. You can get the list from # 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. # # Also make sure goes through the unchanged indexes and updates them as well. # # 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. This # is how works. # # isn't important. You don't need to implement it. # # Implement to delete the output files associated with the purged files. # # Implement to delete the output files associated with the purged indexes. # # Implement to generate an output file from the parsed source file. # # Implement to generate an output file for each index. # # Implement to rebuild the menu file. # # 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 stitches them # all together into the final executable file. # # isn't important. You don't need to implement it. # # Implement to delete the intermediate files associated with the purged files. # # Implement to delete the intermediate files associated with the purged indexes. # # Implement to generate an intermediate file from the parsed source file. # # Implement to generate an intermediate file for the specified index. # # Implement to generate the intermediate file for the menu. # # Implement so that if the project changed, it stitches 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 so that if the project changed, it opens the output file and does anything it needs to do # to get ready for editing. # # Implement to remove the entries associated with the purged files. # # Implement to remove the entries associated with the purged indexes. # # Implement to add or replace a section of the output file with a new one generated from the parsed file. # # Implement to add or replace an index in the output file with a new one generated from the specified index. # # Implement 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 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 and instead rebuild the menu in if # the parameter is 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. # ############################################################################### # # Group: Required Interface Functions # # All Builder classes *must* define these functions. # # # Function: INIT # # Define this function to call Add()> so that knows about this package. # Packages are defined this way so that new ones can be added without messing around in other code. # # # Function: 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, returns 'html' so someone could use -o html [directory] to use that package. # sub CommandLineOption { NaturalDocs::Error->SoftDeath($_[0] . " didn't define CommandLineOption()."); }; # # Function: BuildFile # # 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: # # sourceFile - The name of the source file. # parsedFile - The parsed source file, as an arrayref of objects. # sub BuildFile #(sourceFile, parsedFile) { NaturalDocs::Error->SoftDeath($_[0] . " didn't define BuildFile()."); }; ############################################################################### # # Group: Optional Interface Functions # # These functions can be implemented but packages are not required to do so. # # # Function: New # # Creates and returns a new object. # # Note that this is the only function where the first parameter will be the package name, not the object itself. # sub New { my $package = shift; my $object = [ ]; bless $object, $package; return $object; }; # # Function: BeginBuild # # 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, # needs to keep the CSS files in sync regardless of whether the source tree changed or not. # # Parameters: # # hasChanged - Whether the project has changed, such as source files or the menu file. If false, nothing else is going to be # called except . # sub BeginBuild #(hasChanged) { }; # # Function: EndBuild # # 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, needs to keep the # CSS files in sync regardless of whether the source tree changed or not. # # Parameters: # # hasChanged - Whether the project has changed, such as source files or the menu file. If false, the only other function that # was called was . # sub EndBuild #(hasChanged) { }; # # Function: BuildIndex # # Define this function to create an index for the passed topic. You can get the index from # 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: # # topic - The to limit the index by. # sub BuildIndex #(topic) { }; # # Function: PurgeFiles # # Define this function to make the package remove all output related to the passed files. These files no longer have Natural Docs # content. # # Parameters: # # files - An existence hashref of the files to purge. # sub PurgeFiles #(files) { }; # # Function: PurgeIndexes # # 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: # # indexes - An existence hashref of the of the indexes to purge. # sub PurgeIndexes #(indexes) { }; # # Function: UpdateMenu # # Define this function to make the package update the menu. It will only be called if the menu changed. # sub UpdateMenu { }; 1;