File Coverage

blib/lib/Mason/Interp.pm
Criterion Covered Total %
statement 565 568 99.4
branch 97 108 89.8
condition 20 28 71.4
subroutine 139 139 100.0
pod n/a
total 821 843 97.3


line stmt bran cond sub pod time code
1             package Mason::Interp;
2             $Mason::Interp::VERSION = '2.24';
3 27     27   142 use Carp;
  27         49  
  27         1136  
4 28     27   8682 use Devel::GlobalDestruction;
  28         34123  
  28         180  
5 30     25   1395 use File::Basename;
  30         51  
  30         1145  
6 29     25   156 use File::Path;
  29         175  
  29         867  
7 29     25   153 use File::Temp qw(tempdir);
  29         43  
  29         748  
8 27     20   8872 use Guard;
  27         9363  
  27         1027  
9 28     20   6425 use Mason::CodeCache;
  28         90  
  28         1458  
10 29     20   13089 use Mason::Request;
  29         725  
  29         1418  
11 28     20   10539 use Mason::Result;
  28         68  
  28         894  
12 23     20   184 use Mason::Types;
  23         36  
  23         614  
13             use Mason::Util
14 22     20   97 qw(can_load catdir catfile combine_similar_paths find_wanted first_index is_absolute json_decode mason_canon_path read_file taint_is_on touch_file uniq write_file);
  22         33  
  22         2486  
15 22     20   125 use Class::Load;
  22         28  
  22         677  
16 22     20   15400 use Memoize;
  22         41278  
  22         1141  
17 22     20   152 use Moose::Util::TypeConstraints;
  22         32  
  22         251  
18 22     20   34438 use Mason::Moose;
  22         45  
  22         158  
19              
20             my $default_out = sub { print( $_[0] ) };
21             my $next_id = 0;
22             my $max_depth = 16;
23              
24             # Passed attributes
25             #
26             has 'allow_globals' => ( isa => 'ArrayRef[Str]', default => sub { [] }, trigger => sub { shift->_validate_allow_globals } );
27             has 'autobase_names' => ( isa => 'ArrayRef[Str]', lazy_build => 1 );
28             has 'autoextend_request_path' => ( isa => 'Bool', default => 1 );
29             has 'class_header' => ( default => '' );
30             has 'comp_root' => ( required => 1, isa => 'Mason::Types::CompRoot', coerce => 1 );
31             has 'component_class_prefix' => ( lazy_build => 1 );
32             has 'data_dir' => ( lazy_build => 1 );
33             has 'dhandler_names' => ( isa => 'ArrayRef[Str]', lazy_build => 1 );
34             has 'index_names' => ( isa => 'ArrayRef[Str]', lazy_build => 1 );
35             has 'mason_root_class' => ( required => 1 );
36             has 'no_source_line_numbers' => ( default => 0 );
37             has 'object_file_extension' => ( default => '.mobj' );
38             has 'plugins' => ( default => sub { [] } );
39             has 'pure_perl_extensions' => ( default => sub { ['.mp'] } );
40             has 'static_source' => ();
41             has 'static_source_touch_file' => ();
42             has 'top_level_extensions' => ( default => sub { ['.mc', '.mp'] } );
43              
44             # Derived attributes
45             #
46             has 'allowed_globals_hash' => ( init_arg => undef, lazy_build => 1 );
47             has 'code_cache' => ( init_arg => undef, lazy_build => 1 );
48             has 'distinct_string_count' => ( init_arg => undef, default => 0 );
49             has 'globals_package' => ( init_arg => undef, lazy_build => 1 );
50             has 'id' => ( init_arg => undef, default => sub { $next_id++ } );
51             has 'match_request_path' => ( init_arg => undef, lazy_build => 1 );
52             has 'pure_perl_regex' => ( lazy_build => 1 );
53             has 'request_params' => ( init_arg => undef );
54             has 'top_level_regex' => ( lazy_build => 1 );
55              
56             # Class overrides
57             #
58             CLASS->_define_class_override_methods();
59              
60             # Allow access to current interp while in load()
61             #
62             our ($current_load_interp);
63 22     20   47621 method current_load_interp () { $current_load_interp }
  228     227   792  
  228         497  
  228         731  
