File Coverage

lib/Cache/Static/HTML_Mason_Util/hmc.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             ##
2             #
3             # Copyright 2005-2006, Brian Szymanski
4             #
5             # This file is part of Cache::Static
6             #
7             # Cache::Static is free software; you can redistribute it and/or modify
8             # it under the terms of the GNU General Public License as published by
9             # the Free Software Foundation; either version 2 of the License, or
10             # any later version.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15             # GNU General Public License for more details.
16             #
17             # For more information about Cache::Static, point a web browser at
18             # http://chronicle.allafrica.com/scache/ or read the
19             # documentation included with the Cache::Static distribution in the
20             # doc/ directory
21             #
22             ##
23              
24             package Cache::Static::HTML_Mason_Util::hmc;
25              
26 1     1   7 use strict;
  1         3  
  1         46  
27 1     1   7 use warnings;
  1         2  
  1         41  
28              
29 1     1   6 use vars qw ( @ISA );
  1         2  
  1         96  
30              
31 1     1   522 use HTML::Mason;
  0            
  0            
32             use HTML::Mason::Compiler;
33             use HTML::Mason::Compiler::ToObject;
34             use Cache::Static;
35              
36             @ISA = qw(HTML::Mason::Compiler::ToObject);
37              
38             my %last_component_deps;
39             my ($r, $m, $wr);
40             my $parent_dir = undef;
41              
42             sub find_extra_deps {
43             my ($self, $subcomponent, %args) = @_;
44              
45             my $top_call = defined($args{top_call}) ? $args{top_call} : 1;
46             $m = $args{m};
47             $r = $args{r};
48             $wr = $r->document_root;
49              
50             Cache::Static::_log(3, "called find_extra_deps: $subcomponent (top: $top_call)\n");
51              
52             my @ret = ();
53             #cache Mason compiles we know if none of our depends changed we don't
54             #need to do any compilation (however, if any of them changed, we may
55             #still need to do compilation - currently we just recompile ALL -
56             #this will be improved later)
57             my $str_ret = undef;
58             my $sc_key = ($top_call ? Cache::Static::make_key($subcomponent) : undef);
59             if($top_call) {
60             my $hmc_deps = Cache::Static::get_if_same($sc_key, [],
61             namespace => "_Cache_Static_hmc");
62             if(defined($hmc_deps)) {
63             my @hmc_deps = @{Storable::thaw $hmc_deps};
64             ($str_ret, undef) = Cache::Static::_is_same($sc_key,
65             \@hmc_deps, namespace => "_Cache_Static_hmc");
66             @ret = @hmc_deps;
67             }
68             }
69             if(defined($str_ret)) {
70             Cache::Static::_log(3, "got cached depend list for $subcomponent");
71             } else {
72             open(F, $subcomponent) || die "can't open $subcomponent";
73             my $code = join("\n", ) || die "can't read $subcomponent";
74             close(F) || die "can't close $subcomponent";
75             my $cr = $self->compile(
76             top_call => $top_call,
77             comp_source => $code,
78             name => "something or other (fill me in!)",
79             cache_static_friendly_key => "$subcomponent" );
80             die "couldn't compile $subcomponent: $cr" unless(defined($cr));
81              
82             if($top_call) {
83             my %processed_deps = ();
84             while((scalar keys %processed_deps) !=
85             (scalar keys %last_component_deps)) {
86             my @deps = keys %last_component_deps;
87             Cache::Static::_log(4, "deps: @deps");
88             Cache::Static::_log(4, "proc'd deps: ".
89             join(" ", keys %processed_deps));
90             foreach my $dep (@deps) {
91             next if $processed_deps{$dep};
92             unless($dep =~ /^file\|/) {
93             $processed_deps{$dep} = 1;
94             next;
95             }
96             Cache::Static::_log(4, "got new mason file dep: $dep");
97             $processed_deps{$dep} = 1;
98             $dep = _pathify($dep, 0);
99             Cache::Static::_log(3, "recursing on dep: $dep\n");
100             #note this has a side effect of modifying %last_component_deps
101             $self->find_extra_deps($dep, %args, top_call => 0);
102             }
103             }
104             }
105             @ret = map { _pathify($_, 1) } keys %last_component_deps;
106             Cache::Static::_log(4, "ret: @ret");
107             #we are caching the dependencies of this mason file
108             #e.g. @ret has a list of file dependencies
109             if($top_call) {
110             Cache::Static::set($sc_key, Storable::freeze(\@ret),
111             [], namespace => "_Cache_Static_hmc");
112             }
113             }
114              
115             return \@ret;
116             }
117              
118             sub _pathify {
119             my $file = shift;
120             my $leave_spec = shift || 0;
121             if($leave_spec) {
122             $file =~ s/^file\|/file\|$wr\//;
123             } else {
124             $file =~ s/^file\|/$wr\//;
125             }
126             #strip out ../, ./
127             $file =~ s/\/[^\/]+\/\.\.\//\//g;
128             $file =~ s/\.\///g;
129             #strip redundant slashes
130             $file =~ s/\/\/+/\//g;
131             return $file;
132             }
133              
134             sub _Cache_Static_component_call {
135             my $self = shift;
136             my $has_content = shift;
137              
138             #args should be 'call' => $component
139             my $k = shift;
140             die "Cache::Static - incompatible version of HTML::Mason" unless($k eq 'call');
141             my $component = shift;
142              
143             my $curr_dir = $parent_dir || $m->current_comp->dir_path;
144             Cache::Static::_log(4, "component: $component, curr_dir: $curr_dir",
145             ", parent_dir: $parent_dir, dir_path: ", $m->current_comp->dir_path);
146              
147             #don't worry about components with embedded content for now (<|& foo &>...)
148             unless($has_content) {
149             $component =~ s/^\s+//;
150             # (from HTML::Mason::Devel) - To eliminate the need for quotes in
151             # most cases, Mason employs some magic parsing: If the first character is
152             # one of "[\w/_.]", comp_path is assumed to be a literal string running
153             # up to the first comma or &>. Otherwise, comp_path is evaluated as an
154             # expression.
155             if($component =~ /^['"]?[\w\/_.]/) {
156             #support for "component" & 'component'
157             if($component =~ /^[']/) {
158             $component =~ s/^[']//;
159             $component =~ s/['].*//;
160             } elsif($component =~ /^["]/) {
161             $component =~ s/^["]//;
162             $component =~ s/["].*//;
163             }
164             #strip off everything after a comma
165             $component =~ s/,.*$//s;
166             #strip off any trailing whitespace
167             $component =~ s/\s+$//s;
168             #now we've got the component, add a file dep
169             if($component) {
170             my $component_path =
171             ($component =~ /^\//) ?
172             $component :
173             $curr_dir.'/'.$component;
174             $component_path =~ s/\/\/+/\//g;
175             Cache::Static::_log(4, "HTML_Mason_Util::hmc added component dep: file|$component_path");
176             $last_component_deps{"file|$component_path"} = 1;
177             }
178             } else {
179             Cache::Static::_log(3, "HTML_Mason_Util::hmc added MISS dep for dynamic component: $component");
180             $last_component_deps{MISS} = 1;
181             }
182             } else {
183             Cache::Static::_log(3, "HTML_Mason_Util::hmc added MISS dep for component $component with content");
184             $last_component_deps{MISS} = 1;
185             }
186              
187             if($has_content) {
188             return $self->SUPER::component_content_call(@_);
189             } else {
190             return $self->SUPER::component_call(@_);
191             }
192             }
193              
194             sub compile {
195             my ($self, %args) = @_;
196             my $fkey = $args{cache_static_friendly_key};
197             delete $args{cache_static_friendly_key};
198             $parent_dir = $fkey;
199             $parent_dir =~ s/\/[^\/]*$//; #just the dir
200             $parent_dir =~ s/^$wr//; #strip off webroot
201             Cache::Static::_log(4, "compiling: $fkey in $parent_dir");
202             my $ret = 0;
203             unless($ret) {
204             %last_component_deps = () if($args{top_call});
205             delete $args{top_call};
206             $ret = $self->SUPER::compile(%args);
207             }
208             return $ret;
209             }
210              
211             sub component_content_call {
212             my $self = shift;
213             return _Cache_Static_component_call($self, 1, @_);
214             }
215              
216             sub component_call {
217             my $self = shift;
218             return _Cache_Static_component_call($self, 0, @_);
219             }
220             1;
221