File Coverage

blib/lib/MasonX/Request/ExtendedCompRoot.pm
Criterion Covered Total %
statement 18 127 14.1
branch 0 68 0.0
condition 0 6 0.0
subroutine 6 14 42.8
pod 6 6 100.0
total 30 221 13.5


line stmt bran cond sub pod time code
1             # This software is copyright (c) 2004 Alex Robinson.
2             # It is free software and can be used under the same terms as perl,
3             # i.e. either the GNU Public Licence or the Artistic License.
4              
5             package MasonX::Request::ExtendedCompRoot;
6              
7 1     1   6099 use strict;
  1         3  
  1         67  
8              
9             our $VERSION = '0.03';
10              
11 1     1   6 use base qw(HTML::Mason::Request);
  1         3  
  1         1403  
12              
13             # fetch_comp needs this
14 1     1   69927 use HTML::Mason::Tools qw(absolute_comp_path);
  1         9  
  1         72  
15 1     1   5 use HTML::Mason::Exceptions( abbr => [qw(param_error error)] );
  1         1  
  1         9  
16 1     1   66 use Params::Validate qw(:all);
  1         2  
  1         242  
17             Params::Validate::validation_options( on_fail => sub { param_error( join '', @_ ) } );
18 1     1   5 use File::Spec;# qw(canonpath file_name_is_absolute);
  1         2  
  1         1632  
