| 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__ |