| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Config::NameValue; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | # ABSTRACT: Round trip simple name/value config file handling. | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | # VERSION | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 2 |  |  | 2 |  | 206913 | use strict; | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 70 |  | 
| 9 | 2 |  |  | 2 |  | 10 | use warnings; | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 49 |  | 
| 10 | 2 |  |  | 2 |  | 9491 | use namespace::autoclean; | 
|  | 2 |  |  |  |  | 48766 |  | 
|  | 2 |  |  |  |  | 15 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 | 2 |  |  | 2 |  | 140 | use Carp; | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 149 |  | 
| 13 | 2 |  |  | 2 |  | 1151 | use File::Slurp qw( slurp ); | 
|  | 2 |  |  |  |  | 25976 |  | 
|  | 2 |  |  |  |  | 169 |  | 
| 14 | 2 |  |  | 2 |  | 18 | use Scalar::Util qw( blessed ); | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 139 |  | 
| 15 | 2 |  |  | 2 |  | 12 | use POSIX qw( strftime ); | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 26 |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | our $VERSION = 1.00; | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | {  # Quick! Hide! | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | my $error; | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | sub new { | 
| 25 |  |  |  |  |  |  |  | 
| 26 | 4 |  |  | 4 | 1 | 25807 | my ( $class, $file ) = @_; | 
| 27 |  |  |  |  |  |  |  | 
| 28 | 4 | 100 | 66 |  |  | 73 | croak 'Calling new as a function is not supported' | 
| 29 |  |  |  |  |  |  | unless $class && $class ne ''; | 
| 30 |  |  |  |  |  |  |  | 
| 31 | 3 |  | 33 |  |  | 22 | my $self = bless {}, ref $class || $class; | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 3 | 100 | 66 |  |  | 23 | $self->load( $file ) | 
| 34 |  |  |  |  |  |  | if $file && $file ne ''; | 
| 35 |  |  |  |  |  |  |  | 
| 36 | 3 |  |  |  |  | 21 | return $self; | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | sub load { | 
| 42 |  |  |  |  |  |  |  | 
| 43 | 5 |  |  | 5 | 1 | 19441 | my ( $self, $file ) = @_; | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 5 | 100 |  |  |  | 41 | croak 'Calling load as a function is not supported' | 
| 46 |  |  |  |  |  |  | unless blessed $self; | 
| 47 |  |  |  |  |  |  |  | 
| 48 | 4 | 100 | 66 |  |  | 31 | if ( ! $file || $file eq '' ) { | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | croak 'No file to load' | 
| 51 | 1 | 50 | 33 |  |  | 27 | unless exists $self->{ file } && $self->{ file } ne ''; | 
| 52 |  |  |  |  |  |  |  | 
| 53 | 0 |  |  |  |  | 0 | $file = $self->{ file }; | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  |  | 
| 57 | 3 |  |  |  |  | 22 | my @lines = slurp( $file, { chomp => 1 } ); | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 2 |  |  |  |  | 423 | for ( my $i = 0 ; $i < @lines ; $i++ ) { | 
| 60 |  |  |  |  |  |  |  | 
| 61 | 18 |  |  |  |  | 30 | my $line = $lines[ $i ]; | 
| 62 |  |  |  |  |  |  |  | 
| 63 | 18 | 100 |  |  |  | 92 | next if $line =~ /^\s*(#.*)?$/;  # Ignore blank lines and comment lines | 
| 64 | 8 |  |  |  |  | 24 | $line =~ s/(? | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 8 |  |  |  |  | 51 | $line =~ s/^\s*(.*?)\s*$/$1/;    # Strip leading and trailing whitespace | 
| 67 |  |  |  |  |  |  |  | 
| 68 | 8 |  |  |  |  | 39 | my @data = split /\s*=\s*/, $line, 2; | 
| 69 | 8 |  |  |  |  | 34 | $data[ 0 ] =~ s/^\s*(.*)/$1/; | 
| 70 | 8 |  |  |  |  | 18 | $data[ 1 ] =~ s/^(["'])(.*)\1$/$2/; | 
| 71 | 8 |  |  |  |  | 14 | $data[ 1 ] =~ s/\\#/#/g; | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 8 |  |  |  |  | 58 | $self->{ name }{ $data[ 0 ] } = { value => $data[ 1 ], line => $i, modified => 0 }; | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 2 |  |  |  |  | 6 | $self->{ file }     = $file; | 
| 78 | 2 |  |  |  |  | 33 | $self->{ lines }    = \@lines; | 
| 79 | 2 |  |  |  |  | 7 | $self->{ count }    = scalar @lines; | 
| 80 | 2 |  |  |  |  | 4 | $self->{ modified } = 0; | 
| 81 |  |  |  |  |  |  |  | 
| 82 | 2 |  |  |  |  | 8 | return 1; | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | } ## end sub load | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | sub save { | 
| 88 |  |  |  |  |  |  |  | 
| 89 | 4 |  |  | 4 | 1 | 11301 | my ( $self, $file ) = @_; | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 4 | 100 |  |  |  | 33 | croak 'Calling save as a function is not supported' | 
| 92 |  |  |  |  |  |  | unless blessed $self; | 
| 93 |  |  |  |  |  |  |  | 
| 94 | 3 | 100 | 66 |  |  | 30 | if ( ! $file || $file eq '' ) { | 
|  |  | 100 |  |  |  |  |  | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | croak 'No file to save' | 
| 97 | 1 | 50 | 33 |  |  | 18 | unless exists $self->{ file } && $self->{ file } ne ''; | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 0 |  |  |  |  | 0 | $file = $self->{ file }; | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | } elsif ( $file eq $self->{ file } ) { | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | croak 'No changes, not saving' | 
| 104 | 1 | 50 |  |  |  | 22 | unless $self->{ modified }; | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | } | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 1 | 50 |  |  |  | 6 | if ( $self->{ modified } ) { | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 0 |  |  |  |  | 0 | my @modified = grep { $self->{ name }{ $_ }{ modified } } keys %{ $self->{ name } }; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 0 |  |  |  |  | 0 | for my $name ( @modified ) { | 
| 113 |  |  |  |  |  |  |  | 
| 114 | 0 |  |  |  |  | 0 | my ( $value, $line ) = @{ $self->{ name }{ $name } }{ qw( value line ) }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 115 | 0 |  |  |  |  | 0 | $self->{ lines }[ $line ] =~ s/^(\s*(["'])$name\2\s*=\s*)(["'])(?:.*)\3\s*$/$1$3$value$3/; | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  |  | 
| 120 | 1 |  |  |  |  | 4 | my $work_file = "$file.work"; | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 1 |  |  |  |  | 1435 | require IO::Handle; | 
| 123 |  |  |  |  |  |  |  | 
| 124 | 1 | 50 |  |  |  | 10701 | open my $FH, '>', $work_file | 
| 125 |  |  |  |  |  |  | or croak "Unable to open $work_file: $!"; | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 1 |  |  |  |  | 3 | print $FH "$_\n" for @{ $self->{ lines } }; | 
|  | 1 |  |  |  |  | 25 |  | 
| 128 |  |  |  |  |  |  |  | 
| 129 | 1 | 50 |  |  |  | 11 | $FH->close | 
| 130 |  |  |  |  |  |  | or carp "Unable to close $work_file: $!\n";  # How do I test this to satisfy Devel::Cover? | 
| 131 |  |  |  |  |  |  |  | 
| 132 | 1 | 50 |  |  |  | 163 | rename $work_file, $file | 
| 133 |  |  |  |  |  |  | or croak "Unable to rename $work_file to $file: $!"; | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | } ## end sub save | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  | sub get { | 
| 139 |  |  |  |  |  |  |  | 
| 140 | 7 |  |  | 7 | 1 | 8048 | my ( $self, $name ) = @_; | 
| 141 |  |  |  |  |  |  |  | 
| 142 | 7 | 100 |  |  |  | 57 | croak 'Calling get as a function is not supported' | 
| 143 |  |  |  |  |  |  | unless blessed $self; | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | croak "Nothing loaded" | 
| 146 | 6 | 100 | 66 |  |  | 65 | if ! exists $self->{ count } || $self->{ count } == 0; | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 5 | 50 |  |  |  | 14 | croak "Can't get nothing (no name passed)" | 
| 149 |  |  |  |  |  |  | if $name eq ''; | 
| 150 |  |  |  |  |  |  |  | 
| 151 | 1 |  |  |  |  | 3 | do { $error = "$name does not exist"; return } | 
|  | 1 |  |  |  |  | 7 |  | 
| 152 | 5 | 100 |  |  |  | 18 | unless exists $self->{ name }{ $name }; | 
| 153 |  |  |  |  |  |  |  | 
| 154 | 4 |  |  |  |  | 35 | return $self->{ name }{ $name }{ value }; | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | } ## end sub get | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | sub set { | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 2 |  |  | 2 | 1 | 1898 | my ( $self, $name, $value ) = @_; | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 2 | 100 |  |  |  | 23 | croak 'Calling set as a function is not supported' | 
| 164 |  |  |  |  |  |  | unless blessed $self; | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | croak "Nothing loaded" | 
| 167 | 1 | 50 | 33 |  |  | 21 | if ! exists $self->{ count } || $self->{ count } == 0; | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 0 | 0 |  |  |  | 0 | croak "Can't set nothing (no name passed)" | 
| 170 |  |  |  |  |  |  | if $name eq ''; | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 0 | 0 |  |  |  | 0 | if ( ! exists $self->{ name }{ $name } ) { | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | #    my $date = do { | 
| 175 |  |  |  |  |  |  | # | 
| 176 |  |  |  |  |  |  | #      my @d = localtime( time ); | 
| 177 |  |  |  |  |  |  | #      $d[5] += 1900; | 
| 178 |  |  |  |  |  |  | #      $d[4]++; | 
| 179 |  |  |  |  |  |  | # | 
| 180 |  |  |  |  |  |  | #      join '-', @d[4,3,5]; | 
| 181 |  |  |  |  |  |  | # | 
| 182 |  |  |  |  |  |  | #    }; | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 0 |  |  |  |  | 0 | $value =~ s/#/\\#/; | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 0 |  |  |  |  | 0 | my $comment = sprintf '# %s added by %s on %s', $name, __PACKAGE__, strftime( '%F', gmtime ); | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 0 |  |  |  |  | 0 | push @{ $self->{ lines } }, $comment; | 
|  | 0 |  |  |  |  | 0 |  | 
| 189 | 0 |  |  |  |  | 0 | push @{ $self->{ lines } }, "$name=\"$value\""; | 
|  | 0 |  |  |  |  | 0 |  | 
| 190 |  |  |  |  |  |  |  | 
| 191 | 0 |  |  |  |  | 0 | $self->{ count }++; | 
| 192 | 0 |  |  |  |  | 0 | $self->{ name }{ $name } = { value => $value, line => $self->{ count }++, modified => 0, }; | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | } else { | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 0 |  |  |  |  | 0 | @{ $self->{ name }{ $name } }{ qw( value modified ) } = ( $value, 1 ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | } | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 0 |  |  |  |  | 0 | $self->{ modified } = 1; | 
| 201 |  |  |  |  |  |  |  | 
| 202 | 0 |  |  |  |  | 0 | return 1; | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | } ## end sub set | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 5 |  |  | 5 | 1 | 20 | sub error { $error } | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | }  # You can come out now! | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | 1; | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | __END__ |