File Coverage

blib/lib/Business/ISBN.pm
Criterion Covered Total %
statement 166 191 86.9
branch 38 56 67.8
condition 11 21 52.3
subroutine 59 69 85.5
pod 30 30 100.0
total 304 367 82.8


line stmt bran cond sub pod time code
1 8     8   231614 use 5.008;
  8         50  
2              
3             package Business::ISBN;
4 8     8   45 use strict;
  8         16  
  8         365  
5              
6             =encoding utf8
7              
8             =head1 NAME
9              
10             Business::ISBN - work with International Standard Book Numbers
11              
12             =head1 SYNOPSIS
13              
14             use Business::ISBN;
15              
16             # 10 digit ISBNs
17             $isbn10 = Business::ISBN->new('1565922573');
18             $isbn10 = Business::ISBN->new('1-56592-257-3');
19              
20             # 13 digit ISBNs
21             $isbn13 = Business::ISBN->new('978-0-596-52724-2');
22              
23             # convert
24             $isbn10 = $isbn13->as_isbn10; # for the 978 prefixes
25              
26             $isbn13 = $isbn10->as_isbn13;
27              
28             # maybe you don't care what it is as long as everything works
29             $isbn = Business::ISBN->new( $ARGV[0] );
30              
31             #print the ISBN with hyphens at usual positions
32             print $isbn->as_string;
33              
34             #print the ISBN with hyphens at specified positions.
35             #this not does affect the default positions
36             print $isbn->as_string([]);
37              
38             #print the group code or publisher code
39             print $isbn->group_code;
40              
41             print $isbn->publisher_code;
42              
43             #check to see if the ISBN is valid
44             $isbn->is_valid;
45              
46             #fix the ISBN checksum. BEWARE: the error might not be
47             #in the checksum!
48             $isbn->fix_checksum;
49              
50             # create an EAN13 barcode in PNG format
51             $isbn->png_barcode;
52              
53             =head1 DESCRIPTION
54              
55             This modules handles International Standard Book Numbers, including
56             ISBN-10 and ISBN-13.
57              
58             The data come from L, which means you can update
59             the data separately from the code. Also, you can use L
60             with whatever F you like if you have updated data. See
61             that module for details.
62              
63             =cut
64              
65             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
66             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
67             # # Boring set up stuff
68 8         74 use subs qw(
69             _common_format
70             INVALID_GROUP_CODE
71             INVALID_PUBLISHER_CODE
72             BAD_CHECKSUM
73             GOOD_ISBN
74             BAD_ISBN
75             ARTICLE_CODE_OUT_OF_RANGE
76 8     8   4333 );
  8         193  
77 8         604 use vars qw(
78             @EXPORT_OK
79             %EXPORT_TAGS
80             %group_data
81             $MAX_GROUP_CODE_LENGTH
82 8     8   711 );
  8         14  
83              
84 8     8   51 use Carp qw(carp croak cluck);
  8         14  
  8         458  
85 8     8   46 use Exporter qw(import);
  8         14  
  8         316  
86              
87 8     8   4453 use Business::ISBN::Data 20191107; # now a separate module
  8         295900  
  8         2098  