19              
20             # this absurdity, because there's a bug if you leave it out or pass no args
21             __PACKAGE__->valid_params(blop => 0);
22              
23             #
24             # Standard request subclass alter_superclass dance
25             #
26             sub new
27             {
28 0     0 1   my $class = shift;
29 0 0         $class->alter_superclass( $HTML::Mason::ApacheHandler::VERSION ?
    0          
30             'HTML::Mason::Request::ApacheHandler' :
31             $HTML::Mason::CGIHandler::VERSION ?
32             'HTML::Mason::Request::CGI' :
33             'HTML::Mason::Request' );
34 0           return $class->SUPER::new(@_);
35             }
36              
37             #
38             # Given a component path (absolute or relative), returns a component.
39             # Handles SELF, PARENT, REQUEST, comp:method, relative->absolute
40             # conversion, and local subcomponents.
41             #
42             # Basically copied and pasted from HTML::Mason::Request
43             #Ęsee inline comments for diffs
44             #
45             sub fetch_comp
46             {
47 0     0 1   my ($self,$path) = @_;
48 0 0         param_error "fetch_comp: requires path as first argument" unless defined($path);
49              
50             #
51             # Handle paths SELF and PARENT
52             #
53 0 0         if ($path eq 'SELF') {
54 0           return $self->base_comp;
55             }
56 0 0         if ($path eq 'PARENT') {
57 0 0         my $c = $self->current_comp->parent
58             or error "PARENT designator used from component with no parent";
59 0           return $c;
60             }
61 0 0         if ($path eq 'REQUEST') {
62 0           return $self->request_comp;
63             }
64              
65             ##### Additions/Changes to Request.pm #####
66             #
67             # Handle paths of the form comp_root=>comp_path
68             # Make calls to specific comp_roots appear to be absolute paths
69 0 0         if (index($path,'=>') != -1)
70             {
71 0           $path =~ s|^/*|/|;
72             }
73              
74             #
75             # Handle paths of the form comp_path:method_name
76             #
77 0 0         if (index($path,':') != -1) {
78 0           my ($method_comp,$owner_comp);
79 0           my ($owner_path,$method_name) = split(':',$path,2);
80            
81 0           my @comp_root = $self->comp_root;
82 0           foreach (@comp_root)
83             {
84 0           $owner_comp = undef;
85 0           my $owner_path_with_comp_root = $owner_path;
86 0 0         if ($owner_path_with_comp_root =~ m/^(SELF|PARENT|REQUEST)$/)
    0          
87             {
88             # leave alone - these are the special paths
89             }
90             elsif (index($owner_path_with_comp_root,'=>') == -1)
91             {
92             # make comp_path into comp_root=>comp_path unless it already is
93 0           $owner_path_with_comp_root = $_->[0].'=>'.$owner_path_with_comp_root;
94             }
95 0           $owner_comp = $self->fetch_comp($owner_path_with_comp_root);
96 0 0         next unless ($owner_comp);
97 0           $owner_comp->_locate_inherited('methods',$method_name,\$method_comp);
98             # nothing more to be done since, success, we have a method_comp
99 0 0         last if ($method_comp);
100             # nothing more to be done as path is special or an explicit comp_root call
101 0 0         last if $owner_path eq $owner_path_with_comp_root;
102             }
103             # now do the error handling
104 0 0         unless ($owner_comp) { error "could not find component for path '$owner_path'\n"; }
  0            
105 0 0         unless ($method_comp) { error "no method '$method_name' for component " . $owner_comp->name; }
  0            
106             # owner_comp->title tweaked to owner_comp->name
107 0           return $method_comp;
108             }
109             ##### Additions to Request.pm end #####
110              
111             #
112             # If path does not contain a slash, check for a subcomponent in the
113             # current component first.
114             #
115 0 0         if ($path !~ /\//) {
116 0           my $cur_comp = $self->current_comp;
117             # Check my subcomponents.
118 0 0         if (my $subcomp = $cur_comp->subcomps($path)) {
119 0           return $subcomp;
120             }
121             # If I am a subcomponent, also check my owner's subcomponents.
122             # This won't work when we go to multiply embedded subcomponents...
123 0 0 0       if ($cur_comp->is_subcomp and my $subcomp = $cur_comp->owner->subcomps($path)) {
124 0           return $subcomp;
125             }
126             }
127              
128             #
129             # Otherwise pass the absolute path to interp->load.
130             #
131             # For speed, don't call ->current_comp, instead access it directly
132 0 0         $path = absolute_comp_path($path, $self->{stack}[-1]{comp}->dir_path)
133             unless substr($path, 0, 1) eq '/';
134              
135 0           my $comp = $self->interp->load($path);
136              
137 0           return $comp;
138             }
139              
140             #
141             # Call Request.pm's exec, then put comp_root back
142             # to what it was when the current request or subrequest was made
143             #
144             sub exec
145             {
146 0     0 1   my $self = shift;
147 0           my $return_exec = $self->SUPER::exec(@_);
148 0           $self->reset_comp_root;
149 0           return $return_exec;
150             }
151              
152             #
153             # return comp_root array and optionally set it
154             #
155             sub comp_root
156             {
157 0     0 1   my $self = shift;
158 0           my @comp_root = $self->_validate_comp_root_args(@_);
159 0 0         if (@comp_root)
160             {
161 0           $self->_store_comp_root;
162 0           $self->interp->resolver->{comp_root} = \@comp_root;
163             }
164 0           return @{$self->interp->resolver->{comp_root}};
  0            
165             }
166              
167             #
168             # add further comp_roots to the beginning of the comp_root array
169             #
170             sub prefix_comp_root
171             {
172 0     0 1   my $self = shift;
173 0           my @prefix_comp_root = $self->_validate_comp_root_args(@_);
174 0 0         return unless (@prefix_comp_root);
175 0           my %seen;
176 0           foreach my $root (@{$self->interp->resolver->{comp_root}})
  0            
177             {
178 0           $seen{$root->[0]} = 1;
179             }
180 0           foreach my $root (@prefix_comp_root)
181             {
182 0 0         param_error "comp_root '$root->[0]' already exists" if ($seen{$root->[0]});
183             }
184 0           $self->_store_comp_root;
185 0           unshift(@{$self->interp->resolver->{comp_root}}, @prefix_comp_root);
  0            
186 0           return;
187             }
188              
189             #
190             # put comp_root back to how it was at the beginning of the current (sub)request
191             #
192             sub reset_comp_root
193             {
194 0     0 1   my $self = shift;
195 0 0         if ($self->{store_comp_root})
196             {
197 0           my @copy_store = @{$self->{store_comp_root}};
  0            
198 0           $self->interp->resolver->{comp_root} = \@copy_store;
199 0           $self->{store_comp_root} = undef;
200             }
201 0           return;
202             }
203              
204             #
205             # make sure we know what the original comp_root was
206             #
207             sub _store_comp_root
208             {
209 0     0     my $self = shift;
210 0 0         unless ($self->{store_comp_root})
211             {
212 0           my @copy_root = @{$self->interp->resolver->{comp_root}};
  0            
213 0           $self->{store_comp_root} = \@copy_root;
214             }
215 0           return;
216             }
217              
218             #
219             # make sure that args are valid and marshall into required array format
220             #
221             sub _validate_comp_root_args
222             {
223 0     0     my $self = shift;
224 0           my @check_comp_root = @_;
225            
226 0           my $array_check = ref($check_comp_root[0]);
227 0 0         if ($array_check eq "ARRAY")
228             {
229 0           my $inner_array_check = ref($check_comp_root[0][0]);
230 0 0 0       if ( ($inner_array_check =~ /ARRAY|HASH/s) or (index($check_comp_root[0][0],'=>') != -1) )
231             {
232 0           for (my $i = scalar(@{$check_comp_root[0]}) - 1; $i >= 0; $i--)
  0            
233             {
234 0           $check_comp_root[$i] = $check_comp_root[0][$i];
235             }
236             }
237             }
238            
239 0           my %seen;
240 0           foreach (@check_comp_root)
241             {
242 0           my $ref_check = ref($_);
243 0 0         unless ($ref_check =~ m/ARRAY|HASH/)
244             {
245 0           my $string = $_;
246 0 0         if (index($string,'=>') != -1)
247             {
248 0           my @root_split = split('=>', $string);
249 0 0         if ($root_split[2]) { die "Too many delimiters in comp_root $string"; }
  0            
250 0           $_ = \@root_split;
251             }
252 0           else { die "$string is wrong - comp_root should take the form 'comp_root_name=>/path/to/comp_root'"; }
253             }
254 0 0         if ($ref_check =~ m/HASH/)
255             {
256 0           my %hash_store = %{$_};
  0            
257 0           foreach my $key (keys %hash_store)
258             {
259 0           $_ = [$key, $hash_store{$key}];
260             }
261             }
262 0           $_->[1] = File::Spec->canonpath( $_->[1] );
263 0 0         param_error "path specified for comp_root '$_->[0]' ($_->[1]) is not an absolute directory" unless File::Spec->file_name_is_absolute( $_->[1] );
264 0 0         param_error "path specified for comp_root '$_->[0]' ($_->[1]) does not exist" unless (-d $_->[1]);
265 0 0         param_error "comp_root '$_->[0]' should only be specified once" if $seen{$_->[0]}++;
266             }
267 0           return @check_comp_root;
268             }
269              
270             1;
271              
272              
273             __END__