File Coverage

blib/lib/Config/INI/Serializer.pm
Criterion Covered Total %
statement 85 95 89.4
branch 43 66 65.1
condition 6 12 50.0
subroutine 11 11 100.0
pod 3 3 100.0
total 148 187 79.1


line stmt bran cond sub pod time code
1             package Config::INI::Serializer;
2             BEGIN {
3 1     1   40589 $Config::INI::Serializer::AUTHORITY = 'cpan:SCHWIGON';
4             }
5             $Config::INI::Serializer::VERSION = '0.002';
6 1     1   25 use 5.006;
  1         3  
7 1     1   5 use strict;
  1         1  
  1         17  
8 1     1   5 use warnings;
  1         1  
  1         801  
9              
10             # ABSTRACT: Round-trip INI serializer for nested data
11              
12              
13             # lightweight OO to the extreme, as we really don't need more
14             sub new {
15 3     3 1 4053 bless {}, shift;
16             }
17              
18             # utility method, stolen from App::Reference, made internal here
19             sub _get_branch {
20 644     644   1049 my ($self, $branch_name, $create, $ref) = @_;
21 644         652 my ($sub_branch_name, $branch_piece, $attrib, $type, $branch, $cache_ok);
22 644 50       1123 $ref = $self if (!defined $ref);
23              
24             # check the cache quickly and return the branch if found
25 644   33     2173 $cache_ok = (ref($ref) ne "ARRAY" && $ref eq $self); # only cache from $self
26 644 50       970 $branch = $ref->{_branch}{$branch_name} if ($cache_ok);
27 644 50       971 return ($branch) if (defined $branch);
28              
29             # not found, so we need to parse the $branch_name and walk the $ref tree
30 644         591 $branch = $ref;
31 644         669 $sub_branch_name = "";
32              
33             # these: "{field1}" "[3]" "field2." are all valid branch pieces
34 644         2245 while ($branch_name =~ s/^([\{\[]?)([^\.\[\]\{\}]+)([\.\]\}]?)//) {
35              
36 1784         2549 $branch_piece = $2;
37 1784         2043 $type = $3;
38 1784 100       4312 $sub_branch_name .= ($3 eq ".") ? "$1$2" : "$1$2$3";
39              
40 1784 50       2777 if (ref($branch) eq "ARRAY") {
41 0 0       0 if (! defined $branch->[$branch_piece]) {
42 0 0       0 if ($create) {
43 0 0       0 $branch->[$branch_piece] = ($type eq "]") ? [] : {};
44 0         0 $branch = $branch->[$branch_piece];
45 0 0       0 $ref->{_branch}{$sub_branch_name} = $branch if ($cache_ok);
46             }
47             else {
48 0         0 return(undef);
49             }
50             }
51             else {
52 0         0 $branch = $branch->[$branch_piece];
53 0         0 $sub_branch_name .= "$1$2$3"; # accumulate the $sub_branch_name
54             }
55             }
56             else {
57 1784 100       2907 if (! defined $branch->{$branch_piece}) {
58 58 50       76 if ($create) {
59 58 50       139 $branch->{$branch_piece} = ($type eq "]") ? [] : {};
60 58         80 $branch = $branch->{$branch_piece};
61 58 50       115 $ref->{_branch}{$sub_branch_name} = $branch if ($cache_ok);
62             }
63             else {
64 0         0 return(undef);
65             }
66             }
67             else {
68 1726         2373 $branch = $branch->{$branch_piece};
69             }
70             }
71 1784 100       6812 $sub_branch_name .= $type if ($type eq ".");
72             }
73 644         1309 return $branch;
74             }
75              
76             # utility method, stolen from App::Reference, made internal here
77             sub _set {
78 664     664   934 my ($self, $property_name, $property_value, $ref) = @_;
79             #$ref = $self if (!defined $ref);
80              
81 664         635 my ($branch_name, $attrib, $type, $branch, $cache_ok);
82 664 100       2151 if ($property_name =~ /^(.*)([\.\{\[])([^\.\[\]\{\}]+)([\]\}]?)$/) {
83 644         896 $branch_name = $1;
84 644         762 $type = $2;
85 644         780 $attrib = $3;
86 644   33     2311 $cache_ok = (ref($ref) ne "ARRAY" && $ref eq $self);
87 644 50       1002 $branch = $ref->{_branch}{$branch_name} if ($cache_ok);
88 644 50       1641 $branch = $self->_get_branch($1,1,$ref) if (!defined $branch);
89             }
90             else {
91 20         22 $branch = $ref;
92 20         23 $attrib = $property_name;
93             }
94              
95 664 50       1113 if (ref($branch) eq "ARRAY") {
96 0         0 $branch->[$attrib] = $property_value;
97             }
98             else {
99 664         1776 $branch->{$attrib} = $property_value;
100             }
101             }
102              
103             # the serialize frontend method
104             sub serialize {
105 1     1 1 2 my ($self, $data) = @_;
106 1         6 $self->_serialize($data, "");
107             }
108              
109             # recursive serialize method doing the actual work, internal
110             sub _serialize {
111 30     30   40 my ($self, $data, $section) = @_;
112 30         27 my ($section_data, $idx, $key, $elem);
113 30 100       76 if (ref($data) eq "ARRAY") {
    50          
114 7         17 for ($idx = 0; $idx <= $#$data; $idx++) {
115 24         27 $elem = $data->[$idx];
116 24 100       66 if (!ref($elem)) {
117 2 50 33     12 $section_data .= "[$section]\n" if (!$section_data && $section);
118 2         6 $section_data .= "$idx = $elem\n";
119             }
120             }
121 7         16 for ($idx = 0; $idx <= $#$data; $idx++) {
122 24         30 $elem = $data->[$idx];
123 24 100       47 if (ref($elem)) {
124 22 50       85 $section_data .= $self->_serialize($elem, $section ? "$section.$idx" : $idx);
125             }
126             }
127             }
128             elsif (ref($data)) {
129 23         150 foreach $key (sort keys %$data) {
130 337         399 $elem = $data->{$key};
131 337 100       551 if (!ref($elem)) {
132 1     1   6 no warnings 'uninitialized';
  1         2  
  1         389  
133 330 100 100     650 $section_data .= "[$section]\n" if (!$section_data && $section);
134 330         557 $section_data .= "$key = $elem\n";
135             }
136             }
137 23         143 foreach $key (sort keys %$data) {
138 337         345 $elem = $data->{$key};
139 337 100       537 if (ref($elem)) {
140 7 100       28 $section_data .= $self->_serialize($elem, $section ? "$section.$key" : $key);
141             }
142             }
143             }
144              
145 30         202 return $section_data;
146             }
147              
148             # the deserialize frontend method
149             sub deserialize {
150 2     2 1 4 my ($self, $inidata) = @_;
151 2         2 my ($data, $r, $line, $attrib_base, $attrib, $value);
152              
153 2         4 $data = {};
154              
155 2         4 $attrib_base = "";
156 2         130 foreach $line (split(/\n/, $inidata)) {
157 712 50       1319 next if ($line =~ /^;/); # ignore comments
158 712 50       1126 next if ($line =~ /^#/); # ignore comments
159 712 100       1298 if ($line =~ /^\[([^\[\]]+)\] *$/) { # i.e. [Repository.default]
160 48         72 $attrib_base = $1;
161             }
162 712 100       2500 if ($line =~ /^ *([^ =]+) *= *(.*)$/) {
163 664 100       1714 $attrib = $attrib_base ? "$attrib_base.$1" : $1;
164 664         914 $value = $2;
165 664         1175 $self->_set($attrib, $value, $data);
166             }
167             }
168 2         52 return $data;
169             }
170              
171             # END of stolen ::App::Serialize::Ini
172              
173             1;
174              
175             __END__