File Coverage

blib/lib/WWW/Scraper/ISBN/Driver.pm
Criterion Covered Total %
statement 73 73 100.0
branch 30 30 100.0
condition 16 19 84.2
subroutine 14 14 100.0
pod 10 10 100.0
total 143 146 97.9


line stmt bran cond sub pod time code
1             package WWW::Scraper::ISBN::Driver;
2              
3 8     8   134950 use strict;
  8         33  
  8         225  
4 8     8   41 use warnings;
  8         25  
  8         372  
5              
6             our $VERSION = '1.05';
7              
8             #----------------------------------------------------------------------------
9             # Library Modules
10              
11 8     8   52 use Carp;
  8         17  
  8         7153  
12              
13             #----------------------------------------------------------------------------
14             # Public API
15              
16             # Preloaded methods go here.
17             sub new {
18 11     11 1 790 my $proto = shift;
19 11   66     60 my $class = ref($proto) || $proto;
20              
21 11         45 my $self = {
22             FOUND => 0,
23             VERBOSITY => 0,
24             BOOK => undef,
25             ERROR => ''
26             };
27            
28 11         23 bless ($self, $class);
29 11         25 return $self;
30             }
31              
32 15     15 1 990 sub found { my $self = shift; return $self->_accessor('FOUND',@_) }
  15         34  
33 6     6 1 551 sub verbosity { my $self = shift; return $self->_accessor('VERBOSITY',@_) }
  6         16  
34 6     6 1 566 sub book { my $self = shift; return $self->_accessor('BOOK',@_) }
  6         19  
35 8     8 1 568 sub error { my $self = shift; return $self->_accessor('ERROR',@_) }
  8         19  
36              
37             sub _accessor {
38 35     35   51 my $self = shift;
39 35         47 my $accessor = shift;
40 35 100       79 if (@_) { $self->{$accessor} = shift };
  14         26  
41 35         167 return $self->{$accessor};
42             }
43              
44             sub search {
45 2     2 1 742 croak(q{Child class must overload 'search()' method.});
46             }
47              
48             #----------------------------------------------------------------------------
49             # Internal Class methods
50              
51             # a generic method for storing the error & setting not found
52             sub handler {
53 4     4 1 589 my $self = shift;
54 4 100       14 if (@_) {
55 3         9 $self->{ERROR} = shift;
56 3 100       9 print "Error: $self->{ERROR}\n" if $self->verbosity;
57             };
58 4         21 return $self->found(0);
59             }
60              
61             sub convert_to_ean13 {
62 23     23 1 5926 my $self = shift;
63 23   50     60 my $isbn = shift || return;
64 23         35 my $prefix;
65              
66 23 100 100     97 return unless(length $isbn == 10 || length $isbn == 13);
67              
68 22 100       52 if(length $isbn == 13) {
69 14 100       93 return if($isbn !~ /^(978|979)(\d{10})$/);
70 12         47 ($prefix,$isbn) = ($1,$2);
71             } else {
72 8 100       62 return if($isbn !~ /^(\d{10}|\d{9}X)$/);
73 7         17 $prefix = '978';
74             }
75              
76 19         43 my $isbn13 = $prefix . $isbn;
77 19         37 chop($isbn13);
78 19         78 my @isbn = split(//,$isbn13);
79 19         39 my ($lsum,$hsum) = (0,0);
80 19         46 while(@isbn) {
81 114         172 $hsum += shift @isbn;
82 114         228 $lsum += shift @isbn;
83             }
84              
85 19         37 my $csum = ($lsum * 3) + $hsum;
86 19         36 $csum %= 10;
87 19 100       47 $csum = 10 - $csum if($csum != 0);
88              
89 19         80 return $isbn13 . $csum;
90             }
91              
92             sub convert_to_isbn10 {
93 16     16 1 30 my $self = shift;
94 16   50     53 my $ean = shift || return;
95              
96 16 100 100     78 return unless(length $ean == 10 || length $ean == 13);
97 15 100       110 return if($ean !~ /^(?:978|979)?(\d{9})[\dX]$/);
98 13         45 my ($isbn,$isbn10) = ($1,$1);
99              
100 13         33 my ($csum, $pos, $digit) = (0, 0, 0);
101 13         34 for ($pos = 9; $pos > 0; $pos--) {
102 117         175 $digit = $isbn % 10;
103 117         159 $isbn /= 10; # Decimal shift ISBN for next time
104 117         203 $csum += ($pos * $digit);
105             }
106 13         33 $csum %= 11;
107 13 100       30 $csum = 'X' if ($csum == 10);
108 13         147 return $isbn10 . $csum;
109             }
110              
111             sub is_valid {
112 11     11 1 23 my $self = shift;
113 11 100       34 my $isbn = shift or return 0;
114              
115             # validate and convert into EAN13 format
116 10         23 my $ean = $self->convert_to_ean13($isbn);
117              
118 10 100       36 return 0 if(!$ean);
119 9 100 100     48 return 0 if(length $isbn == 13 && $isbn ne $ean);
120 8 100 100     30 return 0 if(length $isbn == 10 && $isbn ne $self->convert_to_isbn10($ean));
121              
122 6         35 return 1;
123             }
124              
125             1;
126              
127             __END__