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   216401 use 5.008;
  8         48  
2              
3             package Business::ISBN;
4 8     8   47 use strict;
  8         12  
  8         382  
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         46 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   4746 );
  8         193  
77 8         621 use vars qw(
78             @EXPORT_OK
79             %EXPORT_TAGS
80             %group_data
81             $MAX_GROUP_CODE_LENGTH
82 8     8   737 );
  8         17  
83              
84 8     8   49 use Carp qw(carp croak cluck);
  8         14  
  8         491  
85 8     8   50 use Exporter qw(import);
  8         13  
  8         349  
86              
87 8     8   4774 use Business::ISBN::Data 20191107; # now a separate module
  8         308409  
  8         1956  
88             # ugh, hack
89             *group_data = *Business::ISBN::country_data;
90             sub _group_data {
91 215568 100   215568   456575 my $isbn_prefix
92             = ref $_[0] eq 'Business::ISBN13'
93             ? $_[0]->prefix
94             : "978";
95 215568         1122320 return $group_data{ $isbn_prefix }->{ $_[1] };
96             }
97              
98 2216     2216   5356 sub _max_group_code_length { $Business::ISBN::MAX_COUNTRY_CODE_LENGTH };
99             sub _max_publisher_code_length {
100 106673     106673   232613 $_[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   142887 my $self = shift;
111 106673         133839 [ @{ $self->_group_data( $self->group_code )->[1] } ];
  106673         176287  
112             }
113              
114             my $debug = $ENV{BUSINESS_ISBN_DEBUG};
115              
116             BEGIN {
117 8     8   46 @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         1069 %EXPORT_TAGS = (
126             'all' => \@EXPORT_OK,
127             );
128             };
129              
130             our $VERSION = '3.006';
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   3937 use Business::ISBN10;
  8         18  
  8         390  
151 8     8   3093 use Business::ISBN13;
  8         22  
  8         7633  
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 1146 my $isbn = shift;
177              
178 4         13 my $obj = Business::ISBN->new( $isbn );
179 4 50       9 return unless defined $obj;
180              
181 4 100       8 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 1073010 my $class = shift;
246 106688         157326 my $input_data = shift;
247 106688         180520 my $common_data = _common_format $input_data;
248              
249 106688 100       239888 return unless $common_data;
250              
251 106678         273354 my $self = {
252             input_isbn => $input_data,
253             common_data => $common_data
254             };
255              
256 106678         154633 my $isbn = do {
257 106678 100       198126 if( length( $common_data ) == 10 ) {
    50          
258 106643         194185 bless $self, 'Business::ISBN10';
259             }
260             elsif( length( $common_data ) == 13 ) {
261 35         75 bless $self, 'Business::ISBN13';
262             }
263             else {
264 0         0 return BAD_ISBN;
265             }
266             };
267              
268 106678         236841 $self->_init( $common_data );
269 106678         238339 $self->_parse_isbn( $common_data );
270              
271 106678         212371 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 11 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 1234524 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 2188 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 6 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 47 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 365152 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 20 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 227 sub prefix { $_[0]->{'prefix'} }
384 428930     428930   842302 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 212568 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 27 sub group { $_[0]->_group_data( $_[0]->group_code )->[0] }
405              
406             sub _group_code_length {
407             length(
408 320039 50   320039   764860 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 110 sub publisher_code { $_[0]->{'publisher_code'} }
420             sub _publisher_code_length {
421             length(
422 106681 50   106681   214545 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 35 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 32 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 13 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 30 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 274625 sub checksum { $_[0]->{'checksum'} }
467 35     35   67 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 161808 my $self = shift;
480              
481 106688 50       206036 cluck "is_valid_checksum: Didn't get object!" unless ref $self;
482              
483 8     8   101 no warnings 'uninitialized';
  8         17  
  8         14352  
484 106688 100       179146 return GOOD_ISBN if $self->checksum eq $self->_checksum;
485              
486 31         101 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 33 my $self = shift;
497              
498 13         27 my $last_char = substr($self->isbn, $self->_checksum_pos, 1);
499 13         33 my $checksum = $self->_checksum;
500              
501 13         41 my $isbn = $self->isbn;
502 13         30 substr($isbn, $self->_checksum_pos, 1) = $checksum;
503              
504 13         32 $self->_set_isbn( $isbn );
505 13         35 $self->_set_checksum( $checksum );
506              
507 13         45 $self->_check_validity;
508              
509 13 100       40 return 0 if $last_char eq $checksum;
510 9         20 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 878 my $self = shift;
540 22         29 my $array_ref = shift;
541              
542             #this allows one to override the positions settings from the
543             #constructor
544 22 100       115 $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       60 return unless $self->is_valid eq GOOD_ISBN;
550 22         51 my $isbn = $self->isbn;
551              
552 22         72 foreach my $position ( sort { $b <=> $a } @$array_ref ) {
  42         81  
553 45 50 33     148 next if $position > 12 or $position < 1;
554 45         91 substr($isbn, $position, 0) = '-';
555             }
556              
557 22         122 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 887 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 830 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         11 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         6 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         6 $next_isbn->fix_checksum;
646              
647 2         5 $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   164314 sub _set_isbn { $_[0]->{'isbn'} = $_[1]; }
682              
683 213369     213369   383405 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   238385 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   344340 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   232647 sub _set_article_code { $_[0]->{'article_code'} = $_[1]; }
699              
700 106682     106682   245664 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   181778 my $data = uc shift;
713              
714             #get rid of everything except decimal digits and X
715 106688         244443 $data =~ s/[^0-9X]//g;
716              
717 106688 100       636250 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         19 return;
727             }
728              
729             sub _init {
730 106678     106678   147698 my $self = shift;
731 106678         142811 my $common_data = shift;
732              
733 106678         434249 my $class = ref $self =~ m/.*::(.*)/g;
734              
735 106678         291193 $self->_set_type;
736 106678         241818 $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         182064 $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   156596 my $self = shift;
754              
755 106678         173803 foreach my $pair ( @methods )
756             {
757 533366         909319 my( $method, $error_code ) = @$pair;
758              
759 533366         821303 my $parser = "_parse_$method";
760 533366         1013179 my $result = $self->$parser;
761              
762 533366 100       999813 unless( defined $result )
763             {
764 9         26 $self->_set_is_valid( $error_code );
765             #print STDERR "Got bad result for $method [$$self{isbn}]\n";
766 9         17 return;
767             }
768              
769 533357         848526 $method = "_set_$method";
770 533357         1062908 $self->$method( $result );
771             }
772              
773 106669         193392 $self->_set_is_valid( $self->is_valid_checksum );
774              
775 106669         151528 return $self;
776             }
777             }
778              
779             sub _parse_group_code {
780 106677     106677   139472 my $self = shift;
781              
782 106677         132688 my $trial; # try this to see what we get
783 106677         139158 my $group_code_length = 0;
784              
785 106677         132010 my $count = 1;
786              
787             GROUP_CODE:
788 106677         189455 while( defined( $trial= substr($self->isbn, $self->_prefix_length, $count++) ) )
789             {
790 108888 100       231652 if( defined $self->_group_data( $trial ) )
791             {
792 106673         239874 return $trial;
793 0         0 last GROUP_CODE;
794             }
795              
796             # if we've past the point of finding a group
797             # code we're pretty much stuffed.
798 2215 100       3983 return if $count > $self->_max_group_code_length;
799             }
800              
801 0         0 return; #failed if I got this far
802             }
803              
804             sub _parse_publisher_code {
805 106673     106673   142724 my $self = shift;
806              
807 106673         174632 my $pairs = $self->_publisher_ranges;
808              
809             # get the longest possible publisher code
810             # I'll try substrs of this to get the real one
811 106673         193171 my $longest = substr(
812             $self->isbn,
813             $self->_prefix_length + $self->_group_code_length,
814             $self->_max_publisher_code_length,
815             );
816              
817             #print STDERR "Trying to parse publisher: longest [$longest]\n";
818 106673         234467 while( @$pairs ) {
819 1214104         1676560 my $lower = shift @$pairs;
820 1214104         1640208 my $upper = shift @$pairs;
821              
822 1214104         1800037 my $trial = substr( $longest, 0, length $lower );
823             #print STDERR "Trying [$trial] with $lower <-> $upper [$$self{isbn}]\n";
824              
825             # this has to be a sring comparison because there are
826             # possibly leading 0s
827 1214104 100 100     3843942 if( $trial ge $lower and $trial le $upper )
828             {
829             #print STDERR "Returning $trial\n";
830 106669         327070 return $trial;
831             }
832              
833             }
834              
835 4         9 return; #failed if I got this far
836             }
837              
838             sub _parse_article_code {
839 106669     106669   140805 my $self = shift;
840              
841 106669         168681 my $head = $self->_prefix_length +
842             $self->_group_code_length +
843             $self->_publisher_code_length;
844 106669         180907 my $length = length( $self->isbn ) - $head - 1;
845              
846 106669         161967 substr( $self->isbn, $head, $length );
847             }
848              
849             sub _parse_checksum {
850 106669     106669   147262 my $self = shift;
851              
852 106669         156146 substr( $self->isbn, -1, 1 );
853             }
854              
855             sub _check_validity {
856 13     13   22 my $self = shift;
857              
858 13 50 33     23 if( $self->is_valid_checksum eq GOOD_ISBN and
      33        
      33        
859             defined $self->group_code and
860             defined $self->publisher_code and
861             defined $self->prefix
862             ) {
863 13         36 $self->_set_is_valid( GOOD_ISBN );
864 13         26 return GOOD_ISBN;
865             }
866             else {
867 0 0         $self->_set_is_valid( INVALID_PUBLISHER_CODE )
868             unless defined $self->publisher_code;
869 0 0         $self->_set_is_valid( INVALID_GROUP_CODE )
870             unless defined $self->group_code;
871 0 0         $self->_set_is_valid( INVALID_PREFIX )
872             unless defined $self->prefix;
873 0           return;
874             }
875             }
876              
877             sub _hyphen_positions {
878 0     0     croak "hyphen_positions() must be implemented in Business::ISBN subclass"
879             }
880              
881              
882             1;
883              
884             __END__