File Coverage

blib/lib/Config/Dot/Array.pm
Criterion Covered Total %
statement 92 92 100.0
branch 26 26 100.0
condition 9 9 100.0
subroutine 14 14 100.0
pod 4 4 100.0
total 145 145 100.0


line stmt bran cond sub pod time code
1             package Config::Dot::Array;
2              
3 6     6   174006 use strict;
  6         12  
  6         235  
4 6     6   31 use warnings;
  6         34  
  6         327  
5              
6 6     6   3266 use Class::Utils qw(set_params);
  6         121234  
  6         132  
7 6     6   4895 use Config::Utils qw(hash_array);
  6         8446  
  6         140  
8 6     6   480 use English qw(-no_match_vars);
  6         16  
  6         36  
9 6     6   2633 use Error::Pure qw(err);
  6         10  
  6         2429  
10 6     6   33 use Readonly;
  6         11  
  6         12861  
11              
12             Readonly::Scalar my $EMPTY_STR => q{};
13              
14             our $VERSION = 0.08;
15              
16             # Constructor.
17             sub new {
18 15     15 1 1527382 my ($class, @params) = @_;
19 15         51 my $self = bless {}, $class;
20              
21             # Callback.
22 15         63 $self->{'callback'} = undef;
23              
24             # Config hash.
25 15         42 $self->{'config'} = {};
26              
27             # Set conflicts detection as error.
28 15         39 $self->{'set_conflicts'} = 1;
29              
30             # Process params.
31 15         76 set_params($self, @params);
32              
33             # Check config hash.
34 13 100       212 if (! $self->_check($self->{'config'})) {
35 3         10 err 'Bad \'config\' parameter.';
36             }
37              
38             # Check callback.
39 10 100 100     64 if (defined $self->{'callback'} && ref $self->{'callback'} ne 'CODE') {
40 1         33 err 'Parameter \'callback\' isn\'t code reference.';
41             }
42              
43             # Count of lines.
44 9         26 $self->{'count'} = 0;
45              
46             # Stack.
47 9         23 $self->{'stack'} = [];
48              
49             # Object.
50 9         57 return $self;
51             }
52              
53             # Parse text or array of texts.
54             sub parse {
55 5     5 1 31 my ($self, $string_or_array_ref) = @_;
56 5         10 my @text;
57 5 100       15 if (ref $string_or_array_ref eq 'ARRAY') {
58 2         4 @text = @{$string_or_array_ref};
  2         6  
59             } else {
60 3         39 @text = split m/$INPUT_RECORD_SEPARATOR/ms,
61             $string_or_array_ref;
62             }
63 5         13 foreach my $line (@text) {
64 12         22 $self->{'count'}++;
65 12         34 $self->_parse($line);
66             }
67 4         18 return $self->{'config'};
68             }
69              
70             # Reset content.
71             sub reset {
72 4     4 1 6385 my $self = shift;
73 4         16 $self->{'config'} = {};
74 4         9 $self->{'count'} = 0;
75 4         11 return;
76             }
77              
78             # Serialize.
79             sub serialize {
80 5     5 1 33 my $self = shift;
81 5         19 return join "\n", $self->_serialize($self->{'config'});
82             }
83              
84             # Check structure.
85             sub _check {
86 21     21   50 my ($self, $config_ref) = @_;
87 21 100       83 if (ref $config_ref eq 'HASH') {
    100          
88 15         27 foreach my $key (sort keys %{$config_ref}) {
  15         56  
89 10 100 100     61 if (ref $config_ref->{$key} ne ''
90             && ! $self->_check($config_ref->{$key})) {
91              
92 2         7 return 0;
93             }
94             }
95 13         50 return 1;
96             } elsif (ref $config_ref eq 'ARRAY') {
97 3         6 foreach my $val (@{$config_ref}) {
  3         8  
98 5 100 100     26 if (ref $val ne '' && ! $self->_check($val)) {
99 1         5 return 0;
100             }
101             }
102 2         10 return 1;
103             } else {
104 3         15 return 0;
105             }
106             }
107              
108             # Parse string.
109             sub _parse {
110 12     12   41 my ($self, $string) = @_;
111              
112             # Remove comments on single line.
113 12         34 $string =~ s/^\s*#.*$//ms;
114              
115             # Blank space.
116 12 100       56 if ($string =~ m/^\s*$/ms) {
117 2         4 return 0;
118             }
119              
120             # Split.
121 10         36 my ($key, $val) = split m/=/ms, $string, 2;
122              
123             # Not a key.
124 10 100       26 if (length $key < 1) {
125 1         2 return 0;
126             }
127              
128             # Bad key.
129 9 100       39 if ($key !~ m/^[-\w\.:,]+\+?$/ms) {
130 1         13 err "Bad key '$key' in string '$string' at line ".
131             "'$self->{'count'}'.";
132             }
133              
134 8         18 my @tmp = split m/\./ms, $key;
135 8         30 hash_array($self, \@tmp, $val);
136              
137             # Ok.
138 8         223 return 1;
139             }
140              
141             # Serialize.
142             sub _serialize {
143 12     12   24 my ($self, $config_ref) = @_;
144 12 100       44 if (ref $config_ref eq 'HASH') {
    100          
145 6         16 my @ret;
146 6         10 foreach my $key (sort keys %{$config_ref}) {
  6         19  
147             my @subkey = $self->_serialize(
148 5         43 $config_ref->{$key});
149 5         12 foreach my $subkey (@subkey) {
150 6 100       24 if ($subkey !~ m/^=/ms) {
151 1         4 $subkey = '.'.$subkey;
152             }
153 6         24 push @ret, $key.$subkey;
154             }
155             }
156 6         38 return @ret;
157             } elsif (ref $config_ref eq 'ARRAY') {
158 1         3 my @ret;
159 1         2 foreach my $val (@{$config_ref}) {
  1         4  
160 2         6 push @ret, $self->_serialize($val);
161             }
162 1         5 return @ret;
163             } else {
164 5         20 return '='.$config_ref;
165             }
166             }
167              
168             1;
169              
170             __END__