From d69ba51bb8498146d07a08031de3685e6cda0768 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Fri, 23 Aug 2019 14:43:52 +0300 Subject: Implement BOOLEAN data type. --- Changes | 3 +++ lib/Config/Parser.pm | 58 +++++++++++++++++++++++++++++++++++++++++++++++----- t/ConfigSpec.pm | 1 + t/conf00.t | 3 ++- t/conf09.t | 8 ++++---- 5 files changed, 63 insertions(+), 10 deletions(-) diff --git a/Changes b/Changes index c2dfadd..39c85ac 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,8 @@ Revision history for Perl extension Config::Parser +1.03 Fri Aug 23 14:44:18 2019 + - implement the BOOLEAN data type + 1.02 Thu Aug 22 09:47:42 2019 - use mro to track descendant classes diff --git a/lib/Config/Parser.pm b/lib/Config/Parser.pm index 0c771ed..bd230b5 100644 --- a/lib/Config/Parser.pm +++ b/lib/Config/Parser.pm @@ -7,7 +7,7 @@ use Cwd qw(abs_path); use Text::ParseWords; use mro; -our $VERSION = "1.02"; +our $VERSION = "1.03"; sub new { my $class = shift; @@ -112,6 +112,8 @@ sub loadsynt { $ret->{re} = '^[0-7]+$'; } elsif ($val eq 'HEX') { $ret->{re} = '^([0-9][A-Fa-f])+$'; + } elsif ($val =~ /^BOOL(EAN)?$/) { + $ret->{check} = \&check_bool; } else { unshift @words, $val; } @@ -142,6 +144,29 @@ sub loadsynt { return $lex; } +sub check_bool { + my ($self, $valref, undef, $locus) = @_; + my %bv = ( + yes => 1, + no => 0, + true => 1, + false => 0, + on => 1, + off => 0, + t => 1, + nil => 0, + 1 => 1, + 0 => 0 + ); + + if (exists($bv{$$valref})) { + $$valref = $bv{$$valref}; + return 1; + } + $self->error("$$valref is not a valid boolean value", locus => $locus); + return 0; +} + 1; =head1 NAME @@ -202,7 +227,7 @@ 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. +Otherwise, it issues proper diagnostics and croaks. Upon successful return, the B<$cf> object is used to obtain the actual configuration values as needed. @@ -229,9 +254,12 @@ Creates a new parser object. Keyword arguments are: =item B -Name of the file to parse. If not supplied, you will have to -call the B<$cfg-Eparse> method explicitly after you are returned a -valid B<$cfg>. +Name of the file to parse. If supplied, the constructor will call +the B and B methods automatically and will croak if +the latter returns false. The B method is given B, +B and B keyword-value pairs (if present) as its arguments. + +If not supplied, the caller is supposed to call both methods later. =item B @@ -239,11 +267,15 @@ Optional line where the configuration starts in B. It is used to keep track of statement location in the file for correct diagnostics. If not supplied, B<1> is assumed. +Valid only together with B. + =item B File handle to read from. If it is not supplied, new handle will be created by using B on the supplied filename. +Valid only together with B. + =item B Dictionary of allowed configuration statements in the file. You will not @@ -329,6 +361,12 @@ Octal number. Hex number. +=item B or B + +Boolean value. Allowed values are: +B, B, B, B, B<1>, for C and +B, B, B, B, B<0>, for C. + =back If the data type is omitted, no checking is performed unless specified @@ -404,6 +442,16 @@ To specify options for a section, use the reserved keyword B<__options__>. Its value is the list of options as described above. After processing, the keyword itself is removed from the lexicon. +=head1 OTHER METHODS + +=head2 $cfg->check($valref, $prev, $locus) + +This method implements syntax checking and translation for C data +types. If B<$$valref> is one of the valid boolean values (as described +above), it translates it to B<1> or B<0>, stores that value in B<$valref>, +and returns 1. Otherwise, it emits error message using B<$cfg->error> and +returns 0. + =head1 SEE ALSO B(3). diff --git a/t/ConfigSpec.pm b/t/ConfigSpec.pm index 30812ed..b94c1df 100644 --- a/t/ConfigSpec.pm +++ b/t/ConfigSpec.pm @@ -16,6 +16,7 @@ __DATA__ base = STRING :mandatory null number = NUMBER :array size = STRING :re='\d+(?:(?i) *[kmg])' + enable = BOOL [load] file = STRING :check=_check_abs_name :mandatory ANY = STRING diff --git a/t/conf00.t b/t/conf00.t index b497c86..1ee18c5 100644 --- a/t/conf00.t +++ b/t/conf00.t @@ -8,7 +8,7 @@ plan(tests => 1); my $c = new ConfigSpec; ok($c->canonical, - q{core.base=4 core.number=[5,10] core.size="10 k" load.file="/etc/passwd" load.foobar="baz"}); + q{core.base=4 core.enable=1 core.number=[5,10] core.size="10 k" load.file="/etc/passwd" load.foobar="baz"}); __DATA__ [core] @@ -16,6 +16,7 @@ __DATA__ base = 4 size = 10 k number = 10 + enable = true [load] file = /etc/passwd foobar = baz diff --git a/t/conf09.t b/t/conf09.t index c533747..66f8c60 100644 --- a/t/conf09.t +++ b/t/conf09.t @@ -2,16 +2,16 @@ use lib qw(t lib); use strict; use Test; -use ConfigSpec; +use ConfigSpec2; use ConfigSpec3; plan(tests => 2); -my $c = new ConfigSpec; +my $c2 = new ConfigSpec2; my $c3 = new ConfigSpec3; -ok($c->canonical_lexicon, - q{{"core" => {"section" => {"base" => {"default" => "null","mandatory" => 1},"number" => {"array" => 1,"re" => "^\\\\d+\\$"},"size" => {"re" => "\\\\d+(?:(?i) *[kmg])"}}},"load" => {"section" => {"*" => {},"file" => {"check" => "_check_abs_name","mandatory" => 1}}}}}); +ok($c2->canonical_lexicon, + q{{"core" => {"section" => {"base" => {"default" => "null","mandatory" => 1}}},"load" => {"section" => {"*" => {"section" => {"param" => {"mandatory" => 1,"section" => {"mode" => {"re" => "^[0-7]+\$"},"owner" => {}}}}}}}}}); ok($c3->canonical_lexicon, q{{"core" => {"section" => {"root" => {"mandatory" => 1}}},"dir" => {"section" => {"diag" => {},"store" => {},"temp" => {}}}}}); -- cgit v1.2.1