88             # ugh, hack
89             *group_data = *Business::ISBN::country_data;
90             sub _group_data {
91 215568 100   215568   403231 my $isbn_prefix
92             = ref $_[0] eq 'Business::ISBN13'
93             ? $_[0]->prefix
94             : "978";
95 215568         1072126 return $group_data{ $isbn_prefix }->{ $_[1] };
96             }
97              
98 2216     2216   5450 sub _max_group_code_length { $Business::ISBN::MAX_COUNTRY_CODE_LENGTH };
99             sub _max_publisher_code_length {
100 106673     106673   209952 $_[0]->_max_length
101              
102             - $_[0]->_prefix_length # prefix
103              
104             - $_[0]->_group_code_length # group
105             - 1 # article
106             - 1; # checksum
107             };
108              
109             sub _publisher_ranges {
110 106673     106673   131311 my $self = shift;
111 106673         136712 [ @{ $self->_group_data( $self->group_code )->[1] } ];
  106673         174088  
112             }
113              
114             my $debug = $ENV{BUSINESS_ISBN_DEBUG};
115              
116             BEGIN {
117 8     8   47 @EXPORT_OK = qw(
118             INVALID_GROUP_CODE INVALID_PUBLISHER_CODE
119             BAD_CHECKSUM GOOD_ISBN BAD_ISBN ARTICLE_CODE_OUT_OF_RANGE
120             INVALID_PREFIX
121             %ERROR_TEXT
122             valid_isbn_checksum
123             );
124              
125 8         1077 %EXPORT_TAGS = (
126             'all' => \@EXPORT_OK,
127             );
128             };
129              
130             our $VERSION = '3.007';
131              
132             sub ARTICLE_CODE_OUT_OF_RANGE () { -5 }
133             sub INVALID_PREFIX () { -4 };
134             sub INVALID_GROUP_CODE () { -2 };
135             sub INVALID_PUBLISHER_CODE () { -3 };
136             sub BAD_CHECKSUM () { -1 };
137             sub GOOD_ISBN () { 1 };
138             sub BAD_ISBN () { 0 };
139              
140             our %ERROR_TEXT = (
141             0 => "Bad ISBN",
142             1 => "Good ISBN",
143             -1 => "Bad ISBN checksum",
144             -2 => "Invalid group code",
145             -3 => "Invalid publisher code",
146             -4 => "Invalid prefix (must be 978 or 979)",
147             -5 => "Incremented article code would be out of range",
148             );
149              
150 8     8   3949 use Business::ISBN10;
  8         20  
  8         382  
151 8     8   2924 use Business::ISBN13;
  8         20  
  8         7150  
