diff options
-rw-r--r-- | Makefile.PL | 4 | ||||
-rw-r--r-- | lib/Config/Parser.pm | 153 |
2 files changed, 155 insertions, 2 deletions
diff --git a/Makefile.PL b/Makefile.PL index cee8413..b832c66 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -24,8 +24,8 @@ WriteMakefile(NAME => 'Config::Parser', resources => { repository => { type => 'git', - url => 'git://git.gnu.org.ua/config-td.git', - web => 'http://git.gnu.org.ua/cgit/config-td.git/', + url => 'git://git.gnu.org.ua/config-parser.git', + web => 'http://git.gnu.org.ua/cgit/config-parser.git/', }, }, provides => Module::Metadata->provides(version => '1.4', diff --git a/lib/Config/Parser.pm b/lib/Config/Parser.pm index 0f0a1f0..7d20aa2 100644 --- a/lib/Config/Parser.pm +++ b/lib/Config/Parser.pm @@ -132,4 +132,157 @@ sub loadsynt { 1; +=head1 NAME + +Config::Parser - base class for configuration file parsers + +=head1 DESCRIPTION + +B<Config::Parser> provides a framework for writing configuration file +parsers. It is an intermediate layer between the abstract syntax tree +(B<Config::AST>) and implementation of a parser for a particular +configuration file format. + +It takes a I<define by example> approach. That means that the implementor +creates a derived class that implements a parser on top of B<Config::Parser>. +Application writers write an example of configuration file in the B<__DATA__> +section of their application, which defines the statements that are allowed +in a valid configuration. This example is then processed by the parser +implementation to create an instance of the parser, which is then used to +process the actual configuration file. + +Let's illustrate this on a practical example. Suppose you need a parser for +a simple configuration file, which consists of keyword/value pairs. In each +pair, the keyword is separated from the value by an equals sign. Pairs are +delimited by newlines. Leading and trailing whitespace characters on a line +are ignored as well as are empty lines. Comments begin with a hash sign and +end with a newline. + +You create the class B<Config::Parser::KV> based on B<Config::Parser>. The +method B<parser> in this class implements the actual parser. + +Application writer decides what keywords are allowed in a valid configuration +file and what are their values and puts them forth in the B<__DATA__> section +of his program (normally in a class derived from B<Config::Parser::KV>, in +the same format as the actual configuration file. For example: + + __DATA__ + basedir = STRING :mandatory + mode = OCTAL + size = NUMBER :array + +This excerpt defines a configuration with three allowed statements. Uppercase +values to the right of the equals sign are data types. Values starting with +a colon are flags that define the semantics of the values. This section +declares that three keywords are allowed. The B<basedir> keyword takes +string as its argument and must be present in a valid configuration. The +B<mode> expects octal number as its argument. The B<size> keyword takes +a number. Multiple B<size> statements are collapsed into an array. + +To parse the actual configuration file, the programmer creates an instance +of the B<Config::Parse::KV> class, passing it the name of the file as its +argument: + + $cf = new Config::Parse::KV($filename); + +This call first parses the B<__DATA__> section and builds validation rules, +then it parses the actual configuration from B<$filename>. Finally, it +applies the validation rules to the created syntax tree. If all rules pass, +the configuration is correct and the constructor returns a valid object. +Otherwise, it issues proper diagnostics and returns B<undef>. + +Upon successful return, the B<$cf> object is used to obtain the actual +configuration values as needed. + +Notice that syntax declarations in the B<__DATA__> section always follow the +actual configuration file format, that's why we call them I<definition by +example>. For instance, the syntax definition for a configuration file in +Apache-like format would look like + + __DATA__ + <section ANY> + basedir STRING :mandatory + mode OCTAL + size NUMBER :array + </section> + +=head1 CONSTRUCTOR + +=head2 $cfg = new Config::Parser(%hash) + +Creates a new parser object. Keyword arguments are: + +=over 4 + +=item B<filename> + +Name of the file to parse. This keyword must be present. + +=item B<line> + +Optional line where the configuration starts in B<filename>. It is used to +keep track of statement location in the file for correct diagnostics. If +not supplied, B<1> is assumed. + +=item B<fh> + +File handle to read from. If it is not supplied, new handle will be +created by using B<open> on the supplied filename. + +=item B<lexicon> + +Dictionary of allowed configuration statements in the file. You will not +need this parameter. It is listed here for completeness sake. Refer to +the B<Config::AST> constructor for details. + +=back + +=head1 USER HOOKS + +These are the methods provided for implementors to do any implementation- +specific tasks. Default implementations are empty placeholders. + +=head2 $cfg->init + +Called after creation of the base object, when parsing of the syntax +definition has finished. Implementors can use it to do any +implementation-specific initialization. + +=head2 $cfg->mangle + +Called after successful parsing. It can be used to modify the created +source tree. + +=head1 PARSER METHODS + +The following two methods are derived from B<Config::AST>. They are +called internally by the constructor, if the file name is supplied. + +=head2 $cfg->parse($filename, %opts) + +Parses the configuration from B<$filename>. Optional arguments are: + +=over 4 + +=item B<fh> + +File handle to read from. If it is not supplied, new handle will be +created by using B<open> on the supplied filename. + +=item B<line> + +Line to start numbering of lines from. It is used to keep track of +statement location in the file for correct diagnostics. If not supplied, +B<1> is assumed. + +=back + +=head2 $cfg->commit + +Finalizes the syntax tree. Returns true on success, and false on errors. + +=head1 SYNTAX DEFINITION + +=cut + |