summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2018-07-09 09:33:02 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2018-07-09 09:33:02 +0200
commit90d7ba0cd178ca223355c8bcb1cf6c1174bee794 (patch)
tree864cf84e7481ea6da4642d2ad4b3bca5c736b745
parent6daf6b93ff54569ec3f1caf68a1a408fe95b51fc (diff)
downloadconfig-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.PL1
-rw-r--r--lib/Config/Tree.pm51
-rw-r--r--lib/Config/Tree/Locus.pm288
-rw-r--r--lib/Config/Tree/Node.pm10
-rw-r--r--lib/Config/Tree/Node/Null.pm2
-rw-r--r--lib/Config/Tree/Node/Section.pm4
-rw-r--r--t/00locus.t50
-rw-r--r--t/01conf10.t7
-rw-r--r--t/02merge.t8
-rw-r--r--t/TestConfig.pm2
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}}) {

Return to:

Send suggestions and report system problems to the System administrator.