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.23';
3 27     27   144 use Carp;
  27         54  
  27         1236  
4 28     27   9274 use Devel::GlobalDestruction;
  28         35580  
  28         181  
5 30     25   1490 use File::Basename;
  30         56  
  30         1074  
6 29     25   147 use File::Path;
  29         194  
  29         908  
7 29     25   150 use File::Temp qw(tempdir);
  29         39  
  29         753  
8 27     20   9553 use Guard;
  27         10008  
  27         1065  
9 28     20   6791 use Mason::CodeCache;
  28         88  
  28         1276  
10 29     20   12231 use Mason::Request;
  29         83  
  29         1270  
11 28     20   9720 use Mason::Result;
  28         69  
  28         889  
12 23     20   183 use Mason::Types;
  23         33  
  23         607  
13             use Mason::Util
14 22     20   98 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         2513  
15 22     20   116 use Class::Load;
  22         27  
  22         987  
16 22     20   14299 use Memoize;
  22         41100  
  22         1076  
17 22     20   142 use Moose::Util::TypeConstraints;
  22         37  
  22         299  
18 22     20   35257 use Mason::Moose;
  22         40  
  22         156  
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   50431 method current_load_interp () { $current_load_interp }
  228     227   624  
  228         414  
  228         664  
64              
65             #
66             # BUILD
67             #
68              
69 22     20   6905 method BUILD ($params) {
  107     106   193  
  107         189  
  107         159  
70              
71             # Initialize static source mode
72             #
73 107 100       362 if ( $self->{static_source} ) {
74 3   33     9 $self->{static_source_touch_file} ||= catfile( $self->data_dir, 'purge.dat' );
75 3         15 $self->{static_source_touch_lastmod} = 0;
76 2         7 $self->_check_static_source_touch_file();
77             }
78              
79             # Separate out request parameters
80             #
81 106         311 $self->{request_params} = {};
82 1696   66     12540 my %is_request_attribute =
83 106         3037 map { ( $_->init_arg || $_->name, 1 ) } $self->request_class->meta->get_all_attributes();
84 106         690 foreach my $key ( keys(%$params) ) {
85 461 100       4026 if ( $is_request_attribute{$key} ) {
86 1         4 $self->{request_params}->{$key} = delete( $params->{$key} );
87             }
88             }
89             }
90              
91 22     20   8575 method _build_allowed_globals_hash () {
  3     3   8  
  3         5  
92 3         4 my @allow_globals = uniq( @{ $self->allow_globals } );
  3         96  
93 3         8 my @canon_globals = map { join( "", $self->_parse_global_spec($_) ) } @allow_globals;
  4         14  
94 1         2 return { map { ( $_, 1 ) } @canon_globals };
  2         28  
95             }
96              
97 22     20   7332 method _build_globals_package () {
  1     1   1  
  1         2  
98 1         22 return "Mason::Globals" . $self->id;
99             }
100              
101 22     20   5935 method _build_autobase_names () {
  85     85   148  
  85         117  
102 85         151 return [ map { "Base" . $_ } @{ $self->top_level_extensions } ];
  163         2224  
  85         2363  
103             }
104              
105 22     20   6697 method _build_code_cache () {
  85     85   165  
  85         139  
106 85         2599 return $self->code_cache_class->new();
107             }
108              
109 21     20   5962 method _build_component_class_prefix () {
  73     73   137  
  73         86  
110 73         1882 return "MC" . $self->id;
111             }
112              
113 21     20   6058 method _build_data_dir () {
  1     1   2  
  1         2  
114 1         53 return tempdir( 'mason-data-XXXX', TMPDIR => 1, CLEANUP => 1 );
115             }
116              
117 21     20   6239 method _build_dhandler_names () {
  77     77   183  
  77         450  
118 77         122 return [ map { "dhandler" . $_ } @{ $self->top_level_extensions } ];
  147         2253  
  77         2389  
119             }
120              
121 21     20   6428 method _build_index_names () {
  72     72   142  
  72         113  
122 72         106 return [ map { "index" . $_ } @{ $self->top_level_extensions } ];
  137         1999  
  72         2001  
123             }
124              
125 21     20   6683 method _build_pure_perl_regex () {
  74     74   112  
  74         100  
126 74         2102 my $extensions = $self->pure_perl_extensions;
127 74 100       253 if ( !@$extensions ) {
128 1         24 return qr/(?!)/; # matches nothing
129             }
130             else {
131 73         282 my $regex = join( '|', @$extensions ) . '$';
132 73         2294 return qr/$regex/;
133             }
134             }
135              
136 21     20   6938 method _build_top_level_regex () {
  74     74   140  
  74         106  
137 74         1984 my $extensions = $self->top_level_extensions;
138 74 100       260 if ( !@$extensions ) {
139 2         48 return qr/./; # matches everything
140             }
141             else {
142 72         230 my $regex = join( '|', @$extensions );
143 72 100       111 if ( my @other_names = grep { !/$regex/ } @{ $self->dhandler_names },
  273         1524  
  72         1903  
  72         2128  
144             @{ $self->index_names } )
145             {
146 17         71 $regex .= '|(?:/(?:' . join( '|', @other_names ) . '))';
147             }
148 72         240 $regex = '(?:' . $regex . ')$';
149 72         2665 return qr/$regex/;
150             }
151             }
152              
153             #
154             # PUBLIC METHODS
155             #
156              
157 20     20   8330 method all_paths ($dir_path) {
  4     4   10  
  4         6  
  4         5  
158 4   100     16 $dir_path ||= '/';
159 4         11 $self->_assert_absolute_path($dir_path);
160             return $self->_collect_paths_for_all_comp_roots(
161             sub {
162 8     8   11 my $root_path = shift;
163 8         12 my $dir = $root_path . $dir_path;
164 8 100       155 return ( -d $dir ) ? find_wanted( sub { -f }, $dir ) : ();
  24         760  
165             }
166 4         26 );
167             }
168              
169 20     20   7598 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   7447 method flush_code_cache () {
  87     87   160  
  87         139  
181 87         2338 my $code_cache = $self->code_cache;
182              
183 87         517 foreach my $key ( $code_cache->get_keys() ) {
184 196         738 $code_cache->remove($key);
185             }
186             }
187              
188 20     20   6293 method glob_paths ($glob_pattern) {
  3     3   4  
  3         6  
  3         4  
189             return $self->_collect_paths_for_all_comp_roots(
190             sub {
191 6     6   6 my $root_path = shift;
192 6         228 return glob( $root_path . $glob_pattern );
193             }
194 3         16 );
195             }
196              
197             our $in_load = 0;
198              
199 20     20   7223 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   16607 method _superclass_signature ($compc) {
  260     260   522  
  260         516  
  260         360  
328 260         1182 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         19164 foreach my $superclass (@superclasses) {
334 260 100       2280 if ( my $cmeta = $superclass->cmeta ) {
335 71         2539 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       2700 return join( ",", map { join( "-", $_, $_->cmeta ? $_->cmeta->id : 0 ) } @superclasses );
  260         917  
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   8356 method object_dir () {
  270     270   493  
  270         391  
355 270         7310 return catdir( $self->data_dir, 'obj' );
356             }
357              
358 20     20   6544 method run () {
  184     184   358  
  184         260  
359 184         315 my %request_params;
360 184 100       777 if ( ref( $_[0] ) eq 'HASH' ) {
361 11         12 %request_params = %{ shift(@_) };
  11         34  
362             }
363 184         332 my $path = shift;
364 184         720 my $request = $self->_make_request(%request_params);
365 184         1078 $request->run( $path, @_ );
366             }
367              
368 20     20   7373 method set_global () {
  3     3   3  
  3         4  
369 3         4 my ( $spec, $value ) = @_;
370 3 50       6 croak "set_global expects a var name and value" unless $value;
371 3         5 my ( $sigil, $name ) = $self->_parse_global_spec($spec);
372 3 100       75 croak "${sigil}${name} is not in the allowed globals list"
373             unless $self->allowed_globals_hash->{"${sigil}${name}"};
374              
375 2         46 my $varname = sprintf( "%s::%s", $self->globals_package, $name );
376 20     20   2631 no strict 'refs';
  20         45  
  20         775  
377 20     20   120 no warnings 'once';
  20         34  
  20         822  
378 2         11 $$varname = $value;
379             }
380              
381             #
382             # MODIFIABLE METHODS
383             #
384              
385 20     20   5774 method DEMOLISH () {
  109     109   273  
  109         161  
386 109 50       2090 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       1216 $self->flush_code_cache() if defined( $self->{code_cache} );
392             }
393              
394 20     20   6776 method _compile ($source_file, $path) {
  237     237   405  
  237         453  
  237         336  
395 237         8083 my $compilation = $self->compilation_class->new(
396             source_file => $source_file,
397             path => $path,
398             interp => $self
399             );
400 237         1348 return $compilation->compile();
401             }
402              
403 20     20   6964 method _compile_to_file ($source_file, $path, $object_file) {
  233     233   419  
  233         449  
  233         292  
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     3066 if ( defined $object_file && !-f $object_file ) {
411 225         7580 my ($dirname) = dirname($object_file);
412 225 100       3024 if ( !-d $dirname ) {
413 95 50       275 unlink($dirname) if ( -e _ );
414 95         22883 mkpath( $dirname, 0, 0775 );
415             }
416 225 50       3046 rmtree($object_file) if ( -d $object_file );
417             }
418 233         1067 my $object_contents = $self->_compile( $source_file, $path );
419              
420 207         1283 $self->write_object_file( $object_file, $object_contents );
421             }
422              
423 20     20   8561 method is_pure_perl_comp_path ($path) {
  237     237   410  
  237         365  
  237         302  
424 237 100       6266 return ( $path =~ $self->pure_perl_regex ) ? 1 : 0;
425             }
426              
427 20     20   6509 method is_top_level_comp_path ($path) {
  211     211   391  
  211         330  
  211         278  
428 211 100       5327 return ( $path =~ $self->top_level_regex ) ? 1 : 0;
429             }
430              
431 20     20   6830 method _load_class_from_object_file ($compc, $object_file, $path, $default_parent_path) {
  244     244   370  
  244         498  
  244         280  
432 244         755 my $flags = $self->_extract_flags_from_object_file($object_file);
433 244   66     947 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         2310 my $code = sprintf( 'package %s; use Moose; extends \'%s\'; do(\'%s\'); die $@ if $@',
439             $compc, $parent_compc, $object_file );
440 227 50       926 ($code) = ( $code =~ /^(.*)/s ) if taint_is_on();
441 19     19   141 eval($code);
  19     15   27  
  19     9   159  
  15     5   110  
  15     1   22  
  15     1   129  
  9         66  
  9         17  
  9         72  
  6         38  
  6         10  
  6         43  
  4         27  
  4         6  
  4         27  
  3         23  
  3         4  
  3         22  
  3         21  
  3         5  
  3         22  
  3         23  
  3         7  
  3         23  
  3         21  
  3         4  
  3         23  
  3         20  
  3         3  
  3         21  
  3         21  
  3         4  
  3         24  
  3         21  
  3         4  
  3         24  
  3         21  
  3         5  
  3         21  
  3         19  
  3         5  
  3         22  
  3         22  
  3         3  
  3         22  
  3         20  
  3         5  
  3         21  
  2         13  
  2         3  
  2         15  
  2         13  
  2         2  
  2         14  
  2         14  
  2         4  
  2         14  
  2         15  
  2         2  
  2         15  
  1         7  
  1         1  
  1         7  
  1         6  
  1         2  
  1         6  
  1         5  
  1         3  
  1         5  
  1         6  
  1         1  
  1         8  
  1         7  
  1         2  
  1         8  
  1         7  
  1         1  
  1         7  
  1         7  
  1         3  
  1         7  
  1         7  
  1         1  
  1         7  
  1         7  
  1         2  
  1         8  
  1         8  
  1         2  
  1         7  
  9         70  
  9         16  
  9         78  
  6         42  
  6         8  
  6         46  
  3         23  
  3         4  
  3         25  
  6         45  
  6         10  
  6         47  
  227         21127  
  1         10  
  1         3  
  1         12  
  1         9  
  1         2  
  1         11  
442 227 100       1183 die $@ if $@;
443              
444 225         1234 $compc->_set_class_cmeta($self);
445 225         911 $self->modify_loaded_class($compc);
446             }
447              
448 20     20   8994 method modify_loaded_class ($compc) {
  225     225   416  
  225         356  
  225         306  
449 225         926 $self->_add_default_wrap_method($compc);
450             }
451              
452 20     20   6550 method write_object_file ($object_file, $object_contents) {
  207     207   339  
  207         392  
  207         268  
453 207         789 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   7006 method _build_match_request_path ($interp:) {
  82     82   161  
  82         126  
464              
465             # Create a closure for efficiency - all this data is immutable for an interp.
466             #
467 82         125 my @dhandler_subpaths = map { "/$_" } @{ $interp->dhandler_names };
  149         431  
  82         4146  
468 82         2624 my $ignore_file_regex =
469 82         165 '(/' . join( "|", @{ $interp->autobase_names }, @{ $interp->dhandler_names } ) . ')$';
  82         2221  
470 82         1506 $ignore_file_regex = qr/$ignore_file_regex/;
471 82 100       2571 my @autoextensions = $interp->autoextend_request_path ? @{ $interp->top_level_extensions } : ();
  77         1856  
472 82         261 my @index_names = @{ $interp->index_names };
  82         2117  
473 82         165 undef $interp; # So this doesn't end up in closure and cause cycle
474              
475             return sub {
476 205     205   335 my ( $request, $request_path ) = @_;
477 205         4884 my $interp = $request->interp;
478 205         330 my $path_info = '';
479 205         5824 my $declined_paths = $request->declined_paths;
480 205         501 my @index_subpaths = map { "/$_" } @index_names;
  399         1059  
481 205         385 my $path = $request_path;
482 205         234 my @tried_paths;
483              
484             # Deal with trailing slash
485             #
486 205 100 66     1413 $path_info = chop($path) if $path ne '/' && substr( $path, -1 ) eq '/';
487              
488 205         280 while (1) {
489 504         2602 my @candidate_paths =
490             ( $path_info eq '' && !@autoextensions ) ? ($path)
491             : ( $path eq '/' ) ? ( @index_subpaths, @dhandler_subpaths )
492             : (
493 504         1011 ( grep { !/$ignore_file_regex/ } map { $path . $_ } @autoextensions ),
  890         1661  
494 280 100 100     1836 ( map { $path . $_ } ( @index_subpaths, @dhandler_subpaths ) )
    100          
495             );
496 280         706 push( @tried_paths, @candidate_paths );
497 280         555 foreach my $candidate_path (@candidate_paths) {
498 656 100       4701 next if $declined_paths->{$candidate_path};
499 600 100       11737 if ( my $compc = $interp->load($candidate_path) ) {
500 165 100 100     2471 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         551 $request->{path_info} = $path_info;
508 158         587 return $compc->cmeta->path;
509             }
510             }
511             }
512 92 100       1162 $interp->_top_level_not_found( $request_path, \@tried_paths ) if $path eq '/';
513 75         2299 my $name = basename($path);
514 75 100       307 $path_info =
    100          
515             $path_info eq '/' ? "$name/"
516             : length($path_info) ? "$name/$path_info"
517             : $name;
518 75         3338 $path = dirname($path);
519 75         197 @index_subpaths = (); # only match index file in same directory
520             }
521 82         2809 };
522             }
523              
524             #
525             # PRIVATE METHODS
526             #
527              
528 20     20   15192 method _parse_global_spec () {
  11     11   15  
  11         13  
529 11         11 my $spec = shift;
530 11 100       70 croak "only scalar globals supported at this time (not '$spec')" if $spec =~ /^[@%]/;
531 10         22 $spec =~ s/^\$//;
532 10 100       116 die "'$spec' is not a valid global var name" unless $spec =~ qr/^[[:alpha:]_]\w*$/;
533 9         27 return ( '$', $spec );
534             }
535              
536 20     20   9171 method _add_default_wrap_method ($compc) {
  225     225   327  
  225         384  
  225         258  
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       1012 unless ( $compc->meta->has_method('wrap') ) {
543 220         16436 my $path = $compc->cmeta->path;
544             my $code = sub {
545 189     189   5468 my $self = shift;
546 189 100       561 if ( $self->cmeta->path eq $path ) {
547 153 50       895 if ( $self->can('main') ) {
548 153         838 $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         219 $compc->_inner();
558             }
559 220         1436 };
560 220         905 $compc->meta->add_augment_method_modifier( wrap => $code );
561             }
562             }
563              
564 20     20   8670 method _assert_absolute_path ($path) {
  1470     1470   1571  
  1470         1556  
  1470         1464  
565 1470   50     2531 $path ||= '';
566 1470 100       3512 croak "'$path' is not an absolute path" unless is_absolute($path);
567             }
568              
569 20     20   7242 method _check_static_source_touch_file () {
  186     186   559  
  186         278  
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       5333 if ( my $touch_file = $self->static_source_touch_file ) {
575 8 100       140 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         8 $self->flush_code_cache;
579 2         9 $self->{static_source_touch_lastmod} = $touch_file_lastmod;
580             }
581             }
582             }
583              
584 20     20   7318 method _collect_paths_for_all_comp_roots ($code) {
  7     7   7  
  7         10  
  7         9  
585 7         7 my @paths;
586 7         8 foreach my $root_path ( @{ $self->comp_root } ) {
  7         227  
587 14         18 my $root_path_length = length($root_path);
588 14         24 my @files = $code->($root_path);
589 14         30 push( @paths, map { substr( $_, $root_path_length ) } @files );
  18         43  
590             }
591 7         25 return uniq(@paths);
592             }
593              
594 20     20   8488 method _comp_class_for_path ($path) {
  244     244   460  
  244         480  
  244         323  
595 244         630 my $classname = substr( $path, 1 );
596 244         1493 $classname =~ s/[^\w]/_/g;
597 244         585 $classname =~ s/\//::/g;
598 244         8350 $classname = join( "::", $self->component_class_prefix, $classname );
599 244         578 return $classname;
600             }
601              
602 20     20   7912 method _construct_distinct_string () {
  2     2   5  
  2         2  
603 2         8 my $number = ++$self->{distinct_string_count};
604 2         7 my $str = $self->_construct_distinct_string_for_number($number);
605 2         9 return $str;
606             }
607              
608 20     20   6819 method _construct_distinct_string_for_number ($number) {
  2     2   5  
  2         4  
  2         3  
609 2         6 my $distinct_delimeter = "__MASON__";
610 2         20 return sprintf( "%s%d%s", $distinct_delimeter, $number, $distinct_delimeter );
611             }
612              
613 20     20   6888 method _default_parent_path ($orig_path) {
  298     298   489  
  298         504  
  298         340  
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       2771 my ( $dir_path, $base_name ) = ( $orig_path =~ m{^(/.*?)/?([^/]+)$} )
623             or die "not a valid absolute component path - '$orig_path'";
624 298         520 my $path = $dir_path;
625              
626 298         419 my @autobase_subpaths = map { "/$_" } @{ $self->autobase_names };
  590         1521  
  298         8592  
627 298         491 while (1) {
628 389         728 my @candidate_paths =
629             ( $path eq '/' )
630             ? @autobase_subpaths
631 466 100       1389 : ( map { $path . $_ } @autobase_subpaths );
632 466 100   881   2476 if ( ( my $index = first_index { $_ eq $orig_path } @candidate_paths ) != -1 ) {
  881         2891  
633 47         129 splice( @candidate_paths, 0, $index + 1 );
634             }
635 466         1525 foreach my $candidate_path (@candidate_paths) {
636 816 100       19077 if ( $self->comp_exists($candidate_path) ) {
637 74         1096 return $candidate_path;
638             }
639             }
640 392 100       4537 if ( $path eq '/' ) {
641 224         762 return '/';
642             }
643 168         4996 $path = dirname($path);
644             }
645             }
646              
647 20     20   11082 method _determine_parent_compc ($path, $flags) {
  244     244   363  
  244         428  
  244         264  
648 244         309 my $parent_compc;
649 244 100       759 if ( exists( $flags->{extends} ) ) {
650 13         26 my $extends = $flags->{extends};
651 13 100       22 if ( defined($extends) ) {
652 11 100       91 $extends = mason_canon_path( join( "/", dirname($path), $extends ) )
653             if substr( $extends, 0, 1 ) ne '/';
654 11 100       223 $parent_compc = $self->load($extends)
655             or die "could not load '$extends' for extends flag";
656             }
657             else {
658 2         65 $parent_compc = $self->component_class;
659             }
660             }
661 235         8164 return $parent_compc;
662             }
663              
664 20     20   8566 method _extract_flags_from_object_file ($object_file) {
  244     244   317  
  244         398  
  244         401  
665 244         539 my $flags = {};
666 244 50       8263 open( my $fh, "<", $object_file ) or die "could not open '$object_file': $!";
667 244         3470 my $line = <$fh>;
668 244 100       1286 if ( my ($flags_str) = ( $line =~ /\# FLAGS: (.*)/ ) ) {
669 13         44 $flags = json_decode($flags_str);
670             }
671 244         2284 return $flags;
672             }
673              
674 20     20   8381 method _flush_load_cache () {
  378     378   790  
  378         566  
675 378         1433 Memoize::flush_cache('comp_exists');
676 378         23025 Memoize::flush_cache('load');
677             }
678              
679 20     20   6559 method _make_request () {
  185     185   293  
  185         254  
680 185         7142 return $self->request_class->new( interp => $self, %{ $self->request_params }, @_ );
  185         5281  
681             }
682              
683 20     20   6576 method _object_file_for_path ($path) {
  270     270   463  
  270         413  
  270         335  
684 270         869 return catfile( $self->object_dir, ( split /\//, $path ) ) . $self->object_file_extension;
685             }
686              
687 20     20   7286 method _source_file_for_path ($path) {
  1282     1282   1597  
  1282         1481  
  1282         1219  
688 1282         2326 $self->_assert_absolute_path($path);
689 1281         1585 foreach my $root_path ( @{ $self->comp_root } ) {
  1281         32859  
690 1281         2521 my $source_file = $root_path . $path;
691 1281 100       27235 return $source_file if -f $source_file;
692             }
693 939         4163 return undef;
694             }
695              
696 20     20   7467 method _top_level_not_found ($path, $tried_paths) {
  17     17   41  
  17         42  
  17         22  
697 17         83 my @combined_paths = combine_similar_paths(@$tried_paths);
698 116         271 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         505 join( ", ", map { "'$_'" } @combined_paths ),
703 0         0 @{ $self->comp_root } > 1
704 17 50       102 ? "component roots " . join( ", ", map { "'$_'" } @{ $self->comp_root } )
  0         0  
705             : "component root '" . $self->comp_root->[0] . "'"
706             )
707             );
708             }
709              
710 20     20   9095 method _validate_allow_globals () {
  3     3   5  
  3         5  
711              
712             # Will build allowed_globals_hash and also validate the param
713             #
714 3         92 $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   220 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         135 while ( my ( $method_name, $name ) = each(%class_overrides) ) {
740 160         7106 my $base_method_name = "base_$method_name";
741 160         724 has $method_name => ( init_arg => undef, lazy_build => 1 );
742 160         30393 has $base_method_name => ( isa => 'Str', lazy_build => 1 );
743             __PACKAGE__->meta->add_method(
744             "_build_$method_name" => sub {
745 625     625   1238 my $self = shift;
        625      
        625      
        625      
        625      
        625      
        625      
        625      
        625      
746 625         18314 my $base_class = $self->$base_method_name;
747 625         1904 Class::Load::load_class($base_class);
748 625         31045 return Mason::PluginManager->apply_plugins_to_class( $base_class, $name,
749             $self->plugins );
750             }
751 160         31055 );
752             __PACKAGE__->meta->add_method(
753             "_build_$base_method_name" => sub {
754 624     624   1059 my $self = shift;
        624      
        624      
        624      
        624      
        624      
        624      
        624      
        624      
755 632         2662 my @candidates =
756 624         16684 map { join( '::', $_, $name ) } ( uniq( $self->mason_root_class, 'Mason' ) );
757 624 50       1092 my ($base_class) = grep { can_load($_) } @candidates
  632         1913  
758             or die
759             sprintf( "cannot load %s for %s", join( ', ', @candidates ), $base_method_name );
760 624         20111 return $base_class;
761             }
762 160         9368 );
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