File Coverage

blib/lib/Config/PFiles/Path.pm
Criterion Covered Total %
statement 90 95 94.7
branch 22 26 84.6
condition 10 13 76.9
subroutine 18 18 100.0
pod 1 1 100.0
total 141 153 92.1


line stmt bran cond sub pod time code
1             # --8<--8<--8<--8<--
2             #
3             # Copyright (C) 2007 Smithsonian Astrophysical Observatory
4             #
5             # This file is part of Config::PFiles::Path
6             #
7             # Config::PFiles::Path is free software: you can redistribute it and/or modify
8             # it under the terms of the GNU General Public License as published by
9             # the Free Software Foundation, either version 3 of the License, or (at
10             # your option) any later version.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15             # GNU General Public License for more details.
16             #
17             # You should have received a copy of the GNU General Public License
18             # along with this program. If not, see .
19             #
20             # -->8-->8-->8-->8--
21              
22             package Config::PFiles::Path;
23              
24 11     11   163154 use 5.008009;
  11         39  
  11         823  
25              
26 11     11   53 use strict;
  11         14  
  11         347  
27 11     11   48 use warnings;
  11         17  
  11         316  
28              
29 11     11   5925 use Symbol;
  11         8781  
  11         878  
30 11     11   66 use Carp;
  11         14  
  11         682  
31 11     11   5551 use Sub::Uplevel;
  11         9926  
  11         63  
32              
33             our $VERSION = '0.03';
34              
35 11     11   11551 use overload '""' => '_export' ;
  11         9144  
  11         70  
