diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2018-05-04 08:49:19 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2018-05-04 08:49:19 +0200 |
commit | 783e1a2e76f1bdc90fd72557b9117c4a5101a36f (patch) | |
tree | 0bf278403e8107fa86a80f6da392c9e81dedfd0b | |
parent | 150fc09a517fa8708690a0f9384f168a124d0a75 (diff) | |
download | config-ast-783e1a2e76f1bdc90fd72557b9117c4a5101a36f.tar.gz config-ast-783e1a2e76f1bdc90fd72557b9117c4a5101a36f.tar.bz2 |
Implement "direct addressing"
An experimental feature that allows the programmer to access configuration
settings as if they were methods of the configuration class. E.g. the
following setting
.foo.bar.baz: 45
can be accessed as
$cfg->tree->Foo->Bar->Baz
(Keyword names are capitalized to help distinguish them from the regular
methods. Also a dash in the setting name should be represented as __ when
using it as a method. Thus 'temp-dir' would become Temp__dir).
* lib/Config/Tree.pm (subtree): New method.
* lib/Config/Tree/Node.pm (is_leaf, is_null): New methods.
Overload bool, eq, and "".
* lib/Config/Tree/Node/Null.pm: New module.
* lib/Config/Tree/Node/Section.pm: Implement AUTOLOAD for accessing
settings as methods.
* lib/Config/Tree/Node/Value.pm: Implement as_string.
-rw-r--r-- | lib/Config/Tree.pm | 5 | ||||
-rw-r--r-- | lib/Config/Tree/Node.pm | 21 | ||||
-rw-r--r-- | lib/Config/Tree/Node/Null.pm | 26 | ||||
-rw-r--r-- | lib/Config/Tree/Node/Section.pm | 20 | ||||
-rw-r--r-- | lib/Config/Tree/Node/Value.pm | 5 | ||||
-rw-r--r-- | t/02conf01.t | 21 |
6 files changed, 95 insertions, 3 deletions
diff --git a/lib/Config/Tree.pm b/lib/Config/Tree.pm index e379efa..45b934b 100644 --- a/lib/Config/Tree.pm +++ b/lib/Config/Tree.pm | |||
@@ -502,6 +502,11 @@ sub tree { | |||
502 | return $self->{_tree} //= new Config::Tree::Node::Section(locus => new Config::Tree::Locus); | 502 | return $self->{_tree} //= new Config::Tree::Node::Section(locus => new Config::Tree::Locus); |
503 | } | 503 | } |
504 | 504 | ||
505 | sub subtree { | ||
506 | my $self = shift; | ||
507 | return $self->tree->subtree(@_); | ||
508 | } | ||
509 | |||
505 | sub _get_section_synt { | 510 | sub _get_section_synt { |
506 | my ($self, $kw, $name) = @_; | 511 | my ($self, $kw, $name) = @_; |
507 | 512 | ||
diff --git a/lib/Config/Tree/Node.pm b/lib/Config/Tree/Node.pm index 90fb8c4..79e105f 100644 --- a/lib/Config/Tree/Node.pm +++ b/lib/Config/Tree/Node.pm | |||
@@ -143,6 +143,16 @@ Returns true if node is a leaf node | |||
143 | 143 | ||
144 | =cut | 144 | =cut |
145 | 145 | ||
146 | sub is_leaf { 0 } | ||
147 | |||
148 | =head2 is_null | ||
149 | |||
150 | Returns true if node is a null node | ||
151 | |||
152 | =cut | ||
153 | |||
154 | sub is_null { 0 } | ||
155 | |||
146 | =head2 is_section() | 156 | =head2 is_section() |
147 | 157 | ||
148 | Returns true if node represents a section. | 158 | Returns true if node represents a section. |
@@ -151,7 +161,7 @@ Returns true if node represents a section. | |||
151 | 161 | ||
152 | sub is_section { ! shift->is_leaf } | 162 | sub is_section { ! shift->is_leaf } |
153 | 163 | ||
154 | =head2 is_section() | 164 | =head2 is_value() |
155 | 165 | ||
156 | Returns true if node represents a value (or statement). | 166 | Returns true if node represents a value (or statement). |
157 | 167 | ||
@@ -234,6 +244,15 @@ sub flatten { | |||
234 | return &{$sort}(grep { $_->[1]->is_value } @ar); | 244 | return &{$sort}(grep { $_->[1]->is_value } @ar); |
235 | } | 245 | } |
236 | 246 | ||
247 | use overload | ||
248 | bool => sub { 1 }, | ||
249 | '""' => sub { shift->as_string }, | ||
250 | eq => sub { | ||
251 | my ($self,$other) = @_; | ||
252 | return $self->as_string eq $other | ||
253 | }; | ||
254 | |||
255 | |||
237 | 1; | 256 | 1; |
238 | 257 | ||
239 | 258 | ||
diff --git a/lib/Config/Tree/Node/Null.pm b/lib/Config/Tree/Node/Null.pm new file mode 100644 index 0000000..f03e7a1 --- /dev/null +++ b/lib/Config/Tree/Node/Null.pm | |||
@@ -0,0 +1,26 @@ | |||
1 | package Config::Tree::Node::Null; | ||
2 | use parent 'Config::Tree::Node'; | ||
3 | use strict; | ||
4 | use warnings; | ||
5 | use Carp; | ||
6 | |||
7 | sub is_null { 1 } | ||
8 | |||
9 | our $AUTOLOAD; | ||
10 | |||
11 | sub AUTOLOAD { | ||
12 | my $self = shift; | ||
13 | my $key = $AUTOLOAD; | ||
14 | $key =~ s/.*:://; | ||
15 | if ($key =~ s/^([A-Z])(.*)/\l$1$2/) { | ||
16 | return $self; | ||
17 | } | ||
18 | confess "Can't locate method $AUTOLOAD"; | ||
19 | } | ||
20 | |||
21 | sub as_string { '(null)' } | ||
22 | |||
23 | use overload | ||
24 | bool => sub { 0 }; | ||
25 | |||
26 | 1; | ||
diff --git a/lib/Config/Tree/Node/Section.pm b/lib/Config/Tree/Node/Section.pm index b9d0620..8fec46b 100644 --- a/lib/Config/Tree/Node/Section.pm +++ b/lib/Config/Tree/Node/Section.pm | |||
@@ -2,6 +2,8 @@ package Config::Tree::Node::Section; | |||
2 | use parent 'Config::Tree::Node'; | 2 | use parent 'Config::Tree::Node'; |
3 | use strict; | 3 | use strict; |
4 | use warnings; | 4 | use warnings; |
5 | use Carp; | ||
6 | use Config::Tree::Node::Null; | ||
5 | 7 | ||
6 | sub new { | 8 | sub new { |
7 | my $class = shift; | 9 | my $class = shift; |
@@ -36,8 +38,6 @@ sub delete { | |||
36 | delete $self->{_subtree}{$key}; | 38 | delete $self->{_subtree}{$key}; |
37 | } | 39 | } |
38 | 40 | ||
39 | sub is_leaf { 0 } | ||
40 | |||
41 | sub merge { | 41 | sub merge { |
42 | my ($self, $other) = @_; | 42 | my ($self, $other) = @_; |
43 | while (my ($k, $v) = each %{$other->subtree}) { | 43 | while (my ($k, $v) = each %{$other->subtree}) { |
@@ -57,4 +57,20 @@ sub merge { | |||
57 | } | 57 | } |
58 | } | 58 | } |
59 | 59 | ||
60 | sub as_string { '(section)' } | ||
61 | |||
62 | our $AUTOLOAD; | ||
63 | |||
64 | sub AUTOLOAD { | ||
65 | my $self = shift; | ||
66 | my $key = $AUTOLOAD; | ||
67 | $key =~ s/.*:://; | ||
68 | if ($key =~ s/^([A-Z])(.*)/\l$1$2/) { | ||
69 | $key =~ s/__/-/g; | ||
70 | return $self->subtree($self->{_ci} ? lc($key) : $key) | ||
71 | // new Config::Tree::Node::Null; | ||
72 | } | ||
73 | confess "Can't locate method $AUTOLOAD"; | ||
74 | } | ||
75 | |||
60 | 1; | 76 | 1; |
diff --git a/lib/Config/Tree/Node/Value.pm b/lib/Config/Tree/Node/Value.pm index ee14159..c46a139 100644 --- a/lib/Config/Tree/Node/Value.pm +++ b/lib/Config/Tree/Node/Value.pm | |||
@@ -31,4 +31,9 @@ sub value { | |||
31 | 31 | ||
32 | sub is_leaf { 1 }; | 32 | sub is_leaf { 1 }; |
33 | 33 | ||
34 | sub as_string { | ||
35 | my $self = shift; | ||
36 | return $self->value | ||
37 | } | ||
38 | |||
34 | 1; | 39 | 1; |
diff --git a/t/02conf01.t b/t/02conf01.t new file mode 100644 index 0000000..b06d0dd --- /dev/null +++ b/t/02conf01.t | |||
@@ -0,0 +1,21 @@ | |||
1 | # -*- perl -*- | ||
2 | use lib qw(t lib); | ||
3 | use strict; | ||
4 | use Test; | ||
5 | use TestConfig; | ||
6 | use Data::Dumper; | ||
7 | |||
8 | plan(tests => 4); | ||
9 | |||
10 | my $t = new TestConfig( | ||
11 | config => [ | ||
12 | base => '/etc', | ||
13 | 'file.passwd.mode' => '0644', | ||
14 | 'file.passwd.root.uid' => 0, | ||
15 | 'file.passwd.root.dir' => '/root', | ||
16 | ]); | ||
17 | |||
18 | ok($t->tree->File->Passwd->Root->Dir); | ||
19 | ok($t->tree->File->Passwd->Root->Dir,'/root'); | ||
20 | ok($t->tree->File->Base->Name->is_null); | ||
21 | ok(!$t->tree->File->Base->Name); | ||