File Coverage

blib/lib/Config/INI/Serializer.pm
Criterion Covered Total %
statement 83 93 89.2
branch 43 66 65.1
condition 6 12 50.0
subroutine 10 10 100.0
pod 2 3 66.6
total 144 184 78.2


line stmt bran cond sub pod time code
1             package Config::INI::Serializer;
2             BEGIN {
3 1     1   41591 $Config::INI::Serializer::AUTHORITY = 'cpan:SCHWIGON';
4             }
5             {
6             $Config::INI::Serializer::VERSION = '0.001';
7             }
8              
9 1     1   8 use strict;
  1         2  
  1         24  
10 1     1   4 use warnings;
  1         1  
  1         707  
11              
12             # ABSTRACT: Round-trip INI serializer for nested data
13              
14              
15             # lightweight OO to the extreme, as we really don't need more
16             sub new {
17 3     3 0 6754 bless {}, shift;
18             }
19              
20             # utility method, stolen from App::Reference, made internal here
21             sub _get_branch {
22 644     644   1516 my ($self, $branch_name, $create, $ref) = @_;
23 644         655 my ($sub_branch_name, $branch_piece, $attrib, $type, $branch, $cache_ok);
24 644 50       1297 $ref = $self if (!defined $ref);
25              
26             # check the cache quickly and return the branch if found
27 644   33     22843 $cache_ok = (ref($ref) ne "ARRAY" && $ref eq $self); # only cache from $self
28 644 50       1151 $branch = $ref->{_branch}{$branch_name} if ($cache_ok);
29 644 50       1185 return ($branch) if (defined $branch);
30              
31             # not found, so we need to parse the $branch_name and walk the $ref tree
32 644         1748 $branch = $ref;
33 644         831 $sub_branch_name = "";
34              
35             # these: "{field1}" "[3]" "field2." are all valid branch pieces
36 644         6477 while ($branch_name =~ s/^([\{\[]?)([^\.\[\]\{\}]+)([\.\]\}]?)//) {
37              
38 1784         3627 $branch_piece = $2;
39 1784         2452 $type = $3;
40 1784 100       5620 $sub_branch_name .= ($3 eq ".") ? "$1$2" : "$1$2$3";
41              
42 1784 50       3314 if (ref($branch) eq "ARRAY") {
43 0 0       0 if (! defined $branch->[$branch_piece]) {
44 0 0       0 if ($create) {
45 0 0       0 $branch->[$branch_piece] = ($type eq "]") ? [] : {};
46 0         0 $branch = $branch->[$branch_piece];
47 0 0       0 $ref->{_branch}{$sub_branch_name} = $branch if ($cache_ok);
48             }
49             else {
50 0         0 return(undef);
51             }
52             }
53             else {
54 0         0 $branch = $branch->[$branch_piece];
55 0         0 $sub_branch_name .= "$1$2$3"; # accumulate the $sub_branch_name
56             }
57             }
58             else {
59 1784 100       4223 if (! defined $branch->{$branch_piece}) {
60 58 50       95 if ($create) {
61 58 50       218 $branch->{$branch_piece} = ($type eq "]") ? [] : {};
62 58         90 $branch = $branch->{$branch_piece};
63 58 50       127 $ref->{_branch}{$sub_branch_name} = $branch if ($cache_ok);
64             }
65             else {
66 0         0 return(undef);
67             }
68             }
69             else {
70 1726         3119 $branch = $branch->{$branch_piece};
71             }
72             }
73 1784 100       20336 $sub_branch_name .= $type if ($type eq ".");
74             }
75 644         3029 return $branch;
76             }
77              
78             # utility method, stolen from App::Reference, made internal here
79             sub _set {
80 664     664   1548 my ($self, $property_name, $property_value, $ref) = @_;
81             #$ref = $self if (!defined $ref);
82              
83 664         705 my ($branch_name, $attrib, $type, $branch, $cache_ok);
84 664 100       4814 if ($property_name =~ /^(.*)([\.\{\[])([^\.\[\]\{\}]+)([\]\}]?)$/) {
85 644         1270 $branch_name = $1;
86 644         1236 $type = $2;
87 644         866 $attrib = $3;
88 644   33     3345 $cache_ok = (ref($ref) ne "ARRAY" && $ref eq $self);
89 644 50       1277 $branch = $ref->{_branch}{$branch_name} if ($cache_ok);
90 644 50       2271 $branch = $self->_get_branch($1,1,$ref) if (!defined $branch);
91             }
92             else {
93 20         23 $branch = $ref;
94 20         24 $attrib = $property_name;
95             }
96              
97 664 50       2540 if (ref($branch) eq "ARRAY") {
98 0         0 $branch->[$attrib] = $property_value;
99             }
100             else {
101 664         3007 $branch->{$attrib} = $property_value;
102             }
103             }
104              
105             # the serialize frontend method
106             sub serialize {
107 1     1 1 3 my ($self, $data) = @_;
108 1         5 $self->_serialize($data, "");
109             }
110              
111             # recursive serialize method doing the actual work, internal
112             sub _serialize {
113 30     30   44 my ($self, $data, $section) = @_;
114 30         30 my ($section_data, $idx, $key, $elem);
115 30 100       170 if (ref($data) eq "ARRAY") {
    50          
116 7         23 for ($idx = 0; $idx <= $#$data; $idx++) {
117 24         33 $elem = $data->[$idx];
118 24 100       71 if (!ref($elem)) {
119 2 50 33     13 $section_data .= "[$section]\n" if (!$section_data && $section);
120 2         7 $section_data .= "$idx = $elem\n";
121             }
122             }
123 7         18 for ($idx = 0; $idx <= $#$data; $idx++) {
124 24         42 $elem = $data->[$idx];
125 24 100       104 if (ref($elem)) {
126 22 50       85 $section_data .= $self->_serialize($elem, $section ? "$section.$idx" : $idx);
127             }
128             }
129             }
130             elsif (ref($data)) {
131 23         404 foreach $key (sort keys %$data) {
132 337         539 $elem = $data->{$key};
133 337 100       579 if (!ref($elem)) {
134 1     1   7 no warnings 'uninitialized';
  1         2  
  1         379  
135 330 100 100     675 $section_data .= "[$section]\n" if (!$section_data && $section);
136 330         1013 $section_data .= "$key = $elem\n";
137             }
138             }
139 23         254 foreach $key (sort keys %$data) {
140 337         661 $elem = $data->{$key};
141 337 100       562 if (ref($elem)) {
142 7 100       42 $section_data .= $self->_serialize($elem, $section ? "$section.$key" : $key);
143             }
144             }
145             }
146              
147 30         734 return $section_data;
148             }
149              
150             # the deserialize frontend method
151             sub deserialize {
152 2     2 1 6 my ($self, $inidata) = @_;
153 2         4 my ($data, $r, $line, $attrib_base, $attrib, $value);
154              
155 2         5 $data = {};
156              
157 2         5 $attrib_base = "";
158 2         235 foreach $line (split(/\n/, $inidata)) {
159 712 50       2862 next if ($line =~ /^;/); # ignore comments
160 712 50       1832 next if ($line =~ /^#/); # ignore comments
161 712 100       1899 if ($line =~ /^\[([^\[\]]+)\] *$/) { # i.e. [Repository.default]
162 48         175 $attrib_base = $1;
163             }
164 712 100       6887 if ($line =~ /^ *([^ =]+) *= *(.*)$/) {
165 664 100       1974 $attrib = $attrib_base ? "$attrib_base.$1" : $1;
166 664         2097 $value = $2;
167 664         1627 $self->_set($attrib, $value, $data);
168             }
169             }
170 2         75 return $data;
171             }
172              
173             # END of stolen ::App::Serialize::Ini
174              
175             1;
176              
177             __END__