File Coverage

blib/lib/Business/ISBN.pm
Criterion Covered Total %
statement 166 197 84.2
branch 38 58 65.5
condition 11 21 52.3
subroutine 59 69 85.5
pod 30 30 100.0
total 304 375 81.0


line stmt bran cond sub pod time code
1 8     8   1790313 use 5.008;
  8         35  
2              
3             package Business::ISBN;
4 8     8   49 use strict;
  8         39  
  8         551  
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         52 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   3935 );
  8         2928  
77 8         760 use vars qw(
78             @EXPORT_OK
79             %EXPORT_TAGS
80             %group_data
81             $MAX_GROUP_CODE_LENGTH
82 8     8   946 );
  8         40  
83              
84 8     8   52 use Carp qw(carp croak cluck);
  8         25  
  8         693  
85 8     8   47 use Exporter qw(import);
  8         16  
  8         402  
86              
87 8     8   5354 use Business::ISBN::Data 20230322.001; # now a separate module
  8         425523  
  8         2938  
88             # ugh, hack
89             *group_data = *Business::ISBN::country_data;
90             sub _group_data {
91 215568 100   215568   513084 my $isbn_prefix
92             = ref $_[0] eq 'Business::ISBN13'
93             ? $_[0]->prefix
94             : "978";
95 215568         1858593 return $group_data{ $isbn_prefix }->{ $_[1] };
96             }
97              
98 2216     2216   7571 sub _max_group_code_length { $Business::ISBN::MAX_COUNTRY_CODE_LENGTH };
99             sub _max_publisher_code_length {
100 106673     106673   292848 $_[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   160503 my $self = shift;
111 106673         161458 [ @{ $self->_group_data( $self->group_code )->[1] } ];
  106673         206679  
112             }
113              
114             my $debug = $ENV{BUSINESS_ISBN_DEBUG};
115              
116             BEGIN {
117 8     8   69 @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         1289 %EXPORT_TAGS = (
126             'all' => \@EXPORT_OK,
127             );
128             };
129              
130             our $VERSION = '3.013';
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   4723 use Business::ISBN10;
  8         27  
  8         502  
151 8     8   3828 use Business::ISBN13;
  8         40  
  8         8734  
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 1540 my $isbn = shift;
177              
178 4         40 my $obj = Business::ISBN->new( $isbn );
179 4 50       11 return unless defined $obj;
180              
181 4 100       7 return 1 if $obj->is_valid_checksum == GOOD_ISBN;
182 2 50       7 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 2287135 my $class = shift;
246 106688         174524 my $input_data = shift;
247 106688         236858 my $common_data = _common_format $input_data;
248              
249 106688 100       258015 return unless $common_data;
250              
251 106678         339898 my $self = {
252             input_isbn => $input_data,
253             common_data => $common_data
254             };
255              
256 106678         158996 my $isbn = do {
257 106678 100       225372 if( length( $common_data ) == 10 ) {
    50          
258 106643         242241 bless $self, 'Business::ISBN10';
259             }
260             elsif( length( $common_data ) == 13 ) {
261 35         117 bless $self, 'Business::ISBN13';
262             }
263             else {
264 0         0 return BAD_ISBN;
265             }
266             };
267              
268 106678         285306 $self->_init( $common_data );
269 106678         260734 $self->_parse_isbn( $common_data );
270              
271 106678         316400 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 10 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 7 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 1573309 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 2925 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 4 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 19 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 462781 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 45 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 309 sub prefix { $_[0]->{'prefix'} }
384 428930     428930   1139308 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 249202 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 38 sub group { $_[0]->_group_data( $_[0]->group_code )->[0] }
405              
406             sub _group_code_length {
407             length(
408 320039 50   320039   935542 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 133 sub publisher_code { $_[0]->{'publisher_code'} }
420             sub _publisher_code_length {
421             length(
422 106681 50   106681   237198 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 41 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 41 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 21 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 53 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 338195 sub checksum { $_[0]->{'checksum'} }
467 35     35   93 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 148324 my $self = shift;
480              
481 106688 50       214768 cluck "is_valid_checksum: Didn't get object!" unless ref $self;
482              
483 8     8   79 no warnings 'uninitialized';
  8         17  
  8         17416  
484 106688 100       194971 return GOOD_ISBN if $self->checksum eq $self->_checksum;
485              
486 31         129 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 107 my $self = shift;
497              
498 13         38 my $last_char = substr($self->isbn, $self->_checksum_pos, 1);
499 13         44 my $checksum = $self->_checksum;
500              
501 13         77 my $isbn = $self->isbn;
502 13         37 substr($isbn, $self->_checksum_pos, 1) = $checksum;
503              
504 13         63 $self->_set_isbn( $isbn );
505 13         40 $self->_set_checksum( $checksum );
506              
507 13         63 $self->_check_validity;
508              
509 13 100       52 return 0 if $last_char eq $checksum;
510 9         24 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 1480 my $self = shift;
540 22         49 my $array_ref = shift;
541              
542             #this allows one to override the positions settings from the
543             #constructor
544 22 100       149 $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       81 return unless $self->is_valid eq GOOD_ISBN;
550 22         69 my $isbn = $self->isbn;
551              
552 22         114 foreach my $position ( sort { $b <=> $a } @$array_ref ) {
  42         108  
553 45 50 33     177 next if $position > 12 or $position < 1;
554 45         130 substr($isbn, $position, 0) = '-';
555             }
556              
557 22         179 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 1533 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 3164 sub decrement { $_[0]->_step_article_code( -1 ) }
621              
622             sub _step_article_code {
623 4     4   15 my( $self, $step ) = @_;
624 4 50 33     30 carp "The step for _step_isbn must be an integer"
625             unless( $step == int $step and $step != 0 );
626              
627 4         16 my $next_article_code = int $self->article_code + $step;
628              
629 4 100 100     18 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         8 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         8 $next_isbn->fix_checksum;
646              
647 2         9 $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 { require GD::Barcode::EAN13 };
  0         0  
666 0 0       0 if( $@ ) {
667 0         0 carp "Need GD::Barcode::EAN13 to use png_barcode!";
668 0         0 return;
669             }
670              
671 0         0 my $gd_image = GD::Barcode::EAN13->new($ean)->plot;
672 0         0 my $image;
673 0 0       0 if( $gd_image->can('png') ) {
674 0         0 $image = GD::Barcode::EAN13->new($ean)->plot->png;
675             }
676             else {
677 0         0 carp "Your GD module does not have PNG support";
678 0         0 return;
679             }
680              
681 0         0 return $image;
682             }
683              
684             =back
685              
686             =cut
687              
688 106691     106691   213025 sub _set_isbn { $_[0]->{'isbn'} = $_[1]; }
689              
690 213369     213369   479194 sub _set_is_valid { $_[0]->{'valid'} = $_[1]; }
691              
692             sub _set_prefix
693             {
694 0     0   0 croak "_set_prefix() must be implemented in Business::ISBN subclass"
695             }
696              
697 106673     106673   253283 sub _set_group_code { $_[0]->{'group_code'} = $_[1]; }
698              
699 0     0   0 sub _set_group_code_string { $_[0]->{'group_code_string'} = $_[1]; }
700              
701 106669     106669   447552 sub _set_publisher_code { $_[0]->{'publisher_code'} = $_[1]; }
702              
703 0     0   0 sub _set_publisher_code_string { $_[0]->{'publisher_code_string'} = $_[1]; }
704              
705 106669     106669   251282 sub _set_article_code { $_[0]->{'article_code'} = $_[1]; }
706              
707 106682     106682   253402 sub _set_checksum { $_[0]->{'checksum'} = $_[1]; }
708              
709             sub _set_type {
710 0     0   0 croak "_set_type() must be implemented in Business::ISBN subclass"
711             }
712              
713              
714             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
715             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
716             # # internal methods. you don't get to use this one.
717             sub _common_format {
718             #we want uppercase X's
719 106688     106688   223757 my $data = uc shift;
720              
721             #get rid of everything except decimal digits and X
722 106688         317927 $data =~ s/[^0-9X]//g;
723              
724 106688 100       819105 return $1 if $data =~ m/
725             \A #anchor at start
726             (
727             (?:\d\d\d)?
728             \d{9}[0-9X]
729             )
730             \z #anchor at end
731             /x;
732              
733 10         16 return;
734             }
735              
736             sub _init {
737 106678     106678   165055 my $self = shift;
738 106678         169297 my $common_data = shift;
739              
740 106678         574689 my $class = ref $self =~ m/.*::(.*)/g;
741              
742 106678         382694 $self->_set_type;
743 106678         288342 $self->_set_isbn( $common_data );
744              
745             # we don't know if we have a valid group code yet
746             # so let's assume that we don't
747 106678         247620 $self->_set_is_valid( INVALID_GROUP_CODE );
748             }
749              
750             {
751             my @methods = (
752             [ qw( prefix ), INVALID_PREFIX ],
753             [ qw( group_code ), INVALID_GROUP_CODE ],
754             [ qw( publisher_code ), INVALID_PUBLISHER_CODE ],
755             [ qw( article_code ), BAD_ISBN ],
756             [ qw( checksum ), BAD_CHECKSUM ],
757             );
758              
759             sub _parse_isbn {
760 106678     106678   150061 my $self = shift;
761              
762 106678         216219 foreach my $pair ( @methods ) {
763 533366         1096847 my( $method, $error_code ) = @$pair;
764              
765 533366         793993 my $parser = "_parse_$method";
766 533366         1198676 my $result = $self->$parser;
767              
768 533366 100       1156136 unless( defined $result ) {
769 9         26 $self->_set_is_valid( $error_code );
770             #print STDERR "Got bad result for $method [$$self{isbn}]\n";
771 9         17 return;
772             }
773              
774 533357         814593 $method = "_set_$method";
775 533357         1273904 $self->$method( $result );
776             }
777              
778 106669         211352 $self->_set_is_valid( $self->is_valid_checksum );
779              
780 106669         183807 return $self;
781             }
782             }
783              
784             sub _parse_group_code {
785 106677     106677   167322 my $self = shift;
786              
787 106677         172431 my $trial; # try this to see what we get
788 106677         161951 my $group_code_length = 0;
789              
790 106677         142557 my $count = 1;
791              
792             GROUP_CODE:
793 106677         217520 while( defined( $trial= substr($self->isbn, $self->_prefix_length, $count++) ) ) {
794 108888 100       273349 if( defined $self->_group_data( $trial ) ) {
795 106673         273053 return $trial;
796 0         0 last GROUP_CODE;
797             }
798              
799             # if we've past the point of finding a group
800             # code we're pretty much stuffed.
801 2215 100       5757 return if $count > $self->_max_group_code_length;
802             }
803              
804 0         0 return; #failed if I got this far
805             }
806              
807             sub _parse_publisher_code {
808 106673     106673   170292 my $self = shift;
809              
810 106673         225936 my $pairs = $self->_publisher_ranges;
811              
812             # get the longest possible publisher code
813             # I'll try substrs of this to get the real one
814 106673         256381 my $longest = substr(
815             $self->isbn,
816             $self->_prefix_length + $self->_group_code_length,
817             $self->_max_publisher_code_length,
818             );
819              
820             #print STDERR "Trying to parse publisher: longest [$longest]\n";
821 106673         256535 while( @$pairs ) {
822 1298315         1931521 my $lower = shift @$pairs;
823 1298315         1991166 my $upper = shift @$pairs;
824              
825 1298315         1940764 my $trial = substr( $longest, 0, length $lower );
826             #print STDERR "Trying [$trial] with $lower <-> $upper [$$self{isbn}]\n";
827              
828             # this has to be a sring comparison because there are
829             # possibly leading 0s
830 1298315 100 100     4241706 if( $trial ge $lower and $trial le $upper )
831             {
832             #print STDERR "Returning $trial\n";
833 106669         517600 return $trial;
834             }
835              
836             }
837              
838 4         12 return; #failed if I got this far
839             }
840              
841             sub _parse_article_code {
842 106669     106669   164660 my $self = shift;
843              
844 106669         208137 my $head = $self->_prefix_length +
845             $self->_group_code_length +
846             $self->_publisher_code_length;
847 106669         221103 my $length = length( $self->isbn ) - $head - 1;
848              
849 106669         192658 substr( $self->isbn, $head, $length );
850             }
851              
852             sub _parse_checksum {
853 106669     106669   162523 my $self = shift;
854              
855 106669         212390 substr( $self->isbn, -1, 1 );
856             }
857              
858             sub _check_validity {
859 13     13   29 my $self = shift;
860              
861 13 50 33     37 if( $self->is_valid_checksum eq GOOD_ISBN and
      33        
      33        
862             defined $self->group_code and
863             defined $self->publisher_code and
864             defined $self->prefix
865             ) {
866 13         53 $self->_set_is_valid( GOOD_ISBN );
867 13         46 return GOOD_ISBN;
868             }
869             else {
870 0 0         $self->_set_is_valid( INVALID_PUBLISHER_CODE )
871             unless defined $self->publisher_code;
872 0 0         $self->_set_is_valid( INVALID_GROUP_CODE )
873             unless defined $self->group_code;
874 0 0         $self->_set_is_valid( INVALID_PREFIX )
875             unless defined $self->prefix;
876 0           return;
877             }
878             }
879              
880             sub _hyphen_positions {
881 0     0     croak "hyphen_positions() must be implemented in Business::ISBN subclass"
882             }
883              
884              
885             1;
886              
887             __END__