diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2019-08-20 16:02:08 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2019-08-20 16:02:08 +0300 |
commit | b3d1cf2fb648f77a6ea432486ba2a8f026068f11 (patch) | |
tree | 97e6450c863b478ec62bb25134e86e6434705e1a | |
parent | e9f110af920cf4e6642bc3301340b23a7a2a6589 (diff) | |
download | config-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.pm | 163 | ||||
-rw-r--r-- | lib/Config/Parser/Ini.pm | 174 | ||||
-rw-r--r-- | t/ConfigSpec2.pm | 3 |
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 | ||
133 | 1; | 145 | 1; |
@@ -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 |
144 | configuration file format. | 156 | configuration file format. |
145 | 157 | ||
146 | It takes a I<define by example> approach. That means that the implementor | 158 | It takes a I<define by example> approach. That means that the implementer |
147 | creates a derived class that implements a parser on top of B<Config::Parser>. | 159 | creates a derived class that implements a parser on top of B<Config::Parser>. |
148 | Application writers write an example of configuration file in the B<__DATA__> | 160 | Application writers write an example of configuration file in the B<__DATA__> |
149 | section of their application, which defines the statements that are allowed | 161 | section 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 | |||
158 | are ignored as well as are empty lines. Comments begin with a hash sign and | 170 | are ignored as well as are empty lines. Comments begin with a hash sign and |
159 | end with a newline. | 171 | end with a newline. |
160 | 172 | ||
161 | You create the class B<Config::Parser::KV> based on B<Config::Parser>. The | 173 | You create the class, say B<Config::Parser::KV>, inherited from |
162 | method B<parser> in this class implements the actual parser. | 174 | B<Config::Parser>. The method B<parser> in this class implements the actual |
175 | parser. | ||
163 | 176 | ||
164 | Application writer decides what keywords are allowed in a valid configuration | 177 | Application writer decides what keywords are allowed in a valid configuration |
165 | file and what are their values and puts them forth in the B<__DATA__> section | 178 | file and what are their values and describes them in the B<__DATA__> section |
166 | of his program (normally in a class derived from B<Config::Parser::KV>, in | 179 | of his program (normally in a class derived from B<Config::Parser::KV>, in |
167 | the same format as the actual configuration file. For example: | 180 | the 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 | ||
219 | Name of the file to parse. This keyword must be present. | 232 | Name of the file to parse. If not supplied, you will have to |
233 | call the B<$cfg-E<gt>parse> method explicitly after you are returned a | ||
234 | valid 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 | ||
242 | These are the methods provided for implementors to do any implementation- | 257 | These are the methods provided for implementers to do any implementation- |
243 | specific tasks. Default implementations are empty placeholders. | 258 | specific tasks. Default implementations are empty placeholders. |
244 | 259 | ||
245 | =head2 $cfg->init | 260 | =head2 $cfg->init |
246 | 261 | ||
247 | Called after creation of the base object, when parsing of the syntax | 262 | Called after creation of the base object, when parsing of the syntax |
248 | definition has finished. Implementors can use it to do any | 263 | definition has finished. Implementers can use it to do any |
249 | implementation-specific initialization. | 264 | implementation-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 | ||
301 | Syntax definition is a textual description of statements allowed in | ||
302 | a configuration file. It is written in the format of the configuration | ||
303 | file itself and is parsed using the same object (derivative of | ||
304 | B<Config::Parser>) that will be used later to parse the actual configuration. | ||
305 | |||
306 | Syntax definitions are gathered from the B<__DATA__> blocks of | ||
307 | subclasses of B<Config::Parser>. | ||
308 | |||
309 | In a syntax definition the value of each statement consists of optional | ||
310 | data type followed by zero or more options delimited with whitespace. | ||
311 | |||
312 | Valid data types are: | ||
313 | |||
314 | =over 4 | ||
315 | |||
316 | =item B<STRING> | ||
317 | |||
318 | String value. | ||
319 | |||
320 | =item B<NUMBER> or B<DECIMAL> | ||
321 | |||
322 | Decimal number. | ||
323 | |||
324 | =item B<OCTAL> | ||
325 | |||
326 | Octal number. | ||
327 | |||
328 | =item B<HEX> | ||
329 | |||
330 | Hex number. | ||
331 | |||
332 | =back | ||
333 | |||
334 | If the data type is omitted, no checking is performed unless specified | ||
335 | otherwise by other options (see the B<:re> and B<:check> options below). | ||
336 | |||
337 | Options are special names prefixed with a colon. Option names follow | ||
338 | the keywords from the B<Config::AST> keyword lexicon value. An option | ||
339 | can be followed by an equals sign and its value. If an option is used | ||
340 | without arguments, the value B<1> is implied. | ||
341 | |||
342 | Any word not recognized as an option or its value starts the I<default | ||
343 | value>. | ||
344 | |||
345 | Available options are described below: | ||
346 | |||
347 | =over 4 | ||
348 | |||
349 | =item B<:mandatory> | ||
350 | |||
351 | Marks the statement as a mandatory one. If such a statement is missing from | ||
352 | the configuration file, the parser action depends on whether the default value | ||
353 | is supplied. If it is, the statement will be inserted in the parse tree with | ||
354 | the default value. Otherwise, a diagnostic message will be printed and the | ||
355 | constructor will return B<undef>. | ||
356 | |||
357 | =item B<:default> | ||
358 | |||