File Coverage

blib/lib/File/VirusScan.pm
Criterion Covered Total %
statement 50 58 86.2
branch 9 12 75.0
condition 3 6 50.0
subroutine 10 11 90.9
pod 3 3 100.0
total 75 90 83.3


line stmt bran cond sub pod time code
1             package File::VirusScan;
2 2     2   54192 use strict;
  2         3  
  2         67  
3 2     2   9 use warnings;
  2         2  
  2         51  
4 2     2   8 use Carp;
  2         14  
  2         117  
5 2     2   35 use 5.008;
  2         173  
  2         75  
6              
7 2     2   843 use File::VirusScan::Result;
  2         4  
  2         49  
8 2     2   957 use File::VirusScan::ResultSet;
  2         6  
  2         980  
9              
10             our $VERSION = '0.103';
11              
12             # We don't use Module::Pluggable. Most users of this module will have
13             # one or two virus scanners, with the other half-dozen or so plugins
14             # going unused, so there's no sense in finding/loading all plugins.
15             sub new
16             {
17 3     3 1 1991 my ($class, $conf) = @_;
18              
19 3 100 66     11 if(!exists $conf->{engines} || !scalar keys %{ $conf->{engines} }) {
  2         5  
20 1         16 croak q{Must supply an 'engines' value to constructor};
21             }
22              
23 2         3 my %backends;
24              
25             # Load and initialise our backend engines
26 2         3 while (my ($moniker, $backend_conf) = each %{ $conf->{engines} }) {
  3         12  
27              
28 2         4 $moniker =~ s/[^-A-Za-z0-9_:]//;
29 2         1 my $backclass = $moniker;
30              
31 2 100       7 substr($backclass, 0, 1, 'File::VirusScan::Engine::') if substr($backclass, 0, 1) eq '-';
32              
33 2     1   97 eval qq{use $backclass;}; ## no critic(StringyEval)
  1     1   182  
  0         0  
  0         0  
  1         4  
  1         0  
  1         12  
34 2 100       35 if($@) { ## no critic(PunctuationVars)
35 1         14 croak "Unable to find class $backclass for backend '$moniker'";
36             }
37              
38 1         4 $backends{$moniker} = $backclass->new($backend_conf);
39             }
40              
41 1         2 my $self = { always_scan => $conf->{always_scan}, };
42              
43 1 50       3 if(exists $conf->{order}) {
44 0         0 $self->{_backends} = [ @backends{ @{ $conf->{order} } } ];
  0         0  
45             } else {
46 1         2 $self->{_backends} = [ values %backends ];
47             }
48              
49 1         5 return bless $self, $class;
50             }
51              
52             sub scan
53             {
54 2     2 1 671 my ($self, $path) = @_;
55              
56 2         14 my $result = File::VirusScan::ResultSet->new();
57              
58 2         7 for my $back (@{ $self->{_backends} }) {
  2         7  
59              
60 2         2 my $scan_result = eval { $back->scan($path) };
  2         4  
61              
62 2 50       4 if($@) {
63 0         0 $result->add(File::VirusScan::Result->error("Error calling ->scan(): $@"));
64             } else {
65 2         5 $result->add($scan_result);
66             }
67              
68 2 50 33     16 if(!$self->{always_scan}
69             && $result->has_virus())
70             {
71 0         0 last;
72             }
73             }
74              
75 2         13 return $result;
76             }
77              
78             sub get_backends
79             {
80 0     0 1 0 my ($self) = @_;
81 0         0 return $self->{_backends};
82             }
83              
84             1;
85             __END__