64              
65             #
66             # BUILD
67             #
68              
69 22     20   6617 method BUILD ($params) {
  107     106   246  
  107         191  
  107         213  
70              
71             # Initialize static source mode
72             #
73 107 100       438 if ( $self->{static_source} ) {
74 3   33     8 $self->{static_source_touch_file} ||= catfile( $self->data_dir, 'purge.dat' );
75 3         14 $self->{static_source_touch_lastmod} = 0;
76 2         6 $self->_check_static_source_touch_file();
77             }
78              
79             # Separate out request parameters
80             #
81 106         334 $self->{request_params} = {};
82 1696   66     17170 my %is_request_attribute =
83 106         3277 map { ( $_->init_arg || $_->name, 1 ) } $self->request_class->meta->get_all_attributes();
84 106         771 foreach my $key ( keys(%$params) ) {
85 461 100       4642 if ( $is_request_attribute{$key} ) {
86 1         4 $self->{request_params}->{$key} = delete( $params->{$key} );
87             }
88             }
89             }
90              
91 22     20   8653 method _build_allowed_globals_hash () {
  3     3   5  
  3         3  
92 3         6 my @allow_globals = uniq( @{ $self->allow_globals } );
  3         95  
93 3         8 my @canon_globals = map { join( "", $self->_parse_global_spec($_) ) } @allow_globals;
  4         17  
94 1         3 return { map { ( $_, 1 ) } @canon_globals };
  2         35  
95             }
96              
97 22     20   7180 method _build_globals_package () {
  1     1   1  
  1         2  
98 1         24 return "Mason::Globals" . $self->id;
99             }
100              
101 22     20   5741 method _build_autobase_names () {
  85     85   178  
  85         164  
102 85         143 return [ map { "Base" . $_ } @{ $self->top_level_extensions } ];
  163         2912  
  85         2735  
103             }
104              
105 22     20   6120 method _build_code_cache () {
  85     85   162  
  85         120  
106 85         2982 return $self->code_cache_class->new();
107             }
108              
109 21     20   5973 method _build_component_class_prefix () {
  73     73   156  
  73         121  
110 73         2445 return "MC" . $self->id;
111             }
112              
113 21     20   5852 method _build_data_dir () {
  1     1   1  
  1         2  
114 1         5 return tempdir( 'mason-data-XXXX', TMPDIR => 1, CLEANUP => 1 );
115             }
116              
117 21     20   5862 method _build_dhandler_names () {
  77     77   158  
  77         128  
118 77         124 return [ map { "dhandler" . $_ } @{ $self->top_level_extensions } ];
  147         3739  
  77         2758  
119             }
120              
121 21     20   6070 method _build_index_names () {
  72     72   138  
  72         101  
122 72         126 return [ map { "index" . $_ } @{ $self->top_level_extensions } ];
  137         2098  
  72         2206  
123             }
124              
125 21     20   6502 method _build_pure_perl_regex () {
  74     74   149  
  74         121  
126 74         2441 my $extensions = $self->pure_perl_extensions;
127 74 100       282 if ( !@$extensions ) {
128 1         27 return qr/(?!)/; # matches nothing
129             }
130             else {
131 73         432 my $regex = join( '|', @$extensions ) . '$';
132 73         2634 return qr/$regex/;
133             }
134             }
135              
136 21     20   7285 method _build_top_level_regex () {
  74     74   132  
  74         108  
137 74         2605 my $extensions = $self->top_level_extensions;
138 74 100       320 if ( !@$extensions ) {
139 2         77 return qr/./; # matches everything
140             }
141             else {
142 72         254 my $regex = join( '|', @$extensions );
143 72 100       193 if ( my @other_names = grep { !/$regex/ } @{ $self->dhandler_names },
  273         1633  
  72         2249  
  72         2220  
144             @{ $self->index_names } )
145             {
146 17         97 $regex .= '|(?:/(?:' . join( '|', @other_names ) . '))';
147             }
148 72         253 $regex = '(?:' . $regex . ')$';
149 72         2675 return qr/$regex/;
150             }
151             }
152              
153             #
154             # PUBLIC METHODS
155             #
156              
157 20     20   7916 method all_paths ($dir_path) {
  4     4   9  
  4         6  
  4         5  
158 4   100     12 $dir_path ||= '/';
159 4         10 $self->_assert_absolute_path($dir_path);
160             return $self->_collect_paths_for_all_comp_roots(
161             sub {
162 8     8   9 my $root_path = shift;
163 8         11 my $dir = $root_path . $dir_path;
164 8 100       154 return ( -d $dir ) ? find_wanted( sub { -f }, $dir ) : ();
  24         726  
165             }
166 4         22 );
167             }
168              
169 20     20   7162 method comp_exists ($path) {
170              
171             # Canonicalize path
172             #
173             croak "path required" if !defined($path);
174             $path = Mason::Util::mason_canon_path($path);
175              
176             return ( ( $self->static_source && $self->code_cache->get($path) )
177             || $self->_source_file_for_path($path) ) ? 1 : 0;
178             }
179              
180 20     20   7060 method flush_code_cache () {
  87     87   227  
  87         160  
181 87         2726 my $code_cache = $self->code_cache;
182              
183 87         628 foreach my $key ( $code_cache->get_keys() ) {
184 196         779 $code_cache->remove($key);
185             }
186             }
187              
188 20     20   6513 method glob_paths ($glob_pattern) {
  3     3   5  
  3         4  
  3         3  
189             return $self->_collect_paths_for_all_comp_roots(
190             sub {
191 6     6   7 my $root_path = shift;
192 6         219 return glob( $root_path . $glob_pattern );
193             }
194 3         14 );
195             }
196              
197             our $in_load = 0;
198              
199 20     20   6924 method load ($path) {
200              
201             local $current_load_interp = $self;
202              
203             my $code_cache = $self->code_cache;
204              
205             # Canonicalize path
206             #
207             croak "path required" if !defined($path);
208             $path = Mason::Util::mason_canon_path($path);
209              
210             # Quick check memory cache in static source mode
211             #
212             if ( $self->static_source ) {
213             if ( my $entry = $code_cache->get($path) ) {
214             return $entry->{compc};
215             }
216             }
217              
218             local $in_load = $in_load + 1;
219             if ( $in_load > $max_depth ) {
220             die ">$max_depth levels deep in inheritance determination (inheritance cycle?)"
221             if $in_load >= $max_depth;
222             }
223              
224             my $compile = 0;
225             my (
226             $default_parent_path, $source_file, $source_lastmod, $object_file,
227             $object_lastmod, @source_stat, @object_stat
228             );
229              
230             my $stat_source_file = sub {
231             if ( $source_file = $self->_source_file_for_path($path) ) {
232             @source_stat = stat $source_file;
233             if ( @source_stat && !-f _ ) {
234             die "source file '$source_file' exists but it is not a file";
235             }
236             }
237             $source_lastmod = @source_stat ? $source_stat[9] : 0;
238             };
239              
240             my $stat_object_file = sub {
241             $object_file = $self->_object_file_for_path($path);
242             @object_stat = stat $object_file;
243             if ( @object_stat && !-f _ ) {
244             die "object file '$object_file' exists but it is not a file";
245             }
246             $object_lastmod = @object_stat ? $object_stat[9] : 0;
247             };
248              
249             # Determine source and object files and their modified times
250             #
251             $stat_source_file->() or return;
252              
253             # Determine default parent comp
254             #
255             $default_parent_path = $self->_default_parent_path($path);
256              
257             if ( $self->static_source ) {
258              
259             if ( $stat_object_file->() ) {
260              
261             # If touch file is more recent than object file, we can't trust object file.
262             #
263             if ( $self->{static_source_touch_lastmod} >= $object_lastmod ) {
264              
265             # If source file is more recent, recompile. Otherwise, touch
266             # the object file so it will be trusted.
267             #
268             if ( $source_lastmod > $object_lastmod ) {
269             $compile = 1;
270             }
271             else {
272             touch_file($object_file);
273             }
274             }
275             }
276             else {
277             $compile = 1;
278             }
279              
280             }
281             else {
282              
283             # Check memory cache
284             #
285             if ( my $entry = $code_cache->get($path) ) {
286             if ( $entry->{source_lastmod} >= $source_lastmod
287             && $entry->{source_file} eq $source_file
288             && $entry->{default_parent_path} eq $default_parent_path )
289             {
290             my $compc = $entry->{compc};
291             if ( $entry->{superclass_signature} eq $self->_superclass_signature($compc) ) {
292             return $compc;
293             }
294             }
295             $code_cache->remove($path);
296             }
297              
298             # Determine object file and its last modified time
299             #
300             $stat_object_file->();
301             $compile = ( !$object_lastmod || $object_lastmod < $source_lastmod );
302             }
303              
304             $self->_compile_to_file( $source_file, $path, $object_file ) if $compile;
305              
306             my $compc = $self->_comp_class_for_path($path);
307              
308             $self->_load_class_from_object_file( $compc, $object_file, $path, $default_parent_path );
309             $compc->meta->make_immutable();
310              
311             # Save component class in the cache.
312             #
313             $code_cache->set(
314             $path,
315             {
316             source_file => $source_file,
317             source_lastmod => $source_lastmod,
318             default_parent_path => $default_parent_path,
319             compc => $compc,
320             superclass_signature => $self->_superclass_signature($compc),
321             }
322             );
323              
324             return $compc;
325             }
326              
327 20     20   15993 method _superclass_signature ($compc) {
  260     260   545  
  260         496  
  260         395  
328 260         1358 my @superclasses = $compc->meta->superclasses;
329              
330             # Recursively load the superclasses for an existing component class in
331             # case they have changed.
332             #
333 260         21373 foreach my $superclass (@superclasses) {
334 260 100       2440 if ( my $cmeta = $superclass->cmeta ) {
335 71         2717 my $path = $cmeta->path;
336 71         1800 $self->load( $cmeta->path );
337             }
338             }
339              
340             # Return a unique signature representing the component class's superclasses
341             # and their versions.
342             #
343 260 100       2953 return join( ",", map { join( "-", $_, $_->cmeta ? $_->cmeta->id : 0 ) } @superclasses );
  260         983  
344             }
345              
346             # Memoize comp_exists() and load() - this helps both with components used
347             # multiple times in a request, and with determining default parent
348             # components. The memoize cache is cleared at the beginning of each
349             # request, or in static_source_mode, when the purge file is touched.
350             #
351             memoize('comp_exists');
352             memoize('load');
353              
354 20     20   8673 method object_dir () {
  270     270   434  
  270         314  
355 270         7376 return catdir( $self->data_dir, 'obj' );
356             }
357              
358 20     20   6219 method run () {
  184     184   321  
  184         261  
359 184         230 my %request_params;
360 184 100       694 if ( ref( $_[0] ) eq 'HASH' ) {
361 11         11 %request_params = %{ shift(@_) };
  11         34  
362             }
363 184         347 my $path = shift;
364 184         724 my $request = $self->_make_request(%request_params);
365 184         1229 $request->run( $path, @_ );
366             }
367              
368 20     20   7411 method set_global () {
  3     3   5  
  3         8  
369 3         5 my ( $spec, $value ) = @_;
370 3 50       8 croak "set_global expects a var name and value" unless $value;
371 3         6 my ( $sigil, $name ) = $self->_parse_global_spec($spec);
372 3 100       83 croak "${sigil}${name} is not in the allowed globals list"
373             unless $self->allowed_globals_hash->{"${sigil}${name}"};
374              
375 2         50 my $varname = sprintf( "%s::%s", $self->globals_package, $name );
376 20     20   2654 no strict 'refs';
  20         39  
  20         801  
377 20     20   98 no warnings 'once';
  20         26  
  20         845  
378 2         11 $$varname = $value;
379             }
380              
381             #
382             # MODIFIABLE METHODS
383             #
384              
385 20     20   5670 method DEMOLISH () {
  109     109   259  
  109         176  
386 109 50       2421 return if in_global_destruction;
387              
388             # We have to check for code_cache slot directly, in case the object gets
389             # destroyed before it has been fully formed (e.g. missing required attr).
390             #
391 109 100       1231 $self->flush_code_cache() if defined( $self->{code_cache} );
392             }
393              
394 20     20   6732 method _compile ($source_file, $path) {
  237     237   387  
  237         449  
  237         369  
395 237         8614 my $compilation = $self->compilation_class->new(
396             source_file => $source_file,
397             path => $path,
398             interp => $self
399             );
400 237         1331 return $compilation->compile();
401             }
402              
403 20     20   6729 method _compile_to_file ($source_file, $path, $object_file) {
  233     233   394  
  233         401  
  233         352  
404              
405             # We attempt to handle several cases in which a file already exists
406             # and we wish to create a directory, or vice versa. However, not
407             # every case is handled; to be complete, mkpath would have to unlink
408             # any existing file in its way.
409             #
410 233 100 66     3086 if ( defined $object_file && !-f $object_file ) {
411 225         7973 my ($dirname) = dirname($object_file);
412 225 100       2933 if ( !-d $dirname ) {
413 95 50       302 unlink($dirname) if ( -e _ );
414 95         29888 mkpath( $dirname, 0, 0775 );
415             }
416 225 50       3198 rmtree($object_file) if ( -d $object_file );
417             }
418 233         962 my $object_contents = $self->_compile( $source_file, $path );
419              
420 207         1358 $self->write_object_file( $object_file, $object_contents );
421             }
422              
423 20     20   8400 method is_pure_perl_comp_path ($path) {
  237     237   393  
  237         396  
  237         295  
424 237 100       6490 return ( $path =~ $self->pure_perl_regex ) ? 1 : 0;
425             }
426              
427 20     20   6404 method is_top_level_comp_path ($path) {
  211     211   386  
  211         344  
  211         272  
428 211 100       5765 return ( $path =~ $self->top_level_regex ) ? 1 : 0;
429             }
430              
431 20     20   6489 method _load_class_from_object_file ($compc, $object_file, $path, $default_parent_path) {
  244     244   395  
  244         533  
  244         302  
432 244         896 my $flags = $self->_extract_flags_from_object_file($object_file);
433 244   66     1162 my $parent_compc =
434             $self->_determine_parent_compc( $path, $flags )
435             || ( $default_parent_path eq '/' && $self->component_class )
436             || $self->load($default_parent_path);
437              
438 227         3182 my $code = sprintf( 'package %s; use Moose; extends \'%s\'; do(\'%s\'); die $@ if $@',
439             $compc, $parent_compc, $object_file );
440 227 50       959 ($code) = ( $code =~ /^(.*)/s ) if taint_is_on();
441 19     19   140 eval($code);
  19     15   29  
  19     9   140  
  15     5   110  
  15     1   27  
  15     1   109  
  9         65  
  9         15  
  9         66  
  6         42  
  6         9  
  6         46  
  4         29  
  4         8  
  4         26  
  3         21  
  3         15  
  3         22  
  3         20  
  3         4  
  3         22  
  3         24  
  3         5  
  3         23  
  3         20  
  3         4  
  3         21  
  3         20  
  3         4  
  3         18  
  3         98  
  3         6  
  3         21  
  3         1709  
  3         5  
  3         27  
  3         20  
  3         3  
  3         21  
  3         22  
  3         5  
  3         20  
  3         19  
  3         3  
  3         19  
  3         19  
  3         3  
  3         19  
  2         14  
  2         3  
  2         12  
  2         14  
  2         3  
  2         14  
  2         14  
  2         3  
  2         14  
  2         14  
  2         2  
  2         14  
  1         7  
  1         2  
  1         7  
  1         8  
  1         1  
  1         7  
  1         7  
  1         1  
  1         7  
  1         9  
  1         1  
  1         7  
  1         7  
  1         1  
  1         7  
  1         8  
  1         2  
  1         8  
  1         8  
  1         1  
  1         6  
  1         6  
  1         2  
  1         4  
  1         8  
  1         2  
  1         7  
  1         7  
  1         3  
  1         8  
  9         65  
  9         17  
  9         79  
  6         47  
  6         12  
  6         45  
  3         29  
  3         5  
  3         23  
  6         43  
  6         7  
  6         41  
  227         23490  
  1         8  
  1         2  
  1         6  
  1         7  
  1         2  
  1         7  
442 227 100       1325 die $@ if $@;
443              
444 225         1303 $compc->_set_class_cmeta($self);
445 225         929 $self->modify_loaded_class($compc);
446             }
447              
448 20     20   9199 method modify_loaded_class ($compc) {
  225     225   405  
  225         401  
  225         291  
449 225         1151 $self->_add_default_wrap_method($compc);
450             }
451              
452 20     20   6766 method write_object_file ($object_file, $object_contents) {
  207     207   353  
  207         432  
  207         290  
453 207         854 write_file( $object_file, $object_contents );
454             }
455              
456             # Given /foo/bar, look for (by default):
457             # /foo/bar/index.{mp,mc},
458             # /foo/bar/dhandler.{mp,mc},
459             # /foo/bar.{mp,mc},
460             # /dhandler.{mp,mc},
461             # /foo.{mp,mc}
462             #
463 20     20   6958 method _build_match_request_path ($interp:) {
  82     82   184  
  82         119  
464              
465             # Create a closure for efficiency - all this data is immutable for an interp.
466             #
467 82         154 my @dhandler_subpaths = map { "/$_" } @{ $interp->dhandler_names };
  149         461  
  82         2936  
468 82         3087 my $ignore_file_regex =
469 82         185 '(/' . join( "|", @{ $interp->autobase_names }, @{ $interp->dhandler_names } ) . ')$';
  82         2520  
470 82         2055 $ignore_file_regex = qr/$ignore_file_regex/;
471 82 100       3125 my @autoextensions = $interp->autoextend_request_path ? @{ $interp->top_level_extensions } : ();
  77         2299  
472 82         171 my @index_names = @{ $interp->index_names };
  82         2549  
473 82         223 undef $interp; # So this doesn't end up in closure and cause cycle
474              
475             return sub {
476 205     205   411 my ( $request, $request_path ) = @_;
477 205         5258 my $interp = $request->interp;
478 205         389 my $path_info = '';
479 205         5965 my $declined_paths = $request->declined_paths;
480 205         502 my @index_subpaths = map { "/$_" } @index_names;
  399         1052  
481 205         348 my $path = $request_path;
482 205         239 my @tried_paths;
483              
484             # Deal with trailing slash
485             #
486 205 100 66     1373 $path_info = chop($path) if $path ne '/' && substr( $path, -1 ) eq '/';
487              
488 205         273 while (1) {
489 504         2967 my @candidate_paths =
490             ( $path_info eq '' && !@autoextensions ) ? ($path)
491             : ( $path eq '/' ) ? ( @index_subpaths, @dhandler_subpaths )
492             : (
493 504         1113 ( grep { !/$ignore_file_regex/ } map { $path . $_ } @autoextensions ),
  890         1805  
494 280 100 100     2039 ( map { $path . $_ } ( @index_subpaths, @dhandler_subpaths ) )
    100          
495             );
496 280         815 push( @tried_paths, @candidate_paths );
497 280         682 foreach my $candidate_path (@candidate_paths) {
498 656 100       6252 next if $declined_paths->{$candidate_path};
499 600 100       15279 if ( my $compc = $interp->load($candidate_path) ) {
500 165 100 100     2643 if (
      66        
501             $compc->cmeta->is_top_level
502             && ( $path_info eq ''
503             || $compc->cmeta->is_dhandler
504             || $compc->allow_path_info )
505             )
506             {
507 158         582 $request->{path_info} = $path_info;
508 158         667 return $compc->cmeta->path;
509             }
510             }
511             }
512 92 100       1672 $interp->_top_level_not_found( $request_path, \@tried_paths ) if $path eq '/';
513 75         4047 my $name = basename($path);
514 75 100       495 $path_info =
    100          
515             $path_info eq '/' ? "$name/"
516             : length($path_info) ? "$name/$path_info"
517             : $name;
518 75         2044 $path = dirname($path);
519 75         305 @index_subpaths = (); # only match index file in same directory
520             }
521 82         3549 };
522             }
523              
524             #
525             # PRIVATE METHODS
526             #
527              
528 20     20   15162 method _parse_global_spec () {
  11     11   19  
  11         13  
529 11         11 my $spec = shift;
530 11 100       59 croak "only scalar globals supported at this time (not '$spec')" if $spec =~ /^[@%]/;
531 10         27 $spec =~ s/^\$//;
532 10 100       131 die "'$spec' is not a valid global var name" unless $spec =~ qr/^[[:alpha:]_]\w*$/;
533 9         33 return ( '$', $spec );
534             }
535              
536 20     20   8892 method _add_default_wrap_method ($compc) {
  225     225   421  
  225         479  
  225         291  
537              
538             # Default wrap method for any component that doesn't define one.
539             # Call inner() until we're back down at the page component ($self),
540             # then call main().
541             #
542 225 100       1312 unless ( $compc->meta->has_method('wrap') ) {
543 220         20312 my $path = $compc->cmeta->path;
544             my $code = sub {
545 189     189   6282 my $self = shift;
546 189 100       632 if ( $self->cmeta->path eq $path ) {
547 153 50       858 if ( $self->can('main') ) {
548 153         969 $self->main(@_);
549             }
550             else {
551 0         0 die sprintf(
552             "component '%s' ('%s') was called but has no main method - did you forget to define 'main' or 'handle'?",
553             $path, $compc->cmeta->source_file );
554             }
555             }
556             else {
557 36         250 $compc->_inner();
558             }
559 220         1538 };
560 220         844 $compc->meta->add_augment_method_modifier( wrap => $code );
561             }
562             }
563              
564 20     20   8588 method _assert_absolute_path ($path) {
  1470     1470   1832  
  1470         1761  
  1470         1351  
565 1470   50     2954 $path ||= '';
566 1470 100       4050 croak "'$path' is not an absolute path" unless is_absolute($path);
567             }
568              
569 20     20   6998 method _check_static_source_touch_file () {
  186     186   330  
  186         243  
570              
571             # Check the static_source_touch_file, if one exists, to see if it has
572             # changed since we last checked. If it has, clear the code cache.
573             #
574 186 100       5437 if ( my $touch_file = $self->static_source_touch_file ) {
575 8 100       149 return unless -f $touch_file;
576 2         21 my $touch_file_lastmod = ( stat($touch_file) )[9];
577 2 50       9 if ( $touch_file_lastmod > $self->{static_source_touch_lastmod} ) {
578 2         9 $self->flush_code_cache;
579 2         10 $self->{static_source_touch_lastmod} = $touch_file_lastmod;
580             }
581             }
582             }
583              
584 20     20   7082 method _collect_paths_for_all_comp_roots ($code) {
  7     7   8  
  7         8  
  7         6  
585 7         8 my @paths;
586 7         7 foreach my $root_path ( @{ $self->comp_root } ) {
  7         209  
587 14         15 my $root_path_length = length($root_path);
588 14         25 my @files = $code->($root_path);
589 14         29 push( @paths, map { substr( $_, $root_path_length ) } @files );
  18         50  
590             }
591 7         22 return uniq(@paths);
592             }
593              
594 20     20   7712 method _comp_class_for_path ($path) {
  244     244   447  
  244         510  
  244         327  
595 244         814 my $classname = substr( $path, 1 );
596 244         1646 $classname =~ s/[^\w]/_/g;
597 244         631 $classname =~ s/\//::/g;
598 244         9219 $classname = join( "::", $self->component_class_prefix, $classname );
599 244         575 return $classname;
600             }
601              
602 20     20   7714 method _construct_distinct_string () {
  2     2   3  
  2         2  
603 2         4 my $number = ++$self->{distinct_string_count};
604 2         6 my $str = $self->_construct_distinct_string_for_number($number);
605 2         4 return $str;
606             }
607              
608 20     20   6429 method _construct_distinct_string_for_number ($number) {
  2     2   3  
  2         3  
  2         2  
609 2         3 my $distinct_delimeter = "__MASON__";
610 2         9 return sprintf( "%s%d%s", $distinct_delimeter, $number, $distinct_delimeter );
611             }
612              
613 20     20   6421 method _default_parent_path ($orig_path) {
  298     298   463  
  298         483  
  298         356  
614              
615             # Given /foo/bar.mc, look for (by default):
616             # /foo/Base.mp, /foo/Base.mc,
617             # /Base.mp, /Base.mc
618             #
619             # Split path into dir_path and base_name - validate that it has a
620             # starting slash and ends with at least one non-slash character
621             #
622 298 50       2853 my ( $dir_path, $base_name ) = ( $orig_path =~ m{^(/.*?)/?([^/]+)$} )
623             or die "not a valid absolute component path - '$orig_path'";
624 298         586 my $path = $dir_path;
625              
626 298         434 my @autobase_subpaths = map { "/$_" } @{ $self->autobase_names };
  590         1690  
  298         9023  
627 298         514 while (1) {
628 389         802 my @candidate_paths =
629             ( $path eq '/' )
630             ? @autobase_subpaths
631 466 100       1459 : ( map { $path . $_ } @autobase_subpaths );
632 466 100   881   2991 if ( ( my $index = first_index { $_ eq $orig_path } @candidate_paths ) != -1 ) {
  881         3003  
633 47         155 splice( @candidate_paths, 0, $index + 1 );
634             }
635 466         1613 foreach my $candidate_path (@candidate_paths) {
636 816 100       20168 if ( $self->comp_exists($candidate_path) ) {
637 74         1077 return $candidate_path;
638             }
639             }
640 392 100       5009 if ( $path eq '/' ) {
641 224         790 return '/';
642             }
643 168         6322 $path = dirname($path);
644             }
645             }
646              
647 20     20   10666 method _determine_parent_compc ($path, $flags) {
  244     244   398  
  244         510  
  244         309  
648 244         305 my $parent_compc;
649 244 100       829 if ( exists( $flags->{extends} ) ) {
650 13         20 my $extends = $flags->{extends};
651 13 100       29 if ( defined($extends) ) {
652 11 100       88 $extends = mason_canon_path( join( "/", dirname($path), $extends ) )
653             if substr( $extends, 0, 1 ) ne '/';
654 11 100       228 $parent_compc = $self->load($extends)
655             or die "could not load '$extends' for extends flag";
656             }
657             else {
658 2         68 $parent_compc = $self->component_class;
659             }
660             }
661 235         8850 return $parent_compc;
662             }
663              
664 20     20   8154 method _extract_flags_from_object_file ($object_file) {
  244     244   376  
  244         378  
  244         266  
665 244         512 my $flags = {};
666 244 50       8939 open( my $fh, "<", $object_file ) or die "could not open '$object_file': $!";
667 244         3970 my $line = <$fh>;
668 244 100       1421 if ( my ($flags_str) = ( $line =~ /\# FLAGS: (.*)/ ) ) {
669 13         52 $flags = json_decode($flags_str);
670             }
671 244         2789 return $flags;
672             }
673              
674 20     20   7809 method _flush_load_cache () {
  378     378   735  
  378         511  
675 378         1544 Memoize::flush_cache('comp_exists');
676 378         25937 Memoize::flush_cache('load');
677             }
678              
679 20     20   6197 method _make_request () {
  185     185   302  
  185         268  
680 185         7761 return $self->request_class->new( interp => $self, %{ $self->request_params }, @_ );
  185         5837  
681             }
682              
683 20     20   6427 method _object_file_for_path ($path) {
  270     270   391  
  270         390  
  270         319  
684 270         911 return catfile( $self->object_dir, ( split /\//, $path ) ) . $self->object_file_extension;
685             }
686              
687 20     20   7014 method _source_file_for_path ($path) {
  1282     1282   1657  
  1282         1721  
  1282         1326  
688 1282         2514 $self->_assert_absolute_path($path);
689 1281         1656 foreach my $root_path ( @{ $self->comp_root } ) {
  1281         37358  
690 1281         2429 my $source_file = $root_path . $path;
691 1281 100       34524 return $source_file if -f $source_file;
692             }
693 939         4380 return undef;
694             }
695              
696 20     20   7309 method _top_level_not_found ($path, $tried_paths) {
  17     17   60  
  17         61  
  17         46  
697 17         113 my @combined_paths = combine_similar_paths(@$tried_paths);
698 116         259 Mason::Exception::TopLevelNotFound->throw(
699             error => sprintf(
700             "could not resolve request path '%s'; searched for components (%s) under %s\n",
701             $path,
702 17         678 join( ", ", map { "'$_'" } @combined_paths ),
703 0         0 @{ $self->comp_root } > 1
704 17 50       69 ? "component roots " . join( ", ", map { "'$_'" } @{ $self->comp_root } )
  0         0  
705             : "component root '" . $self->comp_root->[0] . "'"
706             )
707             );
708             }
709              
710 20     20   8485 method _validate_allow_globals () {
  3     3   6  
  3         5  
711              
712             # Will build allowed_globals_hash and also validate the param
713             #
714 3         87 $self->allowed_globals_hash;
715             }
716              
717             #
718             # Class overrides. Put here at the bottom because it strangely messes up
719             # Perl line numbering if at the top.
720             #
721             sub _define_class_override_methods {
722 20     20   207 my %class_overrides = (
723             code_cache_class => 'CodeCache',
724             compilation_class => 'Compilation',
725             component_class => 'Component',
726             component_class_meta_class => 'Component::ClassMeta',
727             component_import_class => 'Component::Import',
728             component_moose_class => 'Component::Moose',
729             request_class => 'Request',
730             result_class => 'Result',
731             );
732              
733             # e.g.
734             # $method_name = component_moose_class
735             # $base_method_name = base_component_moose_class
736             # $name = Component::Moose
737             # $default_base_class = Mason::Component::Moose
738             #
739 20         126 while ( my ( $method_name, $name ) = each(%class_overrides) ) {
740 160         7109 my $base_method_name = "base_$method_name";
741 160         670 has $method_name => ( init_arg => undef, lazy_build => 1 );
742 160         28370 has $base_method_name => ( isa => 'Str', lazy_build => 1 );
743             __PACKAGE__->meta->add_method(
744             "_build_$method_name" => sub {
745 625     625   1566 my $self = shift;
        625      
        625      
        625      
        625      
        625      
        625      
        625      
        625      
746 625         21554 my $base_class = $self->$base_method_name;
747 625         2280 Class::Load::load_class($base_class);
748 625         34674 return Mason::PluginManager->apply_plugins_to_class( $base_class, $name,
749             $self->plugins );
750             }
751 160         29643 );
752             __PACKAGE__->meta->add_method(
753             "_build_$base_method_name" => sub {
754 624     624   1241 my $self = shift;
        624      
        624      
        624      
        624      
        624      
        624      
        624      
        624      
755 632         3533 my @candidates =
756 624         19847 map { join( '::', $_, $name ) } ( uniq( $self->mason_root_class, 'Mason' ) );
757 624 50       1472 my ($base_class) = grep { can_load($_) } @candidates
  632         2304  
758             or die
759             sprintf( "cannot load %s for %s", join( ', ', @candidates ), $base_method_name );
760 624         23262 return $base_class;
761             }
762 160         9122 );
763             }
764             }
765              
766             __PACKAGE__->meta->make_immutable();
767              
768             1;
769              
770             __END__
771              
772             =pod
773              
774             =head1 NAME
775              
776             Mason::Interp - Mason Interpreter
777              
778             =head1 SYNOPSIS
779              
780             my $interp = Mason->new(
781             comp_root => '/path/to/comps',
782             data_dir => '/path/to/data',
783             ...
784             );
785             my $output = $interp->run( '/request/path', foo => 5 )->output();
786              
787             =head1 DESCRIPTION
788              
789             Interp is the central Mason object, returned from C<< Mason->new >>. It is
790             responsible for creating new requests, compiling components, and maintaining
791             the cache of loaded components.
792              
793             =head1 PARAMETERS TO THE new() CONSTRUCTOR
794              
795             =over
796              
797             =item allow_globals (varnames)
798              
799             List of one or more global variable names that will be available in all
800             components, like C<< $m >> is by default.
801              
802             allow_globals => [qw($dbh)]
803              
804             As in any programming environment, globals should be created sparingly (if at
805             all) and only when other mechanisms (parameter passing, attributes, singletons)
806             will not suffice. L<Catalyst::View::Mason2|Catalyst::View::Mason2>, for
807             example, creates a C<< $c >> global set to the context object in each request.
808              
809             Set the values of globals with L<set_global|/set_global>.
810              
811             =item autobase_names
812              
813             Array reference of L<autobase|Mason::Manual/Autobase components> filenames to
814             check in order when determining a component's superclass. Default is C<<
815             ["Base.mp", "Base.mc"] >>.
816              
817             =item autoextend_request_path
818              
819             Whether to automatically add the L<top level extensions|/top_level_extensions>
820             (by default ".mp" and ".mc") to the request path when searching for a matching
821             page component. Defaults to true.
822              
823             =item class_header
824              
825             Perl code to be added at the top of the compiled class for every component,
826             e.g. to bring in common features or import common methods. Default is the empty
827             string.
828              
829             # Add to the top of every component class:
830             # use Modern::Perl;
831             # use JSON::XS qw(encode_json decode_json);
832             #
833             my $mason = Mason->new(
834             ...
835             class_header => qq(
836             use Modern::Perl;
837             use JSON::XS qw(encode_json decode_json);
838             ),
839             );
840              
841             This is used by
842             L<Mason::Compilation::output_class_header|Mason::Compilation/output_class_header>.
843             For more advanced usage you can override that method in a subclass or plugin.
844              
845             =item comp_root
846              
847             Required. The component root marks the top of your component hierarchy and
848             defines how component paths are translated into real file paths. For example,
849             if your component root is F</usr/local/httpd/docs>, a component path of
850             F</products/sales.mc> translates to the file
851             F</usr/local/httpd/docs/products/sales.mc>.
852              
853             This parameter may be either a single path or an array reference of paths. If
854             it is an array reference, the paths will be searched in the provided order
855             whenever a component path is resolved, much like Perl's C<< @INC >>.
856              
857             =item component_class_prefix
858              
859             Prefix to use in generated component classnames. Defaults to 'MC' plus the
860             interpreter's count, e.g. MC0. So a component '/foo/bar' would get a classname
861             like 'MC0::foo::bar'.
862              
863             =item data_dir
864              
865             The data directory is a writable directory that Mason uses for various features
866             and optimizations: for example, component object files and data cache files.
867             Mason will create the directory on startup if necessary.
868              
869             Defaults to a temporary directory that will be cleaned up at process end. This
870             will hurt performance as Mason will have to recompile components on each run.
871              
872             =item dhandler_names
873              
874             Array reference of dhandler file names to check in order when resolving a
875             top-level path. Default is C<< ["dhandler.mp", "dhandler.mc"] >>. An empty list
876             disables this feature.
877              
878             =item index_names
879              
880             Array reference of index file names to check in order when resolving a
881             top-level path. Default is C<< ["index.mp", "index.mc"] >>. An empty list
882             disables this feature.
883              
884             =item no_source_line_numbers
885              
886             Do not put in source line number comments when generating code. Setting this
887             to true will cause error line numbers to reflect the real object file, rather
888             than the source component.
889              
890             =item object_file_extension
891              
892             Extension to add to the end of object files. Default is ".mobj".
893              
894             =item plugins
895              
896             A list of plugins and/or plugin bundles:
897              
898             plugins => [
899             'OnePlugin',
900             'AnotherPlugin',
901             '+My::Mason::Plugin::AThirdPlugin',
902             '@APluginBundle',
903             '-DontLikeThisPlugin',
904             ]);
905              
906             See L<Mason::Manual::Plugins>.
907              
908             =item out_method
909              
910             Default L<out_method|Mason::Request/out_method> passed to each new request.
911              
912             =item pure_perl_extensions
913              
914             A listref of file extensions of components to be considered as pure perl (see
915             L<Pure Perl Components|Mason::Manual::Syntax/Pure_Perl_Components>). Default is
916             C<< ['.mp'] >>. If an empty list is specified, then no components will be
917             considered pure perl.
918              
919             =item static_source
920              
921             True or false, default is false. When false, Mason checks the timestamp of the
922             component source file each time the component is used to see if it has changed.
923             This provides the instant feedback for source changes that is expected for
924             development. However it does entail a file stat for each component executed.
925              
926             When true, Mason assumes that the component source tree is unchanging: it will
927             not check component source files to determine if the memory cache or object
928             file has expired. This can save many file stats per request. However, in order
929             to get Mason to recognize a component source change, you must touch the
930             L<static_source_touch_file|/static_source_touch_file>.
931              
932             We recommend turning this mode on in your production sites if possible, if
933             performance is of any concern.
934              
935             =item static_source_touch_file
936              
937             Specifies a filename that Mason will check once at the beginning of every
938             request when in L<static_source|/static_source> mode. When the file timestamp
939             changes (indicating that a component has changed), Mason will clear its
940             in-memory component cache and recheck existing object files.
941              
942             =item top_level_extensions
943              
944             A listref of file extensions of components to be considered "top level",
945             accessible directly from C<< $interp->run >> or a web request. Default is C<<
946             ['.mp', '.mc'] >>. If an empty list is specified, then there will be I<no>
947             restriction; that is, I<all> components will be considered top level.
948              
949             =back
950              
951             =head1 CUSTOM MASON CLASSES
952              
953             These parameters specify alternate classes to use instead of the default
954             Mason:: classes.
955              
956             For example, to use your own Compilation base class:
957              
958             my $interp = Mason->new(base_compilation_class => 'MyApp::Mason::Compilation', ...);
959              
960             L<Relevant plugins|Mason::Manual::Plugins>, if any, will applied to this class
961             to create a final class, which you can get with
962              
963             $interp->compilation_class
964              
965             =over
966              
967             =item base_code_cache_class
968              
969             Specify alternate to L<Mason::CodeCache|Mason::CodeCache>
970              
971             =item base_compilation_class
972              
973             Specify alternate to L<Mason::Compilation|Mason::Compilation>
974              
975             =item base_component_class
976              
977             Specify alternate to L<Mason::Component|Mason::Component>
978              
979             =item base_component_moose_class
980              
981             Specify alternate to L<Mason::Component::Moose|Mason::Component::Moose>
982              
983             =item base_component_class_meta_class
984              
985             Specify alternate to L<Mason::Component::ClassMeta|Mason::Component::ClassMeta>
986              
987             =item base_component_import_class
988              
989             Specify alternate to L<Mason::Component::Import|Mason::Component::Import>
990              
991             =item base_request_class
992              
993             Specify alternate to L<Mason::Request|Mason::Request>
994              
995             =item base_result_class
996              
997             Specify alternate to L<Mason::Result|Mason::Result>
998              
999             =back
1000              
1001             =head1 PUBLIC METHODS
1002              
1003             =over
1004              
1005             =item all_paths ([dir_path])
1006              
1007             Returns a list of distinct component paths under I<dir_path>, which defaults to
1008             '/' if not provided. For example,
1009              
1010             $interp->all_paths('/foo/bar')
1011             => ('/foo/bar/baz.mc', '/foo/bar/blargh.mc')
1012              
1013             Note that these are all component paths, not filenames, and all component roots
1014             are searched if there are multiple ones.
1015              
1016             =item comp_exists (path)
1017              
1018             Returns a boolean indicating whether a component exists for the absolute
1019             component I<path>.
1020              
1021             =item count
1022              
1023             Returns the number of this interpreter, a monotonically increasing integer for
1024             the process starting at 0.
1025              
1026             =item flush_code_cache
1027              
1028             Empties the component cache and removes all component classes.
1029              
1030             =item glob_paths (pattern)
1031              
1032             Returns a list of all component paths matching the glob I<pattern>. e.g.
1033              
1034             $interp->glob_paths('/foo/b*.mc')
1035             => ('/foo/bar.mc', '/foo/baz.mc')
1036              
1037             Note that these are all component paths, not filenames, and all component roots
1038             are searched if there are multiple ones.
1039              
1040             =item load (path)
1041              
1042             Returns the component object corresponding to an absolute component I<path>, or
1043             undef if none exists. Dies with an error if the component fails to load because
1044             of a syntax error.
1045              
1046             =item object_dir
1047              
1048             Returns the directory containing component object files.
1049              
1050             =item run ([request params], path, args...)
1051              
1052             Creates a new L<Mason::Request|Mason::Request> object for the given I<path> and
1053             I<args>, and executes it. Returns a L<Mason::Result|Mason::Result> object,
1054             which is generally accessed to get the output. e.g.
1055              
1056             my $output = $interp->run('/foo/bar', baz => 5)->output;
1057              
1058             The first argument may optionally be a hashref of request parameters, which are
1059             passed to the Mason::Request constructor. e.g. this tells the request to output
1060             to standard output:
1061              
1062             $interp->run({out_method => sub { print $_[0] }}, '/foo/bar', baz => 5);
1063              
1064             =item set_global (varname, value)
1065              
1066             Set the global I<varname> to I<value>. This will be visible in all components
1067             loaded by this interpreter. The variables must be on the
1068             L<allow_globals|/allow_globals> list.
1069              
1070             $interp->set_global('$scalar', 5);
1071             $interp->set_global('$scalar2', $some_object);
1072              
1073             See also L<set_global|Mason::Request/set_global>.
1074              
1075             =back
1076              
1077             =head1 MODIFIABLE METHODS
1078              
1079             These methods are not intended to be called externally, but may be useful to
1080             modify with method modifiers in L<plugins|Mason::Manual::Plugins> and
1081             L<subclasses|Mason::Manual::Subclasses>. Their APIs will be kept as stable as
1082             possible.
1083              
1084             =over
1085              
1086             =item is_pure_perl_comp_path ($path)
1087              
1088             Determines whether I<$path> is a pure Perl component - by default, uses
1089             L<pure_perl_extensions|/pure_perl_extensions>.
1090              
1091             =item is_top_level_comp_path ($path)
1092              
1093             Determines whether I<$path> is a valid top-level component - by default, uses
1094             L<top_level_extensions|/top_level_extensions>.
1095              
1096             =item modify_loaded_class ( $compc )
1097              
1098             An opportunity to modify loaded component class I<$compc> (e.g. add additional
1099             methods or apply roles) before it is made immutable.
1100              
1101             =item write_object_file ($object_file, $object_contents)
1102              
1103             Write compiled component I<$object_contents> to I<$object_file>. This is an
1104             opportunity to modify I<$object_contents> before it is written, or
1105             I<$object_file> after it is written.
1106              
1107             =back
1108              
1109             =head1 SEE ALSO
1110              
1111             L<Mason|Mason>
1112              
1113             =head1 AUTHOR
1114              
1115             Jonathan Swartz <swartz@pobox.com>
1116              
1117             =head1 COPYRIGHT AND LICENSE
1118              
1119             This software is copyright (c) 2012 by Jonathan Swartz.
1120              
1121             This is free software; you can redistribute it and/or modify it under
1122             the same terms as the Perl 5 programming language system itself.
1123              
1124             =cut