aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2019-08-20 16:02:08 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2019-08-20 16:02:08 +0300
commitb3d1cf2fb648f77a6ea432486ba2a8f026068f11 (patch)
tree97e6450c863b478ec62bb25134e86e6434705e1a
parente9f110af920cf4e6642bc3301340b23a7a2a6589 (diff)
downloadconfig-parser-b3d1cf2fb648f77a6ea432486ba2a8f026068f11.tar.gz
config-parser-b3d1cf2fb648f77a6ea432486ba2a8f026068f11.tar.bz2
Provide a way for supplying options to section definition. Improve the docs
* lib/Config/Parser.pm (loadsynt): Return a reference to the reference hash. Process eventual __options__ keywords in sections. Finish documentation. * lib/Config/Parser/Ini.pm: Add documentation * t/ConfigSpec2.pm: Use the __options__ keyword.
-rw-r--r--lib/Config/Parser.pm163
-rw-r--r--lib/Config/Parser/Ini.pm174
-rw-r--r--t/ConfigSpec2.pm3
3 files changed, 320 insertions, 20 deletions
diff --git a/lib/Config/Parser.pm b/lib/Config/Parser.pm
index 7d20aa2..17a3cd0 100644
--- a/lib/Config/Parser.pm
+++ b/lib/Config/Parser.pm
@@ -31,14 +31,19 @@ sub new {
31 } else { 31 } else {
32 $self->lexicon({ '*' => '*' }); 32 $self->lexicon({ '*' => '*' });
33 my $subs = Class::Inspector->subclasses(__PACKAGE__); 33 my $subs = Class::Inspector->subclasses(__PACKAGE__);
34 my $dict;
34 if ($subs) { 35 if ($subs) {
35 foreach my $c (@$subs) { 36 foreach my $c (@$subs) {
36 if (my ($file, $line, $data) = $c->findsynt) { 37 if (my ($file, $line, $data) = $c->findsynt) {
37 $self->loadsynt($file, $line, $data); 38 my $d = $self->loadsynt($file, $line, $data);
39 if ($d) {
40 $dict = { %{$dict // {}}, %$d }
41 }
38 } 42 }
39 last if $c eq $class; 43 last if $c eq $class;
40 } 44 }
41 } 45 }
46 $self->lexicon($dict) if $dict;
42 } 47 }
43 48
44 $self->init; 49 $self->init;
@@ -85,16 +90,14 @@ sub loadsynt {
85 line => $line) 90 line => $line)
86 or croak "Failed to parse template at $file:$line"; 91 or croak "Failed to parse template at $file:$line";
87 close $fh; 92 close $fh;
88 $self->lexicon({ 93
89 %{$self->lexicon // {}}, 94 my @sections;
90 %{$self->as_hash(sub { 95 my $lex = $self->as_hash(sub {
91 my ($what, $name, $val) = @_; 96 my ($what, $name, $val) = @_;
92 $name = '*' if $name eq 'ANY'; 97 $name = '*' if $name eq 'ANY';
93 if ($what eq 'section') { 98 if ($what eq 'section') {
94 $val->{section} = {}; 99 $val->{section} = {};
95 if ($name =~ s/:mandatory$//) { 100 push @sections, $val;
96 $val->{mandatory} = 1;
97 }
98 ($name, $val->{section}); 101 ($name, $val->{section});
99 } else { 102 } else {
100 my @words = parse_line('\s+', 0, $val); 103 my @words = parse_line('\s+', 0, $val);
@@ -103,12 +106,12 @@ sub loadsynt {
103 106
104 if ($val eq 'STRING') { 107 if ($val eq 'STRING') {
105 # nothing 108 # nothing
106 } elsif ($val eq 'NUMBER') { 109 } elsif ($val eq 'NUMBER' || $val eq 'DECIMAL') {
107 $ret->{re} = '\d+'; 110 $ret->{re} = '^\d+$';
108 } elsif ($val eq 'OCTAL') { 111 } elsif ($val eq 'OCTAL') {
109 $ret->{re} = '[0-7]+'; 112 $ret->{re} = '^[0-7]+$';
110 } elsif ($val eq 'HEX') { 113 } elsif ($val eq 'HEX') {
111 $ret->{re} = '([0-9][A-Fa-f])+'; 114 $ret->{re} = '^([0-9][A-Fa-f])+$';
112 } else { 115 } else {
113 unshift @words, $val; 116 unshift @words, $val;
114 } 117 }
@@ -127,7 +130,16 @@ sub loadsynt {
127 } 130 }
128 ($name, $ret); 131 ($name, $ret);
129 } 132 }
130 })->{section}}}); 133 })->{section};
134 # Process eventual __options__ keywords
135 foreach my $s (@sections) {
136 if (exists($s->{section}{__options__})) {
137 @{$s}{keys %{$s->{section}{__options__}}}
138 = values %{$s->{section}{__options__}};
139 delete $s->{section}{__options__};
140 }
141 }
142 return $lex;
131} 143}
132 144
1331; 1451;
@@ -143,7 +155,7 @@ parsers. It is an intermediate layer between the abstract syntax tree
143(B<Config::AST>) and implementation of a parser for a particular 155(B<Config::AST>) and implementation of a parser for a particular
144configuration file format. 156configuration file format.
145 157
146It takes a I<define by example> approach. That means that the implementor 158It takes a I<define by example> approach. That means that the implementer
147creates a derived class that implements a parser on top of B<Config::Parser>. 159creates a derived class that implements a parser on top of B<Config::Parser>.
148Application writers write an example of configuration file in the B<__DATA__> 160Application writers write an example of configuration file in the B<__DATA__>
149section of their application, which defines the statements that are allowed 161section of their application, which defines the statements that are allowed
@@ -158,11 +170,12 @@ delimited by newlines. Leading and trailing whitespace characters on a line
158are ignored as well as are empty lines. Comments begin with a hash sign and 170are ignored as well as are empty lines. Comments begin with a hash sign and
159end with a newline. 171end with a newline.
160 172
161You create the class B<Config::Parser::KV> based on B<Config::Parser>. The 173You create the class, say B<Config::Parser::KV>, inherited from
162method B<parser> in this class implements the actual parser. 174B<Config::Parser>. The method B<parser> in this class implements the actual
175parser.
163 176
164Application writer decides what keywords are allowed in a valid configuration 177Application writer decides what keywords are allowed in a valid configuration
165file and what are their values and puts them forth in the B<__DATA__> section 178file and what are their values and describes them in the B<__DATA__> section
166of his program (normally in a class derived from B<Config::Parser::KV>, in 179of his program (normally in a class derived from B<Config::Parser::KV>, in
167the same format as the actual configuration file. For example: 180the same format as the actual configuration file. For example:
168 181
@@ -216,7 +229,9 @@ Creates a new parser object. Keyword arguments are:
216 229
217=item B<filename> 230=item B<filename>
218 231
219Name of the file to parse. This keyword must be present. 232Name of the file to parse. If not supplied, you will have to
233call the B<$cfg-E<gt>parse> method explicitly after you are returned a
234valid B<$cfg>.
220 235
221=item B<line> 236=item B<line>
222 237
@@ -239,13 +254,13 @@ the B<Config::AST> constructor for details.
239 254
240=head1 USER HOOKS 255=head1 USER HOOKS
241 256
242These are the methods provided for implementors to do any implementation- 257These are the methods provided for implementers to do any implementation-
243specific tasks. Default implementations are empty placeholders. 258specific tasks. Default implementations are empty placeholders.
244 259
245=head2 $cfg->init 260=head2 $cfg->init
246 261
247Called after creation of the base object, when parsing of the syntax 262Called after creation of the base object, when parsing of the syntax
248definition has finished. Implementors can use it to do any 263definition has finished. Implementers can use it to do any
249implementation-specific initialization. 264implementation-specific initialization.
250 265
251=head2 $cfg->mangle 266=head2 $cfg->mangle
@@ -283,6 +298,116 @@ Finalizes the syntax tree. Returns true on success, and false on errors.
283 298
284=head1 SYNTAX DEFINITION 299=head1 SYNTAX DEFINITION
285 300
301Syntax definition is a textual description of statements allowed in
302a configuration file. It is written in the format of the configuration
303file itself and is parsed using the same object (derivative of
304B<Config::Parser>) that will be used later to parse the actual configuration.
305
306Syntax definitions are gathered from the B<__DATA__> blocks of
307subclasses of B<Config::Parser>.
308
309In a syntax definition the value of each statement consists of optional
310data type followed by zero or more options delimited with whitespace.
311
312Valid data types are:
313
314=over 4
315
316=item B<STRING>
317
318String value.
319
320=item B<NUMBER> or B<DECIMAL>
321
322Decimal number.
323
324=item B<OCTAL>
325
326Octal number.
327
328=item B<HEX>
329
330Hex number.
331
332=back
333
334If the data type is omitted, no checking is performed unless specified
335otherwise by other options (see the B<:re> and B<:check> options below).
336
337Options are special names prefixed with a colon. Option names follow
338the keywords from the B<Config::AST> keyword lexicon value. An option
339can be followed by an equals sign and its value. If an option is used
340without arguments, the value B<1> is implied.
341
342Any word not recognized as an option or its value starts the I<default
343value>.
344
345Available options are described below:
346
347=over 4
348
349=item B<:mandatory>
350
351Marks the statement as a mandatory one. If such a statement is missing from
352the configuration file, the parser action depends on whether the default value
353is supplied. If it is, the statement will be inserted in the parse tree with
354the default value. Otherwise, a diagnostic message will be printed and the
355constructor will return B<undef>.
356
357=item B<:default>
358