File Coverage

blib/lib/Config/PFiles/Path.pm
Criterion Covered Total %
statement 87 92 94.5
branch 22 26 84.6
condition 10 13 76.9
subroutine 17 17 100.0
pod 1 1 100.0
total 137 149 91.9


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   335971 use strict;
  11         30  
  11         456  
25 11     11   250 use warnings;
  11         24  
  11         427  
26              
27 11     11   19089 use Symbol;
  11         15991  
  11         1471  
28 11     11   85 use Carp;
  11         17  
  11         937  
29 11     11   9963 use Sub::Uplevel;
  11         15749  
  11         76  
30              
31             our $VERSION = '0.02';
32              
33 11     11   19190 use overload '""' => '_export' ;
  11         12327  
  11         87  
34              
35             my %is_mutator
36             = map { $_ => 1 } qw( _append _prepend _replace _remove );
37              
38             our $AUTOLOAD;
39              
40             # allow the user to do thing when loading the package
41             sub import {
42              
43 11     11   99 my $package = shift;
44              
45 11 100       12568 return unless @_;
46              
47 5         10 my $method = shift;
48              
49 5 100       56 croak( "Can't call method '$method' in this context\n" )
50             unless $is_mutator{ "_$method" };
51              
52 4         81 $AUTOLOAD = $method;
53 4         41 uplevel 1, \&AUTOLOAD, $package, @_;
54             }
55              
56             sub AUTOLOAD {
57 39     39   12575 (my $method = our $AUTOLOAD) =~ s/.*:://;
58              
59             # we don't have a DESTROY method, so ignore it.
60 39 50       130 return if $method =~ /DESTROY/;
61              
62 39         71 my $imethod = '_' . $method;
63              
64 39         47 my $subref = *{qualify_to_ref($imethod,__PACKAGE__)}{CODE};
  39         128  
65              
66             # make sure it's an existing method
67 39 50 33     933 croak( qq{Can't locate object method "$method" via package "},
68             __PACKAGE__, q{"} )
69             if $method =~ /^_/ || ! defined $subref;
70              
71              
72             # is this an object invocation?
73 39 100 66     200 if ( ref $_[0] && $_[0]->isa(__PACKAGE__) )
74             {
75 19         74 goto &$imethod;
76             }
77              
78             # nope. create default object based on $ENV{PFILES} and replace
79             # the class name in the argument list with the new object
80 20         31 my $package = shift;
81 20         77 my $env = $package->new( $ENV{PFILES} );
82 20         45 unshift @_, $env;
83              
84              
85             # if the method will alter the path, make sure to update $ENV{PFILES}
86             # after it has been run
87 20 100       55 if ( $is_mutator{$imethod} )
88             {
89             # respect calling context
90 17         26 my $wantarray = wantarray();
91              
92             # void
93 17 100       41 if ( ! defined $wantarray )
    50          
94             {
95 13         55 uplevel 1, $subref, @_;
96 13         98 $ENV{PFILES} = $env->_export;
97 13         11142 return;
98             }
99              
100             # list
101             elsif ( $wantarray)
102             {
103 4         11 my @results = uplevel 1, $subref, @_;
104 4         10 $ENV{PFILES} = $env->_export;
105 4         29 return @results;
106             }
107              
108             # scalar
109             else
110             {
111 0         0 my $result = uplevel 1, $subref, @_;
112 0         0 $ENV{PFILES} = $env->_export;
113 0         0 return $result;
114             }
115             }
116              
117             # nope, just execute the method
118             else
119             {
120 3         12 goto &$imethod;
121             }
122             }
123              
124             sub new {
125 33     33 1 6679 my ( $class, $pfiles ) = @_;
126              
127 33         101 my $self = bless {}, $class;
128              
129 33         93 $self->__init( $pfiles );
130              
131 32         62 return $self;
132             }
133              
134             sub __init {
135 33     33   52 my ( $self, $pfiles ) = @_;
136              
137 33   100     94 $pfiles ||= q{};
138              
139 33         44 my %dirs;
140 33         205 @dirs{ qw( RW RO ) } =
141             $pfiles =~ /^
142             ([^;]*) # grab everything that's not a semicolon (RW)
143             (?:|;(.*)) # and everything that's after a semicolon (RO)
144             $/x;
145              
146 33 100 100     242 croak( "illegal path: too many semi-colons: $pfiles\n" )
147             if defined $dirs{RO} && $dirs{RO} =~ /;/;
148              
149             # split and store non-empty paths
150 72         548 $self->{$_} = [ grep { $_ ne '' } split( /:/, $dirs{$_} || q{} ) ]
151 32   100     297 for qw( RW RO );
152              
153 32         85 return;
154             }
155              
156             sub __check_set {
157 33     33   53 my ( $dir_set ) = shift;
158              
159 33         38 my $match;
160 33 50       343 unless ( ($match ) = $dir_set =~ /^(RW|RO)$/i )
161             {
162 0         0 local $Carp::CarpLevel = $Carp::CarpLevel + 1;
163 0         0 croak( "illegal value for directory set: $dir_set\n" )
164             }
165              
166 33         181 return uc($match);
167             }
168              
169             sub _append {
170 3     3   53 my ( $self, $dir_set, @dirs ) = @_;
171              
172 3         6 push @{$self->{__check_set($dir_set)}}, @dirs;
  3         11  
173              
174 3         15 return;
175             }
176              
177             sub _prepend {
178 4     4   52 my ( $self, $dir_set, @dirs ) = @_;
179              
180 4         6 unshift @{$self->{__check_set($dir_set)}}, @dirs;
  4         543  
181              
182 4         18 return;
183             }
184              
185             sub _extract {
186 16     16   26 my ( $self, $dir_set ) = @_;
187              
188 16         19 return @{$self->{__check_set($dir_set)}};
  16         37  
189             }
190              
191             sub _replace {
192 10     10   65 my ( $self, $dir_set, @dirs ) = @_;
193              
194 10         67 $dir_set = __check_set($dir_set);
195              
196 10         13 my @old = @{$self->{$dir_set}};
  10         25  
197              
198 10         22 $self->{$dir_set} = [ @dirs ];
199              
200             return @old
201 10 100       47 if defined wantarray;
202              
203 6         21 return;
204             }
205              
206             sub _remove {
207 5     5   61 my ( $self, $dir_set ) = @_;
208              
209 5         36 return $self->replace( $dir_set );
210             }
211              
212             sub _export {
213 23     23   53 my ( $self ) = @_;
214              
215             # join together the non-empty directories in the sets;
216 46         138 my ( $rw, $ro ) =
217 23         41 map { join( q{:}, grep { $_ ne q{} } @{$self->{$_}} ) }
  46         81  
  46         123  
218             qw( RW RO );
219              
220             # construct a rational path
221             return
222 23 100       271 $rw eq q{} ? ";$ro"
    100          
223             : $ro eq q{} ? $rw
224             : "$rw;$ro";
225             }
226              
227             1;
228              
229             __END__