File Coverage

blib/lib/WWW/Mechanize/Script.pm
Criterion Covered Total %
statement 28 30 93.3
branch n/a
condition n/a
subroutine 10 10 100.0
pod n/a
total 38 40 95.0


line stmt bran cond sub pod time code
1             package WWW::Mechanize::Script;
2              
3 1     1   47350 use strict;
  1         4  
  1         43  
4 1     1   5 use warnings;
  1         3  
  1         36  
5              
6 1     1   6 use File::Basename qw(fileparse);
  1         183  
  1         114  
7 1     1   7 use File::Path qw(make_path);
  1         2  
  1         71  
8 1     1   1287 use Hash::Merge ();
  1         3612  
  1         34  
9 1     1   1399 use IO::File;
  1         13863  
  1         171  
10 1     1   1180 use Module::Pluggable::Object ();
  1         10658  
  1         37  
11 1     1   1176 use Params::Util qw(_HASH);
  1         6749  
  1         95  
12 1     1   4711 use Template ();
  1         35542  
  1         34  
13 1     1   860 use WWW::Mechanize ();
  0            
  0            
14             use WWW::Mechanize::Timed ();
15              
16             # ABSTRACT: fetch websites and executes tests on the results
17              
18              
19             our $VERSION = '0.100';
20              
21              
22             sub new
23             {
24             my ( $class, $cfg ) = @_;
25              
26             my $self = bless( { cfg => { %{$cfg} } }, $class );
27              
28             return $self;
29             }
30              
31              
32             sub _gen_code_compute
33             {
34             my $check_cfg = $_[0];
35             my $compute_code;
36              
37             if ( defined( $check_cfg->{code_func} ) )
38             {
39             my $compute_str = "sub { " . $check_cfg->{code_func} . " };";
40             $compute_code = eval $compute_str;
41             $@ and die $@;
42             }
43              
44             if ( !defined($compute_code) and defined( $check_cfg->{code_cmp} ) )
45             {
46             my $compute_str =
47             "sub { my (\$cur,\$new) = \@_; \$cur "
48             . $check_cfg->{code_cmp}
49             . " \$new ? \$cur : \$new; };";
50             $compute_code = eval $compute_str;
51             $@ and die $@;
52             }
53              
54             if ( !defined($compute_code) )
55             {
56             my $compute_str = "sub { my (\$cur,\$new) = \@_; \$cur > \$new ? \$cur : \$new; };";
57             $compute_code = eval $compute_str;
58             $@ and die $@;
59             }
60              
61             return $compute_code;
62             }
63              
64              
65             sub test_plugins
66             {
67             my ( $self, $test ) = @_;
68              
69             unless ( defined( $self->{all_plugins} ) )
70             {
71             my $plugin_base = join( "::", __PACKAGE__, "Plugin" );
72             my $finder =
73             Module::Pluggable::Object->new(
74             require => 1,
75             search_path => [$plugin_base],
76             except => [$plugin_base],
77             inner => 0,
78             only => qr/^${plugin_base}::\p{Word}+$/,
79             );
80              
81             # filter out things that don't look like our plugins
82             my @ap =
83             map { $_->new( $self->{cfg}->{defaults} ) }
84             grep { $_->isa($plugin_base) } $finder->plugins();
85             $self->{all_plugins} = \@ap;
86             }
87              
88             my @tp = grep { $_->can_check($test) } @{ $self->{all_plugins} };
89             return @tp;
90             }
91              
92              
93             sub get_request_value
94             {
95             my ( $self, $request, $value_name ) = @_;
96              
97             $value_name or return;
98              
99             return $request->{$value_name} // $self->{cfg}->{default}->{request}->{$value_name};
100             }
101              
102             sub _get_target
103             {
104             my $def = shift;
105              
106             my $target = $def->{target};
107             $target //= "-";
108              
109             if ( $target ne "-" and $def->{append} )
110             {
111             my ( $name, $path, $suffix ) = fileparse($target);
112             -d $path or make_path($path);
113             my $fh = IO::File->new( $target, ">>" );
114             $fh->seek( 0, SEEK_END );
115             $target = $fh;
116             }
117              
118             return $target;
119             }
120              
121              
122             sub summarize
123             {
124             my ( $self, $code, @msgs ) = @_;
125              
126             my %vars = (
127             %{ _HASH( $self->{cfg}->{templating}->{vars} ) // {} },
128             %{ _HASH( $self->{cfg}->{report}->{vars} ) // {} },
129             CODE => $code,
130             MESSAGES => [@msgs]
131             );
132              
133             my $input = $self->{cfg}->{summary}->{source} // \$self->{cfg}->{summary}->{template};
134             my $output = _get_target( $self->{cfg}->{summary} );
135             my $template = Template->new();
136             $template->process( $input, \%vars, $output )
137             or die $template->error();
138              
139             return;
140             }
141              
142              
143             sub gen_report
144             {
145             my ( $self, $full_test, $mech, $code, @msgs ) = @_;
146             my $response = $mech->response();
147             my %vars = (
148             %{ _HASH( $self->{cfg}->{templating}->{vars} ) // {} },
149             %{ _HASH( $self->{cfg}->{report}->{vars} ) // {} },
150             CODE => $code,
151             MESSAGES => [@msgs],
152             RESPONSE => {
153             CODE => $response->code(),
154             CONTENT => $response->content(),
155             BASE => $response->base(),
156             HEADER => {
157             map { $_ => $response->headers()->header($_) }
158             $response->headers()->header_field_names()
159             },
160             }
161             );
162              
163             my $input = $self->{cfg}->{report}->{source} // \$self->{cfg}->{report}->{template};
164             my $output = _get_target( $self->{cfg}->{report} );
165             my $template = Template->new();
166             $template->process( $input, \%vars, $output )
167             or die $template->error();
168              
169             return;
170             }
171              
172              
173             sub run_script
174             {
175             my ( $self, @script ) = @_;
176             my $code = 0; # XXX
177             my @msgs;
178             my $compute_code = _gen_code_compute( $self->{cfg}->{defaults}->{check} );
179              
180             foreach my $test (@script)
181             {
182             my ( $test_code, @test_msgs ) = $self->run_test($test);
183             $code = &{$compute_code}( $code, $test_code );
184             push( @msgs, @test_msgs );
185             }
186              
187             if ( $self->{cfg}->{summary} )
188             {
189             my $summary = $self->summarize( $code, @msgs );
190             }
191              
192             return ( $code, @msgs );
193             }
194              
195              
196             sub run_test
197             {
198             my ( $self, $test ) = @_;
199              
200             my $merger = Hash::Merge->new('LEFT_PRECEDENT');
201             my $full_test = $merger->merge( $test, $self->{cfg}->{defaults} );
202              
203             my $mech = WWW::Mechanize::Timed->new();
204             foreach my $akey ( keys %{ $full_test->{request}->{agent} } )
205             {
206             # XXX clone and delete array args before
207             $mech->$akey( $full_test->{request}->{agent}->{$akey} );
208             }
209              
210             my $method = $full_test->{request}->{method};
211             defined( $test->{request}->{http_headers} )
212             ? $mech->$method( $full_test->{request}->{uri}, %{ $full_test->{request}->{http_headers} } )
213             : $mech->$method( $full_test->{request}->{uri} );
214              
215             $full_test->{compute_code} = _gen_code_compute( $full_test->{check} );
216              
217             my $code = 0;
218             my @msgs;
219             foreach my $tp ( $self->test_plugins($full_test) )
220             {
221             my ( $plug_code, @plug_msgs ) = $tp->check_response( $full_test, $mech );
222             $code = &{ $full_test->{compute_code} }( $code, $plug_code );
223             push( @msgs, @plug_msgs );
224             }
225              
226             if ( $self->{cfg}->{report} )
227             {
228             $self->gen_report( $full_test, $mech, $code, @msgs );
229             }
230              
231             return ( $code, @msgs );
232             }
233              
234             1;
235              
236             __END__