diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2018-07-09 09:33:02 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2018-07-09 09:33:02 +0200 |
commit | 90d7ba0cd178ca223355c8bcb1cf6c1174bee794 (patch) | |
tree | 864cf84e7481ea6da4642d2ad4b3bca5c736b745 | |
parent | 6daf6b93ff54569ec3f1caf68a1a408fe95b51fc (diff) | |
download | config-ast-90d7ba0cd178ca223355c8bcb1cf6c1174bee794.tar.gz config-ast-90d7ba0cd178ca223355c8bcb1cf6c1174bee794.tar.bz2 |
Switch to Text::Locus instead of the local version
* lib/Config/Tree/Locus.pm: Remove.
* t/00locus.t: Remove.
* Makefile.PL: Require Text::Locus
* lib/Config/Tree.pm: Use Text::Locus
* lib/Config/Tree/Node.pm: Likewise.
* lib/Config/Tree/Node/Null.pm: Likewise.
* lib/Config/Tree/Node/Section.pm: Likewise.
* t/01conf10.t: Likewise.
* t/02merge.t: Likewise.
* t/TestConfig.pm: Likewise.
-rw-r--r-- | Makefile.PL | 1 | ||||
-rw-r--r-- | lib/Config/Tree.pm | 51 | ||||
-rw-r--r-- | lib/Config/Tree/Locus.pm | 288 | ||||
-rw-r--r-- | lib/Config/Tree/Node.pm | 10 | ||||
-rw-r--r-- | lib/Config/Tree/Node/Null.pm | 2 | ||||
-rw-r--r-- | lib/Config/Tree/Node/Section.pm | 4 | ||||
-rw-r--r-- | t/00locus.t | 50 | ||||
-rw-r--r-- | t/01conf10.t | 7 | ||||
-rw-r--r-- | t/02merge.t | 8 | ||||
-rw-r--r-- | t/TestConfig.pm | 2 |
10 files changed, 49 insertions, 374 deletions
diff --git a/Makefile.PL b/Makefile.PL index 56b8a16..cedef68 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -17,6 +17,7 @@ WriteMakefile(NAME => 'Config::Tree', 'File::Temp' => '0.22', 'File::stat' => 0, 'Scalar::Util' => '1.48', + 'Text::Locus' => '1.01' }, META_MERGE => { 'meta-spec' => { version => 2 }, diff --git a/lib/Config/Tree.pm b/lib/Config/Tree.pm index bb36d07..b4d2728 100644 --- a/lib/Config/Tree.pm +++ b/lib/Config/Tree.pm @@ -1,4 +1,4 @@ -# Configuration parser for Sourceyard -*- perl -*- +# Configuration file parser -*- perl -*- # Copyright (C) 2017, 2018 Sergey Poznyakoff <gray@gnu.org> # # This program is free software; you can redistribute it and/or modify @@ -19,7 +19,7 @@ package Config::Tree; use strict; use warnings; use Carp; -use Config::Tree::Locus; +use Text::Locus; use Config::Tree::Node qw(:sort); use Config::Tree::Node::Section; use Config::Tree::Node::Value; @@ -115,8 +115,8 @@ Defines the syntax table. See below for a description of B<%hash>. =head3 Syntax hash -The hash passed via the B<parameters> keyword defines the keywords and -sections allowed within a configuration file. In a simplest case, a +The hash reference passed via the B<parameters> keyword defines the keywords +and sections allowed within a configuration file. In a simplest case, a keyword is described as name => 1 @@ -134,9 +134,10 @@ Whether or not this setting is mandatory. =item default => I<VALUE> -Default value for the setting. It is assigned when entire configuration file -has been parsed, if that particular setting did not occur in it. If I<VALUE> -is a code, it will be invoked as a method each time the value is accessed. +Default value for the setting. This value will be assigned if that particular +variable is not explicilty assigned in the configuration file. If I<VALUE> +is a CODE reference, it will be invoked as a method each time the value is +accessed. Default values must be pure Perl values (not the values that should appear in the configuration file). They are not processed using the B<check> @@ -149,13 +150,14 @@ of the statement appends its value to the end of the array. =item re => I<regexp> -Defines a regular expression to which must be matched by the value of the -setting, otherwise a syntax error will be reported. +Defines a regular expression which the value must match. If it does not, +a syntax error will be reported. =item select => I<coderef> -Points to a function to be called to decide whether to apply this hash to -a particular configuration setting. The function is called as +Reference to a method which will be called in order to decide whether to +apply this hash to a particular configuration setting. The method is +called as $self->$coderef($node, @path) @@ -164,16 +166,17 @@ B<$vref-E<gt>value>, to obtain the actual value), and B<@path> is its patname. =item check => I<coderef> -Defines a code which will be called after parsing the statement in order to +Defines a method which will be called after parsing the statement in order to verify its value. The I<coderef> is called as $self->$coderef($valref, $prev_value, $locus) where B<$valref> is a reference to its value, and B<$prev_value> is the -value of the previous instance of this setting. The function must return non-0 -if the value is OK for that setting. In that case, it is allowed to modify -the value, referenced by B<$valref>. If the value is erroneous, the function -must issue an appropriate error message using B<$cfg-E<gt>error>, and return 0. +value of the previous instance of this setting. The function must return +B<true>, if the value is OK for that setting. In that case, it is allowed +to modify the value referenced by B<$valref>. If the value is erroneous, +the function must issue an appropriate error message using B<$cfg-E<gt>error>, +and return 0. =back @@ -193,11 +196,11 @@ To define a section, use the B<section> keyword, e.g.: } } -This says that a section B<[core]> can have two variables: B<pidfile>, which +This says that the section B<[core]> can have two variables: B<pidfile>, which is mandatory, and B<verbose>, whose value must be B<on>, or B<off> (case- insensitive). -To allow for arbitrary keywords, use B<*>. For example, the following +To accept arbitrary keywords, use B<*>. For example, the following declares the B<[code]> section, which must have the B<pidfile> setting and is allowed to have any other settings as well. @@ -272,7 +275,7 @@ sub reset { =head2 $cfg->error($message, locus => $loc) Prints the B<$message> on STDERR. If B<locus> is given, its value must -be a reference to a valid B<Config::Tree::Locus>(3) object. In that +be a reference to a valid B<Text::Locus>(3) object. In that case, the object will be formatted first, then followed by a ": " and the B<$message>. @@ -497,7 +500,7 @@ sub is_variable { sub tree { my $self = shift; - return $self->{_tree} //= new Config::Tree::Node::Section(locus => new Config::Tree::Locus); + return $self->{_tree} //= new Config::Tree::Node::Section(locus => new Text::Locus); } sub subtree { @@ -534,6 +537,8 @@ use constant TESTS => TAINT && defined eval 'require Taint::Util'; =head2 add_node($path, $node) + FIXME + =cut sub add_node { @@ -586,7 +591,7 @@ sub add_node { if ($node->is_section) { if ($tree->has_key($name)) { - $tree->locus->add_locus($locus); + $tree->locus->union($locus); $tree->subtree($name)->merge($node); } else { $tree->subtree($name => $node); @@ -641,11 +646,11 @@ sub add_node { } } - $tree->locus->add_locus($locus->clone); + $tree->locus->union($locus->clone); my $newnode; if ($newnode = $tree->subtree($name)) { - $newnode->locus->add_locus($locus); + $newnode->locus->union($locus); } else { $newnode = $tree->subtree($name => $node); } diff --git a/lib/Config/Tree/Locus.pm b/lib/Config/Tree/Locus.pm deleted file mode 100644 index 2d21870..0000000 --- a/lib/Config/Tree/Locus.pm +++ /dev/null @@ -1,288 +0,0 @@ -package Config::Tree::Locus; - -use strict; -use warnings; -use parent 'Exporter'; - -use Carp; -use Clone; -use Scalar::Util qw(blessed); - -=head1 NAME - -Config::Tree::Locus - source file location - -=head1 SYNOPSIS - -use Config::Tree::Locus; - -$locus = new Config::Tree::Locus; - -$locus = new Config::Tree::Locus($file, $line); - -$locus->add($file, $line); - -$s = $locus->format; - -$locus->fixup_names('old' => 'new'); - -$locus->fixup_lines(); - -print "$locus: text\n"; - -$res = $locus1 + $locus2; - -=head1 DESCRIPTION - -Provides support for manipulating source file locations. - -=head2 $locus = new Config::Tree::Locus($file, $line, ...); - -Creates a new locus object. Arguments are optional. If given, they -indicate the source file name and line numbers this locus is to represent. - -=cut - -sub new { - my $class = shift; - - my $self = bless { _table => {}, _order => 0 }, $class; - - croak "line numbers not given" if @_ == 1; - $self->add(@_) if @_ > 1; - - return $self; -} - -=head2 $obj->clone - -Creates a new B<Config::Tree::Locus> which is exact copy of B<$obj>. - -=cut - -sub clone { - my $self = shift; - return Clone::clone($self); -} - -=head2 $locus->add($file, $line, [$line1 ...]); - -Adds new location to the locus. Use this for statements spanning several -lines and/or files. - -Returns B<$locus>. - -=cut - -sub add { - my ($self, $file) = (shift, shift); - unless (exists($self->{_table}{$file})) { - $self->{_table}{$file}{_order} = $self->{_order}++; - $self->{_table}{$file}{_lines} = []; - } - push @{$self->{_table}{$file}{_lines}}, @_; - delete $self->{_string}; - return $self; -} - -=head2 $locus->add_locus($locus2); - -Adds locations from B<$locus2> to B<$locus>. - -=cut - -sub add_locus { - my ($self, $other) = @_; - croak "not the same class" - unless blessed($other) && $other->isa(__PACKAGE__); - while (my ($file, $tab) = each %{$other->{_table}}) { - $self->add($file, @{$tab->{_lines}}); - } - return $self; -} - -=head2 $s = $locus->format($msg); - -Returns a string representation of the locus. The argument is optional. -If given, its string representation will be concatenated to the formatted -locus with a ": " in between. If multiple arguments are supplied, their -string representations will be concatenated, separated by horizontal -space characters. This is useful for formatting error messages. - -If the locus contains multiple file locations, the method tries to compact -them by representing contiguous line ranges as B<I<X>-I<Y>> and outputting -each file name once. Line ranges are separated by commas. File locations -are separated by semicolons. E.g.: - - $locus = new Config::Tree::Locus("foo", 1); - $locus->add("foo", 2); - $locus->add("foo", 3); - $locus->add("foo", 5); - $locus->add("bar", 2); - $locus->add("bar", 7); - print $locus->format("here it goes"); - -will produce the following: - - foo:1-3,5;bar:2,7: here it goes - -=cut - -sub format { - my $self = shift; - unless (exists($self->{_string})) { - $self->{_string} = ''; - foreach my $file (sort { - $self->{_table}{$a}{_order} <=> $self->{_table}{$b}{_order} - } - keys %{$self->{_table}}) { - $self->{_string} .= ';' if $self->{_string}; - $self->{_string} .= "$file"; - if (my @lines = @{$self->{_table}{$file}{_lines}}) { - $self->{_string} .= ':'; - my $beg = shift @lines; - my $end = $beg; - my @ranges; - foreach my $line (@lines) { - if ($line == $end + 1) { - $end = $line; - } else { - if ($end > $beg) { - push @ranges, "$beg-$end"; - } else { - push @ranges, $beg; - } - $beg = $end = $line; - } - } - - if ($end > $beg) { - push @ranges, "$beg-$end"; - } else { - push @ranges, $beg; - } - $self->{_string} .= join(',', @ranges); - } - } - } - if (@_) { - if ($self->{_string} ne '') { - return "$self->{_string}: " . join(' ', @_); - } else { - return join(' ', @_); - } - } - return $self->{_string}; -} - -=head2 Overloaded operations - -When used in a string, the locus object formats itself. E.g. to print -a diagnostic message one can write: - - print "$locus: some text\n"; - -In fact, this method is preferred over calling B<$locus->format>. - -Two objects can be added: - - $loc1 + $loc2 - -This will produce a new Locus object containing locations from both B<loc1> -and B<$loc2>. - -Moreover, a term can also be a string in the form B<"I<file>:I<line>>: - - $loc + "file:10" - -or - - "file:10" + $loc - -=cut - -use overload - '""' => sub { shift->format() }, - '+' => sub { - my ($self, $other, $swap) = @_; - if (blessed $other) { - return $self->clone->add_locus($other); - } elsif (!ref($other) && $other =~ m/^(.+):(\d+)$/) { - if ($swap) { - return new Config::Tree::Locus($1, $2) + $self; - } else { - return $self->clone->add($1, $2); - } - } else { - croak "bad argument type in locus addition"; - } - }; - -=head2 $locus->fixup_names('foo' => 'bar', 'baz' => 'quux'); - -Replaces file names in the locations according to the arguments. - -=cut - -sub fixup_names { - my $self = shift; - local %_ = @_; - while (my ($oldname, $newname) = each %_) { - next unless exists $self->{_table}{$oldname}; - croak "target name already exist" if exists $self->{_table}{$newname}; - $self->{_table}{$newname} = delete $self->{_table}{$oldname}; - } - delete $self->{_string}; -} - -=head2 $locus->fixup_lines('foo' => 1, 'baz' => -2); - -Offsets line numbers for each named file by the given number of lines. E.g.: - - $locus = new Config::Tree::Locus("foo", 1); - $locus->add("foo", 2); - $locus->add("foo", 3); - $locus->add("bar", 3); - $locus->fixup_lines(foo => 1. bar => -1); - print $locus->format; - -will produce - - foo:2-4,bar:2 - -If given a single argument, the operation will affect all locations. E.g., -adding the following to the example above: - - $locus->fixup_lines(10); - print $locus->format; - -will produce - - foo:22-24;bar:22 - -=cut - -sub fixup_lines { - my $self = shift; - return unless @_; - if ($#_ == 0) { - my $offset = shift; - while (my ($file, $ref) = each %{$self->{_table}}) { - $ref->{_lines} = [map { $_ + $offset } @{$ref->{_lines}}]; - } - } elsif ($#_ % 2) { - local %_ = @_; - while (my ($file, $offset) = each %_) { - if (exists($self->{_table}{$file})) { - $self->{_table}{$file}{_lines} = - [map { $_ + $offset } - @{$self->{_table}{$file}{_lines}}]; - } - } - } else { - croak "bad number of arguments"; - } - delete $self->{_string}; -} - -1; diff --git a/lib/Config/Tree/Node.pm b/lib/Config/Tree/Node.pm index f836edf..24fca30 100644 --- a/lib/Config/Tree/Node.pm +++ b/lib/Config/Tree/Node.pm @@ -3,7 +3,7 @@ package Config::Tree::Node; use strict; use warnings; use parent 'Exporter'; -use Config::Tree::Locus; +use Text::Locus; use Clone 'clone'; use Carp; @@ -44,7 +44,7 @@ Sets default value. =item B<locus =E<gt>> I<LOC> -Sets the locus - an object of class B<Config::Tree::Locus>, which see. +Sets the locus - an object of class B<Text::Locus>, which see. =item B<file =E<gt>> I<NAME> @@ -102,14 +102,14 @@ sub locus { my $self = shift; if (@_ == 1) { croak "bad argument type" - unless ref($_[0]) eq 'Config::Tree::Locus'; + unless ref($_[0]) eq 'Text::Locus'; $self->{_locus} = $_[0]; } elsif (@_ == 2) { - $self->{_locus} = new Config::Tree::Locus(@_); + $self->{_locus} = new Text::Locus(@_); } elsif (@_) { croak "bad number of arguments"; } - return $self->{_locus} ||= new Config::Tree::Locus; + return $self->{_locus} ||= new Text::Locus; } =head2 $x = $node->order diff --git a/lib/Config/Tree/Node/Null.pm b/lib/Config/Tree/Node/Null.pm index f03e7a1..edf3aad 100644 --- a/lib/Config/Tree/Node/Null.pm +++ b/lib/Config/Tree/Node/Null.pm @@ -20,6 +20,8 @@ sub AUTOLOAD { sub as_string { '(null)' } +sub value { undef } + use overload bool => sub { 0 }; diff --git a/lib/Config/Tree/Node/Section.pm b/lib/Config/Tree/Node/Section.pm index 9a888c0..340bdee 100644 --- a/lib/Config/Tree/Node/Section.pm +++ b/lib/Config/Tree/Node/Section.pm @@ -46,14 +46,14 @@ sub merge { $old->merge($v); } elsif (ref($old->value) eq 'ARRAY') { push @{$old->value}, $v->value; - $old->locus->add_locus($v->locus); + $old->locus->union($v->locus); } else { $old->value($v->value); } } else { $self->subtree($k => $old->clone); } - $self->locus->add_locus($v->locus); + $self->locus->union($v->locus); } } diff --git a/t/00locus.t b/t/00locus.t deleted file mode 100644 index 0f8de52..0000000 --- a/t/00locus.t +++ /dev/null @@ -1,50 +0,0 @@ -# -*- perl -*- -use strict; -use lib qw(t lib); -use Test; -use Config::Tree::Locus; - -plan(tests => 14); - -my $loc = new Config::Tree::Locus; -ok($loc->format, ''); -ok($loc->format('test', 'message'), 'test message'); - -$loc->add('foo', 10); -ok($loc->format, "foo:10"); -ok("$loc", "foo:10"); - -$loc->add('foo', 11); -$loc->add('foo', 12); -$loc->add('foo', 13); -ok($loc->format, "foo:10-13"); - -$loc->add('foo', 24); -$loc->add('foo', 28); -ok($loc->format, "foo:10-13,24,28"); -ok($loc->format('test', 'message'), "foo:10-13,24,28: test message"); - -$loc->add('bar', 1); -$loc->add('baz', 8); -$loc->add('baz', 9); -$loc->add('bar', 5); -ok($loc->format, "foo:10-13,24,28;bar:1,5;baz:8-9"); - -$loc->fixup_names('foo' => 'Foo', 'bar' => 'BAR'); -ok($loc->format, "Foo:10-13,24,28;BAR:1,5;baz:8-9"); - -$loc->fixup_lines('Foo' => -1, 'baz' => 2); -ok($loc->format, "Foo:9-12,23,27;BAR:1,5;baz:10-11"); - -$loc->fixup_lines(3); -ok($loc->format, "Foo:12-15,26,30;BAR:4,8;baz:13-14"); - -$loc = new Config::Tree::Locus("foo", 10, 15); -ok("$loc", "foo:10,15"); - -$loc += "bar:11"; -ok("$loc", "foo:10,15;bar:11"); - -$loc = new Config::Tree::Locus("foo", 10); -my $res = "bar:1" + $loc; -ok("$res", "bar:1;foo:10"); diff --git a/t/01conf10.t b/t/01conf10.t index 5dbecc3..91fcb25 100644 --- a/t/01conf10.t +++ b/t/01conf10.t @@ -4,7 +4,7 @@ use strict; use Test; use TestConfig; -plan(tests => 1); +plan(tests => 2); my %keywords = ( base => { mandatory => 1 }, @@ -12,6 +12,9 @@ my %keywords = ( my $self = shift; return $self->get('base') . '/passwd'; } + }, + index => { + default => 0 } ); @@ -21,3 +24,5 @@ my $t = new TestConfig( ], parameters => \%keywords); ok($t->get('file'), '/etc/passwd'); +ok($t->get('index'), 0); + diff --git a/t/02merge.t b/t/02merge.t index 4c12ec4..77bf705 100644 --- a/t/02merge.t +++ b/t/02merge.t @@ -20,19 +20,19 @@ my $t = new Config::Tree( my $node = new Config::Tree::Node::Section; $node->subtree(number => new Config::Tree::Node::Value( value => [1], - locus => new Config::Tree::Locus('input',1))); + locus => new Text::Locus('input',1))); $node->subtree(name => new Config::Tree::Node::Value( value => 'foo', - locus => new Config::Tree::Locus('input',2))); + locus => new Text::Locus('input',2))); $t->add_node(x => $node); $node = new Config::Tree::Node::Section; $node->subtree(number => new Config::Tree::Node::Value( value => 2, - locus => new Config::Tree::Locus('input',3))); + locus => new Text::Locus('input',3))); $node->subtree(name => new Config::Tree::Node::Value( value => 'bar', - locus => new Config::Tree::Locus('input',4))); + locus => new Text::Locus('input',4))); $t->add_node(x => $node); ok($t->canonical(delim => ' ', locus => 1), diff --git a/t/TestConfig.pm b/t/TestConfig.pm index c566ec8..55a0aee 100644 --- a/t/TestConfig.pm +++ b/t/TestConfig.pm @@ -20,7 +20,7 @@ sub new { while (defined(my $k = shift @$config) && defined(my $v = shift @$config)) { - $self->add_value($k, $v, new Config::Tree::Locus('input', $i++)); + $self->add_value($k, $v, new Text::Locus('input', $i++)); } $self->commit; if (@{$self->{_expected_errors}}) { |