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   213601 use 5.008;
  8         46  
2              
3             package Business::ISBN;
4 8     8   40 use strict;
  8         23  
  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         38 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   4352 );
  8         187  
77 8         594 use vars qw(
78             @EXPORT_OK
79             %EXPORT_TAGS
80             %group_data
81             $MAX_GROUP_CODE_LENGTH
82 8     8   712 );
  8         16  
83              
84 8     8   49 use Carp qw(carp croak cluck);
  8         15  
  8         423  
85 8     8   43 use Exporter qw(import);
  8         16  
  8         375  
86              
87 8     8   4594 use Business::ISBN::Data 20230322.001; # now a separate module
  8         327558  
  8         1866  
88             # ugh, hack
89             *group_data = *Business::ISBN::country_data;
90             sub _group_data {
91 215568 100   215568   435095 my $isbn_prefix
92             = ref $_[0] eq 'Business::ISBN13'
93             ? $_[0]->prefix
94             : "978";
95 215568         1135522 return $group_data{ $isbn_prefix }->{ $_[1] };
96             }
97              
98 2216     2216   5445 sub _max_group_code_length { $Business::ISBN::MAX_COUNTRY_CODE_LENGTH };
99             sub _max_publisher_code_length {
100 106673     106673   241237 $_[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   136591 my $self = shift;
111 106673         129492 [ @{ $self->_group_data( $self->group_code )->[1] } ];
  106673         183111  
112             }
113              
114             my $debug = $ENV{BUSINESS_ISBN_DEBUG};
115              
116             BEGIN {
117 8     8   44 @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         1029 %EXPORT_TAGS = (
126             'all' => \@EXPORT_OK,
127             );
128             };
129              
130             our $VERSION = '3.008';
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   3215 use Business::ISBN10;
  8         19  
  8         427  
151 8     8   2830 use Business::ISBN13;
  8         22  
  8         7324  
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 1215 my $isbn = shift;
177              
178 4         11 my $obj = Business::ISBN->new( $isbn );
179 4 50       11 return unless defined $obj;
180              
181 4 100       9 return 1 if $obj->is_valid_checksum == GOOD_ISBN;
182 2 50       4 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 1105456 my $class = shift;
246 106688         162753 my $input_data = shift;
247 106688         192828 my $common_data = _common_format $input_data;
248              
249 106688 100       237251 return unless $common_data;
250              
251 106678         264918 my $self = {
252             input_isbn => $input_data,
253             common_data => $common_data
254             };
255              
256 106678         155894 my $isbn = do {
257 106678 100       195491 if( length( $common_data ) == 10 ) {
    50          
258 106643         199684 bless $self, 'Business::ISBN10';
259             }
260             elsif( length( $common_data ) == 13 ) {
261 35         77 bless $self, 'Business::ISBN13';
262             }
263             else {
264 0         0 return BAD_ISBN;
265             }
266             };
267              
268 106678         251646 $self->_init( $common_data );
269 106678         229892 $self->_parse_isbn( $common_data );
270              
271 106678         211067 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 8 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 10 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 1254441 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 2229 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 46 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 361742 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 17 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 226 sub prefix { $_[0]->{'prefix'} }
384 428930     428930   848328 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 230305 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 31 sub group { $_[0]->_group_data( $_[0]->group_code )->[0] }
405              
406             sub _group_code_length {
407             length(
408 320039 50   320039   782431 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 124 sub publisher_code { $_[0]->{'publisher_code'} }
420             sub _publisher_code_length {
421             length(
422 106681 50   106681   202226 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 32 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 17 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 278963 sub checksum { $_[0]->{'checksum'} }
467 35     35   65 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 140798 my $self = shift;
480              
481 106688 50       211391 cluck "is_valid_checksum: Didn't get object!" unless ref $self;
482              
483 8     8   73 no warnings 'uninitialized';
  8         35  
  8         14075  
484 106688 100       169768 return GOOD_ISBN if $self->checksum eq $self->_checksum;
485              
486 31         97 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 46 my $self = shift;
497              
498 13         27 my $last_char = substr($self->isbn, $self->_checksum_pos, 1);
499 13         34 my $checksum = $self->_checksum;
500              
501 13         25 my $isbn = $self->isbn;
502 13         24 substr($isbn, $self->_checksum_pos, 1) = $checksum;
503              
504 13         34 $self->_set_isbn( $isbn );
505 13         33 $self->_set_checksum( $checksum );
506              
507 13         39 $self->_check_validity;
508              
509 13 100       38 return 0 if $last_char eq $checksum;
510 9         19 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 1031 my $self = shift;
540 22         31 my $array_ref = shift;
541              
542             #this allows one to override the positions settings from the
543             #constructor
544 22 100       102 $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       55 return unless $self->is_valid eq GOOD_ISBN;
550 22         50 my $isbn = $self->isbn;
551              
552 22         70 foreach my $position ( sort { $b <=> $a } @$array_ref ) {
  42         83  
553 45 50 33     141 next if $position > 12 or $position < 1;
554 45         104 substr($isbn, $position, 0) = '-';
555             }
556              
557 22         150 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 992 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 984 sub decrement { $_[0]->_step_article_code( -1 ) }
621              
622             sub _step_article_code {
623 4     4   9 my( $self, $step ) = @_;
624 4 50 33     18 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     23 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   167172 sub _set_isbn { $_[0]->{'isbn'} = $_[1]; }
682              
683 213369     213369   405207 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   241720 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   339697 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   227021 sub _set_article_code { $_[0]->{'article_code'} = $_[1]; }
699              
700 106682     106682   239464 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   180914 my $data = uc shift;
713              
714             #get rid of everything except decimal digits and X
715 106688         251216 $data =~ s/[^0-9X]//g;
716              
717 106688 100       628326 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         20 return;
727             }
728              
729             sub _init {
730 106678     106678   162910 my $self = shift;
731 106678         138531 my $common_data = shift;
732              
733 106678         408987 my $class = ref $self =~ m/.*::(.*)/g;
734              
735 106678         302082 $self->_set_type;
736 106678         240794 $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         184359 $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   145958 my $self = shift;
754              
755 106678         178804 foreach my $pair ( @methods ) {
756 533366         940301 my( $method, $error_code ) = @$pair;
757              
758 533366         816391 my $parser = "_parse_$method";
759 533366         982700 my $result = $self->$parser;
760              
761 533366 100       985277 unless( defined $result ) {
762 9         23 $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         873496 $method = "_set_$method";
768 533357         1089185 $self->$method( $result );
769             }
770              
771 106669         198867 $self->_set_is_valid( $self->is_valid_checksum );
772              
773 106669         155411 return $self;
774             }
775             }
776              
777             sub _parse_group_code {
778 106677     106677   142920 my $self = shift;
779              
780 106677         148519 my $trial; # try this to see what we get
781 106677         134580 my $group_code_length = 0;
782              
783 106677         131119 my $count = 1;
784              
785             GROUP_CODE:
786 106677         197887 while( defined( $trial= substr($self->isbn, $self->_prefix_length, $count++) ) ) {
787 108888 100       225591 if( defined $self->_group_data( $trial ) ) {
788 106673         236172 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       4122 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   158446 my $self = shift;
802              
803 106673         184378 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         199338 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         232743 while( @$pairs ) {
815 1216517         1597431 my $lower = shift @$pairs;
816 1216517         1581898 my $upper = shift @$pairs;
817              
818 1216517         1668214 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 1216517 100 100     3615254 if( $trial ge $lower and $trial le $upper )
824             {
825             #print STDERR "Returning $trial\n";
826 106669         332757 return $trial;
827             }
828              
829             }
830              
831 4         10 return; #failed if I got this far
832             }
833              
834             sub _parse_article_code {
835 106669     106669   137391 my $self = shift;
836              
837 106669         171427 my $head = $self->_prefix_length +
838             $self->_group_code_length +
839             $self->_publisher_code_length;
840 106669         179703 my $length = length( $self->isbn ) - $head - 1;
841              
842 106669         161955 substr( $self->isbn, $head, $length );
843             }
844              
845             sub _parse_checksum {
846 106669     106669   152845 my $self = shift;
847              
848 106669         169381 substr( $self->isbn, -1, 1 );
849             }
850              
851             sub _check_validity {
852 13     13   22 my $self = shift;
853              
854 13 50 33     22 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         38 $self->_set_is_valid( GOOD_ISBN );
860 13         27 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__