36              
37             my %is_mutator
38             = map { $_ => 1 } qw( _append _prepend _replace _remove );
39              
40             our $AUTOLOAD;
41              
42             # allow the user to do thing when loading the package
43             sub import {
44              
45 11     11   74 my $package = shift;
46              
47 11 100       8014 return unless @_;
48              
49 5         12 my $method = shift;
50              
51 5 100       36 croak( "Can't call method '$method' in this context\n" )
52             unless $is_mutator{ "_$method" };
53              
54 4         6 $AUTOLOAD = $method;
55 4         18 uplevel 1, \&AUTOLOAD, $package, @_;
56             }
57              
58             sub AUTOLOAD {
59 81     81   15937 (my $method = our $AUTOLOAD) =~ s/.*:://;
60              
61             # we don't have a DESTROY method, so ignore it.
62 81 50       207 return if $method =~ /DESTROY/;
63              
64 81         109 my $imethod = '_' . $method;
65              
66 81         66 my $subref = *{qualify_to_ref($imethod,__PACKAGE__)}{CODE};
  81         165  
67              
68             # make sure it's an existing method
69 81 50 33     1497 croak( qq{Can't locate object method "$method" via package "},
70             __PACKAGE__, q{"} )
71             if $method =~ /^_/ || ! defined $subref;
72              
73              
74             # is this an object invocation?
75 81 100 66     347 if ( ref $_[0] && $_[0]->isa(__PACKAGE__) )
76             {
77 61         156 goto &$imethod;
78             }
79              
80             # nope. create default object based on $ENV{PFILES} and replace
81             # the class name in the argument list with the new object
82 20         22 my $package = shift;
83 20         128 my $env = $package->new( $ENV{PFILES} );
84 20         34 unshift @_, $env;
85              
86              
87             # if the method will alter the path, make sure to update $ENV{PFILES}
88             # after it has been run
89 20 100       44 if ( $is_mutator{$imethod} )
90             {
91             # respect calling context
92 17         21 my $wantarray = wantarray();
93              
94             # void
95 17 100       34 if ( ! defined $wantarray )
    50          
96             {
97 13         44 uplevel 1, $subref, @_;
98 13         31 $ENV{PFILES} = $env->_export;
99 13         5387 return;
100             }
101              
102             # list
103             elsif ( $wantarray)
104             {
105 4         12 my @results = uplevel 1, $subref, @_;
106 4         9 $ENV{PFILES} = $env->_export;
107 4         21 return @results;
108             }
109              
110             # scalar
111             else
112             {
113 0         0 my $result = uplevel 1, $subref, @_;
114 0         0 $ENV{PFILES} = $env->_export;
115 0         0 return $result;
116             }
117             }
118              
119             # nope, just execute the method
120             else
121             {
122 3         12 goto &$imethod;
123             }
124             }
125              
126             sub new {
127 43     43 1 8980 my ( $class, $pfiles ) = @_;
128              
129 43         105 my $self = bless {}, $class;
130              
131 43         103 $self->__init( $pfiles );
132              
133 42         67 return $self;
134             }
135              
136             sub __init {
137 43     43   47 my ( $self, $pfiles ) = @_;
138              
139 43   100     104 $pfiles ||= q{};
140              
141 43         40 my %dirs;
142 43         264 @dirs{ qw( RW RO ) } =
143             $pfiles =~ /^
144             ([^;]*) # grab everything that's not a semicolon (RW)
145             (?:|;(.*)) # and everything that's after a semicolon (RO)
146             $/x;
147              
148 43 100 100     252 croak( "illegal path: too many semi-colons: $pfiles\n" )
149             if defined $dirs{RO} && $dirs{RO} =~ /;/;
150              
151             # split and store non-empty paths
152 88         502 $self->{$_} = [ grep { $_ ne '' } split( /:/, $dirs{$_} || q{} ) ]
153 42   100     324 for qw( RW RO );
154              
155 42         83 return;
156             }
157              
158             sub __check_set {
159 69     69   75 my ( $dir_set ) = shift;
160              
161 69         46 my $match;
162 69 50       343 unless ( ($match ) = $dir_set =~ /^(RW|RO)$/i )
163             {
164 0         0 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
165 0         0 croak( "illegal value for directory set: $dir_set\n" )
166             }
167              
168 69         270 return uc($match);
169             }
170              
171             sub _append {
172 7     7   51 my ( $self, $dir_set, @dirs ) = @_;
173              
174 7         9 push @{$self->{__check_set($dir_set)}}, @dirs;
  7         15  
175              
176 7         17 return;
177             }
178              
179             sub _prepend {
180 8     8   53 my ( $self, $dir_set, @dirs ) = @_;
181              
182 8         9 unshift @{$self->{__check_set($dir_set)}}, @dirs;
  8         15  
183              
184 8         19 return;
185             }
186              
187             sub _extract {
188 32     32   37 my ( $self, $dir_set ) = @_;
189              
190 32         27 return @{$self->{__check_set($dir_set)}};
  32         54  
191             }
192              
193             sub _replace {
194 22     22   82 my ( $self, $dir_set, @dirs ) = @_;
195              
196 22         37 $dir_set = __check_set($dir_set);
197              
198 22         402 my @old = @{$self->{$dir_set}};
  22         51  
199              
200 22         39 $self->{$dir_set} = [ @dirs ];
201              
202             return @old
203 22 100       66 if defined wantarray;
204              
205 14         31 return;
206             }
207              
208             sub _remove {
209 11     11   67 my ( $self, $dir_set ) = @_;
210              
211 11         49 return $self->replace( $dir_set );
212             }
213              
214             sub _export {
215 23     23   38 my ( $self ) = @_;
216              
217             # join together the non-empty directories in the sets;
218 46         102 my ( $rw, $ro ) =
219 23         30 map { join( q{:}, grep { $_ ne q{} } @{$self->{$_}} ) }
  46         33  
  46         75  
220             qw( RW RO );
221              
222             # construct a rational path
223             return
224 23 100       610 $rw eq q{} ? ";$ro"
    100          
225             : $ro eq q{} ? $rw
226             : "$rw;$ro";
227             }
228              
229             1;
230              
231             __END__