152              
153             =head2 Function interface
154              
155             =over 4
156              
157             =item valid_isbn_checksum( ISBN10 | ISBN13 )
158              
159             This function is exportable on demand, and works for either 10
160             or 13 character ISBNs).
161              
162             use Business::ISBN qw( valid_isbn_checksum );
163              
164             Returns 1 if the ISBN is a valid ISBN with the right checksum.
165              
166             Returns 0 if the ISBN has valid prefix and publisher codes, but an
167             invalid checksum.
168              
169             Returns undef if the ISBN does not validate for any other reason.
170              
171             =back
172              
173             =cut
174              
175             sub valid_isbn_checksum {
176 4     4 1 1856 my $isbn = shift;
177              
178 4         11 my $obj = Business::ISBN->new( $isbn );
179 4 50       9 return unless defined $obj;
180              
181 4 100       5 return 1 if $obj->is_valid_checksum == GOOD_ISBN;
182 2 50       5 return 0 if $obj->is_valid_checksum == BAD_CHECKSUM;
183 0         0 return;
184             }
185              
186             =head2 Object interface
187              
188             =over 4
189              
190             =item new($isbn)
191              
192             The constructor accepts a scalar representing the ISBN.
193              
194             The string representing the ISBN may contain characters other than
195             C<[0-9xX]>, although these will be removed in the internal
196             representation. The resulting string must look like an ISBN - the
197             first nine characters must be digits and the tenth character must be a
198             digit, 'x', or 'X'.
199              
200             The constructor attempts to determine the group code and the publisher
201             code. If these data cannot be determined, the constructor sets C<<
202             $obj->error >> to something other than C. An object is
203             still returned and it is up to the program to check the C<< error >> method
204             for one of five values or one of the C<< error_* >> methods to check for
205             a particular error. The actual
206             values of these symbolic versions are the same as those from previous
207             versions of this module which used literal values:
208              
209              
210             Business::ISBN::INVALID_PUBLISHER_CODE
211             Business::ISBN::INVALID_GROUP_CODE
212             Business::ISBN::BAD_CHECKSUM
213             Business::ISBN::GOOD_ISBN
214             Business::ISBN::BAD_ISBN
215              
216             If you have one of these values and want to turn it into a string, you
217             can use the C<%Business::ISBN::ERROR_TEXT> hash, which is exportable
218             by asking for it explicitly in the import list:
219              
220             use Business::ISBN qw(%ERROR_TEXT);
221              
222             As of version 2.010_01, you can get this text from C<< error_text >>
223             so you don't have to import anything.
224              
225             The string passed as the ISBN need not be a valid ISBN as long as it
226             superficially looks like one. This allows one to use the
227             C method. Despite the disclaimer in the discussion of
228             that method, the author has found it extremely useful. One should
229             check the validity of the ISBN with C rather than relying
230             on the return value of the constructor. If all one wants to do is
231             check the validity of an ISBN, one can skip the object-oriented
232             interface and use the C function which is
233             exportable on demand.
234              
235             If the constructor decides it cannot create an object, it returns
236             C. It may do this if the string passed as the ISBN cannot be
237             munged to the internal format meaning that it does not even come close
238             to looking like an ISBN.
239              
240             =cut
241              
242             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
243             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
244             sub new {
245 106688     106688 1 1022469 my $class = shift;
246 106688         138517 my $input_data = shift;
247 106688         179374 my $common_data = _common_format $input_data;
248              
249 106688 100       214281 return unless $common_data;
250              
251 106678         239479 my $self = {
252             input_isbn => $input_data,
253             common_data => $common_data
254             };
255              
256 106678         150827 my $isbn = do {
257 106678 100       184236 if( length( $common_data ) == 10 ) {
    50          
258 106643         179304 bless $self, 'Business::ISBN10';
259             }
260             elsif( length( $common_data ) == 13 ) {
261 35         76 bless $self, 'Business::ISBN13';
262             }
263             else {
264 0         0 return BAD_ISBN;
265             }
266             };
267              
268 106678         222901 $self->_init( $common_data );
269 106678         230226 $self->_parse_isbn( $common_data );
270              
271 106678         196583 return $isbn;
272             }
273              
274             =back
275              
276             =head2 Instance methods
277              
278             =over 4
279              
280             =item input_isbn
281              
282             Returns the starting ISBN. Since you may insert hyphens or fix
283             checksums, you might want to see the original data.
284              
285             =cut
286              
287 2     2 1 7 sub input_isbn { $_[0]->{'input_isbn'} }
288              
289             =item common_data
290              
291             Returns the starting ISBN after normalization, which removes anything
292             that isn't a digit or a valid checksum character.
293              
294             =cut
295              
296 1     1 1 5 sub common_data { $_[0]->{'common_data'} }
297              
298              
299             =item isbn
300              
301             Returns the current value of ISBN, even if it has an invalid checksum.
302             This is the raw data so it doesn't have the hyphens. If you want
303             hyphenation, try C.
304              
305             The C method should be the same as C.
306              
307             =cut
308              
309 642392     642392 1 1195399 sub isbn { $_[0]->{'isbn'} }
310              
311             =item error
312              
313             Return the error code for the reason the ISBN isn't valid. The return
314             value is a key in %ERROR_TEXT.
315              
316             =cut
317              
318 13 100   13 1 2082 sub error { $_[0]->{'valid'} < 1 and $_[0]->{'valid'} }
319              
320             =item error_is_bad_group
321              
322             =item error_is_bad_publisher
323              
324             =item error_is_article_out_of_range
325              
326             =item error_is_bad_checksum
327              
328             Returns true if the ISBN error is that type.
329              
330             =cut
331              
332             sub error_is_bad_group {
333 2     2 1 5 return $_[0]->error == INVALID_GROUP_CODE;
334             }
335              
336             sub error_is_bad_publisher {
337 1     1 1 3 return $_[0]->error == INVALID_PUBLISHER_CODE;
338             }
339              
340             sub error_is_article_out_of_range {
341 0     0 1 0 return $_[0]->error == ARTICLE_CODE_OUT_OF_RANGE;
342             }
343              
344             sub error_is_bad_checksum {
345 0     0 1 0 return $_[0]->error == BAD_CHECKSUM;
346             }
347              
348             =item error_text
349              
350             Returns a text version of the error text
351              
352             =cut
353              
354 3     3 1 25 sub error_text { $ERROR_TEXT{$_[0]->{'valid'}} }
355              
356             =item is_valid
357              
358             Return true if the ISBN is valid, meaning that it has a valid prefix
359             (for ISBN-13), group code, and publisher code; and its checksum
360             validates.
361              
362             =cut
363              
364 106679     106679 1 348124 sub is_valid { $_[0]->{'valid'} eq GOOD_ISBN }
365              
366             =item type
367              
368             Returns either C or C.
369              
370             =cut
371              
372 3     3 1 68 sub type { $_[0]->{'type'} }
373              
374              
375             =item prefix
376              
377             Returns the prefix for the ISBN. This is currently either 978 or 979
378             for ISBN-13. It returns the empty string (so, a defined value) for
379             ISBN-10.
380              
381             =cut
382              
383 103     103 1 238 sub prefix { $_[0]->{'prefix'} }
384 428930     428930   821048 sub _prefix_length { length $_[0]->{'prefix'} }
385              
386             =item group_code
387              
388             Returns the group code for the ISBN. This is the numerical version,
389             for example, '0' for the English group. The valid group codes come
390             from C.
391              
392             =cut
393              
394 106702     106702 1 206754 sub group_code { $_[0]->{'group_code'} }
395              
396             =item group
397              
398             Returns the group name for the ISBN. This is the string version. For
399             instance, 'English' for the '0' group. The names come from
400             C.
401              
402             =cut
403              
404 7     7 1 24 sub group { $_[0]->_group_data( $_[0]->group_code )->[0] }
405              
406             sub _group_code_length {
407             length(
408 320039 50   320039   721438 defined $_[0]->{'group_code'} ? $_[0]->{'group_code'} : ''
409             );
410             }
411              
412             =item publisher_code
413              
414             Returns the publisher code for the ISBN. This is the numeric version,
415             for instance '596' for O'Reilly Media.
416              
417             =cut
418              
419 22     22 1 125 sub publisher_code { $_[0]->{'publisher_code'} }
420             sub _publisher_code_length {
421             length(
422 106681 50   106681   190841 defined $_[0]->{'publisher_code'} ? $_[0]->{'publisher_code'} : ''
423             );
424             }
425              
426             =item article_code
427              
428             Returns the article code for the ISBN. This is the numeric version that
429             uniquely identifies the item.
430              
431             =cut
432              
433 7     7 1 37 sub article_code { $_[0]->{'article_code'} }
434              
435             =item article_code_length
436              
437             Returns the article code length for the ISBN.
438              
439             =cut
440              
441 5     5 1 43 sub article_code_length { length $_[0]->{'article_code'} }
442              
443             =item article_code_min
444              
445             Returns the minimum article code length for the publisher code.
446              
447             =cut
448              
449 4     4 1 16 sub article_code_min { 0 }
450              
451             =item article_code_max
452              
453             Returns the max article code length for the publisher code.
454              
455             =cut
456              
457 3     3 1 7 sub article_code_max { '9' x $_[0]->article_code_length }
458              
459             =item checksum
460              
461             Returns the checksum code for the ISBN. This checksum may not be valid since
462             you can create an object an fix the checksum later with C.
463              
464             =cut
465              
466 106691     106691 1 251378 sub checksum { $_[0]->{'checksum'} }
467 35     35   66 sub _checksum_pos { length( $_[0]->isbn ) - 1 }
468              
469              
470             =item is_valid_checksum
471              
472             Returns C for valid checksums and
473             C otherwise. This does not guarantee
474             that the rest of the ISBN is actually assigned to a book.
475              
476             =cut
477              
478             sub is_valid_checksum {
479 106688     106688 1 138474 my $self = shift;
480              
481 106688 50       184732 cluck "is_valid_checksum: Didn't get object!" unless ref $self;
482              
483 8     8   84 no warnings 'uninitialized';
  8         25  
  8         13842  
484 106688 100       172244 return GOOD_ISBN if $self->checksum eq $self->_checksum;
485              
486 31         96 return BAD_CHECKSUM;
487             }
488              
489             =item fix_checksum
490              
491             Checks the checksum and modifies the ISBN to set it correctly if needed.
492              
493             =cut
494              
495             sub fix_checksum {
496 13     13 1 31 my $self = shift;
497              
498 13         29 my $last_char = substr($self->isbn, $self->_checksum_pos, 1);
499 13         32 my $checksum = $self->_checksum;
500              
501 13         28 my $isbn = $self->isbn;
502 13         25 substr($isbn, $self->_checksum_pos, 1) = $checksum;
503              
504 13         47 $self->_set_isbn( $isbn );
505 13         26 $self->_set_checksum( $checksum );
506              
507 13         42 $self->_check_validity;
508              
509 13 100       39 return 0 if $last_char eq $checksum;
510 9         18 return 1;
511             }
512              
513              
514             =item as_string(), as_string([])
515              
516             Return the ISBN as a string. This function takes an
517             optional anonymous array (or array reference) that specifies
518             the placement of hyphens in the string. An empty anonymous array
519             produces a string with no hyphens. An empty argument list
520             automatically hyphenates the ISBN based on the discovered
521             group and publisher codes. An ISBN that is not valid may
522             produce strange results.
523              
524             The positions specified in the passed anonymous array
525             are only used for one method use and do not replace
526             the values specified by the constructor. The method
527             assumes that you know what you are doing and will attempt
528             to use the least three positions specified. If you pass
529             an anonymous array of several positions, the list will
530             be sorted and the lowest three positions will be used.
531             Positions less than 1 and greater than 12 are silently
532             ignored.
533              
534             A terminating 'x' is changed to 'X'.
535              
536             =cut
537              
538             sub as_string {
539 22     22 1 1095 my $self = shift;
540 22         37 my $array_ref = shift;
541              
542             #this allows one to override the positions settings from the
543             #constructor
544 22 100       111 $array_ref = $self->_hyphen_positions unless ref $array_ref eq ref [];
545              
546             # print STDERR Data::Dumper->Dump( [$array_ref], [qw(array_ref)] );
547             # print STDERR Data::Dumper->Dump( [$self], [qw(self)] );
548              
549 22 50       67 return unless $self->is_valid eq GOOD_ISBN;
550 22         53 my $isbn = $self->isbn;
551              
552 22         93 foreach my $position ( sort { $b <=> $a } @$array_ref ) {
  42         87  
553 45 50 33     147 next if $position > 12 or $position < 1;
554 45         118 substr($isbn, $position, 0) = '-';
555             }
556              
557 22         137 return $isbn;
558             }
559              
560             =item as_isbn10
561              
562             Returns a new ISBN object. If the object is already ISBN-10, this method
563             clones it. If it is an ISBN-13 with the prefix 978, it returns the ISBN-10
564             equivalent. For all other cases it returns undef.
565              
566             =cut
567              
568             sub as_isbn10 {
569 0     0 1 0 croak "as_isbn10() must be implemented in Business::ISBN subclass"
570             }
571              
572             =item as_isbn13
573              
574             Returns a new ISBN object. If the object is already ISBN-13, this method
575             clones it. If it is an ISBN-10, it returns the ISBN-13 equivalent with the
576             978 prefix.
577              
578             =cut
579              
580             sub as_isbn13 {
581 0     0 1 0 croak "as_isbn13() must be implemented in Business::ISBN subclass"
582             }
583              
584             =item increment
585              
586             Returns the next C by incrementing the article code of
587             the specified ISBN (object or scalar).
588              
589             Returns undef, if the parameter is invalid or equals the maximum
590             possible ISBN for the publisher.
591              
592             $isbn = Business::ISBN->new('1565922573'); # 1-56592-257-3
593             $next_isbn = $isbn->increment; # 1-56592-258-1
594              
595             If the next article code would exceed the maximum possible article
596             code (such as incrementing 999 to 1000), this returns ARTICLE_CODE_OUT_OF_RANGE
597             as the error.
598              
599             =cut
600              
601 2     2 1 1052 sub increment { $_[0]->_step_article_code( +1 ) }
602              
603             =item decrement
604              
605             Returns the previous C by decrementing the article
606             code of the specified ISBN (object or scalar).
607              
608             Returns undef, if the parameter is invalid or equals the minimum
609             possible ISBN for the publisher.
610              
611             $isbn = Business::ISBN->new('1565922573'); # 1-56592-257-3
612             $prev_isbn = $isbn->decrement; # 1-56592-256-5
613              
614             If the next article code would exceed the maximum possible article
615             code (such as incrementing 000 to -1), this returns ARTICLE_CODE_OUT_OF_RANGE
616             as the error.
617              
618             =cut
619              
620 2     2 1 1007 sub decrement { $_[0]->_step_article_code( -1 ) }
621              
622             sub _step_article_code {
623 4     4   9 my( $self, $step ) = @_;
624 4 50 33     20 carp "The step for _step_isbn must be an integer"
625             unless( $step == int $step and $step != 0 );
626              
627 4         10 my $next_article_code = int $self->article_code + $step;
628              
629 4 100 100     12 return ARTICLE_CODE_OUT_OF_RANGE unless
630             $next_article_code >= $self->article_code_min
631             &&
632             $next_article_code <= $self->article_code_max
633             ;
634              
635 2         7 my $next_isbn = Business::ISBN->new(
636             join('',
637             $self->prefix,
638             $self->group_code,
639             $self->publisher_code,
640             sprintf( "%0*d", $self->article_code_length, $next_article_code ),
641             '0'
642             )
643             );
644              
645 2         7 $next_isbn->fix_checksum;
646              
647 2         8 $next_isbn;
648             }
649              
650             =item png_barcode
651              
652             Returns image data in PNG format for the barcode for the ISBN. This
653             works with ISBN-10 and ISBN-13. The ISBN-10s are automaically converted
654             to ISBN-13.
655              
656             This requires C.
657              
658             =cut
659              
660             sub png_barcode {
661 0     0 1 0 my $self = shift;
662              
663 0         0 my $ean = $self->as_isbn13->as_string([]);
664              
665 0         0 eval "use GD::Barcode::EAN13";
666 0 0       0 if( $@ )
667             {
668 0         0 carp "Need GD::Barcode::EAN13 to use png_barcode!";
669 0         0 return;
670             }
671              
672 0         0 my $image = GD::Barcode::EAN13->new($ean)->plot->png;
673              
674 0         0 return $image;
675             }
676              
677             =back
678              
679             =cut
680              
681 106691     106691   164541 sub _set_isbn { $_[0]->{'isbn'} = $_[1]; }
682              
683 213369     213369   362520 sub _set_is_valid { $_[0]->{'valid'} = $_[1]; }
684              
685             sub _set_prefix
686             {
687 0     0   0 croak "_set_prefix() must be implemented in Business::ISBN subclass"
688             }
689              
690 106673     106673   226214 sub _set_group_code { $_[0]->{'group_code'} = $_[1]; }
691              
692 0     0   0 sub _set_group_code_string { $_[0]->{'group_code_string'} = $_[1]; }
693              
694 106669     106669   330601 sub _set_publisher_code { $_[0]->{'publisher_code'} = $_[1]; }
695              
696 0     0   0 sub _set_publisher_code_string { $_[0]->{'publisher_code_string'} = $_[1]; }
697              
698 106669     106669   207227 sub _set_article_code { $_[0]->{'article_code'} = $_[1]; }
699              
700 106682     106682   219251 sub _set_checksum { $_[0]->{'checksum'} = $_[1]; }
701              
702             sub _set_type {
703 0     0   0 croak "_set_type() must be implemented in Business::ISBN subclass"
704             }
705              
706              
707             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
708             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
709             # # internal methods. you don't get to use this one.
710             sub _common_format {
711             #we want uppercase X's
712 106688     106688   176624 my $data = uc shift;
713              
714             #get rid of everything except decimal digits and X
715 106688         231917 $data =~ s/[^0-9X]//g;
716              
717 106688 100       600001 return $1 if $data =~ m/
718             \A #anchor at start
719             (
720             (?:\d\d\d)?
721             \d{9}[0-9X]
722             )
723             \z #anchor at end
724             /x;
725              
726 10         17 return;
727             }
728              
729             sub _init {
730 106678     106678   137532 my $self = shift;
731 106678         129291 my $common_data = shift;
732              
733 106678         389907 my $class = ref $self =~ m/.*::(.*)/g;
734              
735 106678         278256 $self->_set_type;
736 106678         220237 $self->_set_isbn( $common_data );
737              
738             # we don't know if we have a valid group code yet
739             # so let's assume that we don't
740 106678         173329 $self->_set_is_valid( INVALID_GROUP_CODE );
741             }
742              
743             {
744             my @methods = (
745             [ qw( prefix ), INVALID_PREFIX ],
746             [ qw( group_code ), INVALID_GROUP_CODE ],
747             [ qw( publisher_code ), INVALID_PUBLISHER_CODE ],
748             [ qw( article_code ), BAD_ISBN ],
749             [ qw( checksum ), BAD_CHECKSUM ],
750             );
751              
752             sub _parse_isbn {
753 106678     106678   145867 my $self = shift;
754              
755 106678         183073 foreach my $pair ( @methods ) {
756 533366         886374 my( $method, $error_code ) = @$pair;
757              
758 533366         753171 my $parser = "_parse_$method";
759 533366         938556 my $result = $self->$parser;
760              
761 533366 100       923243 unless( defined $result ) {
762 9         24 $self->_set_is_valid( $error_code );
763             #print STDERR "Got bad result for $method [$$self{isbn}]\n";
764 9         18 return;
765             }
766              
767 533357         796971 $method = "_set_$method";
768 533357         1005686 $self->$method( $result );
769             }
770              
771 106669         186411 $self->_set_is_valid( $self->is_valid_checksum );
772              
773 106669         144982 return $self;
774             }
775             }
776              
777             sub _parse_group_code {
778 106677     106677   144135 my $self = shift;
779              
780 106677         126035 my $trial; # try this to see what we get
781 106677         124380 my $group_code_length = 0;
782              
783 106677         123503 my $count = 1;
784              
785             GROUP_CODE:
786 106677         170940 while( defined( $trial= substr($self->isbn, $self->_prefix_length, $count++) ) ) {
787 108888 100       202657 if( defined $self->_group_data( $trial ) ) {
788 106673         224487 return $trial;
789 0         0 last GROUP_CODE;
790             }
791              
792             # if we've past the point of finding a group
793             # code we're pretty much stuffed.
794 2215 100       4119 return if $count > $self->_max_group_code_length;
795             }
796              
797 0         0 return; #failed if I got this far
798             }
799              
800             sub _parse_publisher_code {
801 106673     106673   145860 my $self = shift;
802              
803 106673         169560 my $pairs = $self->_publisher_ranges;
804              
805             # get the longest possible publisher code
806             # I'll try substrs of this to get the real one
807 106673         189390 my $longest = substr(
808             $self->isbn,
809             $self->_prefix_length + $self->_group_code_length,
810             $self->_max_publisher_code_length,
811             );
812              
813             #print STDERR "Trying to parse publisher: longest [$longest]\n";
814 106673         217581 while( @$pairs ) {
815 1214104         1531800 my $lower = shift @$pairs;
816 1214104         1515444 my $upper = shift @$pairs;
817              
818 1214104         1600597 my $trial = substr( $longest, 0, length $lower );
819             #print STDERR "Trying [$trial] with $lower <-> $upper [$$self{isbn}]\n";
820              
821             # this has to be a sring comparison because there are
822             # possibly leading 0s
823 1214104 100 100     3363782 if( $trial ge $lower and $trial le $upper )
824             {
825             #print STDERR "Returning $trial\n";
826 106669         325429 return $trial;
827             }
828              
829             }
830              
831 4         12 return; #failed if I got this far
832             }
833              
834             sub _parse_article_code {
835 106669     106669   132860 my $self = shift;
836              
837 106669         160754 my $head = $self->_prefix_length +
838             $self->_group_code_length +
839             $self->_publisher_code_length;
840 106669         166771 my $length = length( $self->isbn ) - $head - 1;
841              
842 106669         156723 substr( $self->isbn, $head, $length );
843             }
844              
845             sub _parse_checksum {
846 106669     106669   128569 my $self = shift;
847              
848 106669         150878 substr( $self->isbn, -1, 1 );
849             }
850              
851             sub _check_validity {
852 13     13   23 my $self = shift;
853              
854 13 50 33     24 if( $self->is_valid_checksum eq GOOD_ISBN and
      33        
      33        
855             defined $self->group_code and
856             defined $self->publisher_code and
857             defined $self->prefix
858             ) {
859 13         36 $self->_set_is_valid( GOOD_ISBN );
860 13         26 return GOOD_ISBN;
861             }
862             else {
863 0 0         $self->_set_is_valid( INVALID_PUBLISHER_CODE )
864             unless defined $self->publisher_code;
865 0 0         $self->_set_is_valid( INVALID_GROUP_CODE )
866             unless defined $self->group_code;
867 0 0         $self->_set_is_valid( INVALID_PREFIX )
868             unless defined $self->prefix;
869 0           return;
870             }
871             }
872              
873             sub _hyphen_positions {
874 0     0     croak "hyphen_positions() must be implemented in Business::ISBN subclass"
875             }
876              
877              
878             1;
879              
880             __END__