File Coverage

blib/lib/MARC/Field008.pm
Criterion Covered Total %
statement 114 121 94.2
branch 37 50 74.0
condition 8 9 88.8
subroutine 26 26 100.0
pod 3 3 100.0
total 188 209 89.9


line stmt bran cond sub pod time code
1             package MARC::Field008;
2              
3 5     5   248356 use strict;
  5         12  
  5         204  
4 5     5   51 use warnings;
  5         9  
  5         360  
5              
6 5     5   1191 use Class::Utils qw(set_params);
  5         32535  
  5         252  
7 5     5   4222 use Data::MARC::Field008;
  5         78930  
  5         351  
8 5     5   3593 use Data::MARC::Field008::Book 0.03;
  5         13106  
  5         313  
9 5     5   3192 use Data::MARC::Field008::ComputerFile 0.03;
  5         6432  
  5         242  
10 5     5   6020 use Data::MARC::Field008::ContinuingResource 0.03;
  5         8938  
  5         296  
11 5     5   3230 use Data::MARC::Field008::Map 0.03;
  5         8169  
  5         285  
12 5     5   2801 use Data::MARC::Field008::MixedMaterial 0.03;
  5         5280  
  5         217  
13 5     5   2898 use Data::MARC::Field008::Music 0.03;
  5         8070  
  5         238  
14 5     5   2940 use Data::MARC::Field008::VisualMaterial 0.03;
  5         7602  
  5         336  
15 5     5   37 use Error::Pure qw(err);
  5         9  
  5         328  
16 5     5   30 use List::Util 1.33 qw(any);
  5         142  
  5         376  
17 5     5   28 use Mo::utils 0.08 qw(check_bool check_isa check_required);
  5         110  
  5         425  
18 5     5   78 use Scalar::Util qw(blessed);
  5         53  
  5         13253  
19              
20             our $VERSION = 0.04;
21              
22             # Constructor.
23             sub new {
24 21     21 1 1399776 my ($class, @params) = @_;
25              
26             # Create object.
27 21         127 my $self = bless {}, $class;
28              
29             # Ignore data errors.
30 21         78 $self->{'ignore_data_errors'} = 0;
31              
32             # Leader.
33 21         73 $self->{'leader'} = undef;
34              
35             # Verbose mode.
36 21         52 $self->{'verbose'} = 0;
37              
38             # Process parameters.
39 21         92 set_params($self, @params);
40              
41             # Check 'ignore_data_errors'.
42 21         369 check_required($self, 'ignore_data_errors');
43 21         187 check_bool($self, 'ignore_data_errors');
44              
45             # Check 'leader'.
46 20         435 check_isa($self, 'leader', 'Data::MARC::Leader');
47              
48             # Check 'verbose'.
49 18         489 check_bool($self, 'verbose');
50              
51 18         429 return $self;
52             }
53              
54             sub parse {
55 15     15 1 110 my ($self, $field_008) = @_;
56              
57             # Parameter 'leader' is required for parse().
58 15         46 check_required($self, 'leader');
59              
60             # XXX Fix white space issue in MARC XML record.
61 14 100       133 if (length($field_008) < 40) {
62 2         12 $field_008 .= (' ' x (40 - length($field_008)));
63             }
64              
65             # Check length.
66 14 100       135 if (length($field_008) > 40) {
67 1         8 err 'Bad length of MARC 008 field.',
68             'Length', length($field_008),
69             ;
70             }
71 13 50       42 if ($self->{'verbose'}) {
72 0         0 print "Field 008: |$field_008|\n";
73             }
74              
75 13         88 my %params = (
76             'raw' => $field_008,
77              
78             'date_entered_on_file' => (substr $field_008, 0, 6),
79             'type_of_date' => (substr $field_008, 6, 1),
80             'date1' => (substr $field_008, 7, 4),
81             'date2' => (substr $field_008, 11, 4),
82             'place_of_publication' => (substr $field_008, 15, 3),
83             $self->_parse_different($field_008),
84             'language' => (substr $field_008, 35, 3),
85             'modified_record' => (substr $field_008, 38, 1),
86             'cataloging_source' => (substr $field_008, 39, 1),
87             );
88              
89 13         101 return Data::MARC::Field008->new(%params);
90             }
91              
92             sub serialize {
93 8     8 1 3618 my ($self, $field_008_obj) = @_;
94              
95             # Check object.
96 8 100 100     113 if (! blessed($field_008_obj) || ! $field_008_obj->isa('Data::MARC::Field008')) {
97 2         57 err "Bad 'Data::MARC::Field008' instance to serialize.";
98             }
99              
100 6         22 my $field_008 = $field_008_obj->date_entered_on_file.
101             $field_008_obj->type_of_date.
102             $field_008_obj->date1.
103             $field_008_obj->date2.
104             $field_008_obj->place_of_publication.
105             $self->_serialize_different($field_008_obj->material).
106             $field_008_obj->language.
107             $field_008_obj->modified_record.
108             $field_008_obj->cataloging_source;
109              
110 6         118 return $field_008;
111             }
112              
113             sub _parse_different {
114 13     13   32 my ($self, $field_008) = @_;
115              
116 13         46 my %params;
117              
118             # Book
119 13 100 100 21   85 if ((any { $self->{'leader'}->type eq $_ } qw(a t))
  21 100 66     148  
    100          
    100          
    100          
    50          
    0          
120 20     20   204 && (any { $self->{'leader'}->bibliographic_level eq $_ } qw(a c d m))) {
121              
122 3         82 my %mat_params = (
123             'illustrations' => substr($field_008, 18, 4),
124             'target_audience' => substr($field_008, 22, 1),
125             'form_of_item' => substr($field_008, 23, 1),
126             'nature_of_content' => substr($field_008, 24, 4),
127             'government_publication' => substr($field_008, 28, 1),
128             'conference_publication' => substr($field_008, 29, 1),
129             'festschrift' => substr($field_008, 30, 1),
130             'index' => substr($field_008, 31, 1),
131             'literary_form' => substr($field_008, 33, 1),
132             'biography' => substr($field_008, 34, 1),
133              
134             'raw' => substr($field_008, 18, 17),
135             );
136 3 100       15 $Data::MARC::Field008::Book::STRICT = $self->{'ignore_data_errors'} ? 0 : 1;
137 3         39 my $material = Data::MARC::Field008::Book->new(%mat_params);
138 3         4395 %params = (
139             'material' => $material,
140             'material_type' => 'book',
141             );
142              
143             # Computer files.
144             } elsif ($self->{'leader'}->type eq 'm') {
145 2         54 my %mat_params = (
146             'target_audience' => substr($field_008, 22, 1),
147             'form_of_item' => substr($field_008, 23, 1),
148             'type_of_computer_file' => substr($field_008, 26, 1),
149             'government_publication' => substr($field_008, 28, 1),
150              
151             'raw' => substr($field_008, 18, 17),
152             );
153 2 50       12 $Data::MARC::Field008::ComputerFile::STRICT = $self->{'ignore_data_errors'} ? 0 : 1;
154 2         35 my $material = Data::MARC::Field008::ComputerFile->new(%mat_params);
155 2         844 %params = (
156             'material' => $material,
157             'material_type' => 'computer_file',
158             );
159              
160             # Maps.
161 14     14   230 } elsif (any { $self->{'leader'}->type eq $_ } qw(e f)) {
162 2         43 my %mat_params = (
163             'relief' => substr($field_008, 18, 4),
164             'projection' => substr($field_008, 22, 2),
165             'type_of_cartographic_material' => substr($field_008, 25, 1),
166             'government_publication' => substr($field_008, 28, 1),
167             'form_of_item' => substr($field_008, 29, 1),
168             'index' => substr($field_008, 31, 1),
169             'special_format_characteristics' => substr($field_008, 33, 2),
170              
171             'raw' => substr($field_008, 18, 17),
172             );
173 2 50       12 $Data::MARC::Field008::Map::STRICT = $self->{'ignore_data_errors'} ? 0 : 1;
174 2         24 my $material = Data::MARC::Field008::Map->new(%mat_params);
175 2         1009 %params = (
176             'material' => $material,
177             'material_type' => 'map',
178             );
179              
180             # Music.
181 18     18   155 } elsif (any { $self->{'leader'}->type eq $_ } qw(c d i j)) {
182 2         49 my %mat_params = (
183             'form_of_composition' => substr($field_008, 18, 2),
184             'format_of_music' => substr($field_008, 20, 1),
185             'music_parts' => substr($field_008, 21, 1),
186             'target_audience' => substr($field_008, 22, 1),
187             'form_of_item' => substr($field_008, 23, 1),
188             'accompanying_matter' => substr($field_008, 24, 6),
189             'literary_text_for_sound_recordings' => substr($field_008, 30, 2),
190             'transposition_and_arrangement' => substr($field_008, 33, 1),
191              
192             'raw' => substr($field_008, 18, 17),
193             );
194 2 50       12 $Data::MARC::Field008::Music::STRICT = $self->{'ignore_data_errors'} ? 0 : 1;
195 2         26 my $material = Data::MARC::Field008::Music->new(%mat_params);
196 2         2162 %params = (
197             'material' => $material,
198             'material_type' => 'music',
199             );
200              
201             # Continuing Resources
202             } elsif ($self->{'leader'}->type eq 'a'
203 6     6   73 && (any { $self->{'leader'}->bibliographic_level eq $_ } qw(b i s))) {
204              
205 2         55 my %mat_params = (
206             'frequency' => substr($field_008, 18, 1),
207             'regularity' => substr($field_008, 19, 1),
208             'type_of_continuing_resource' => substr($field_008, 21, 1),
209             'form_of_original_item' => substr($field_008, 22, 1),
210             'form_of_item' => substr($field_008, 23, 1),
211             'nature_of_entire_work' => substr($field_008, 24, 1),
212             'nature_of_content' => substr($field_008, 25, 3),
213             'government_publication' => substr($field_008, 28, 1),
214             'conference_publication' => substr($field_008, 29, 1),
215             'original_alphabet_or_script_of_title' => substr($field_008, 33, 1),
216             'entry_convention' => substr($field_008, 34, 1),
217              
218             'raw' => substr($field_008, 18, 17),
219             );
220 2 50       9 $Data::MARC::Field008::ContinuingResource::STRICT = $self->{'ignore_data_errors'} ? 0 : 1;
221 2         27 my $material = Data::MARC::Field008::ContinuingResource->new(%mat_params);
222 2         1912 %params = (
223             'material' => $material,
224             'material_type' => 'continuing_resource',
225             );
226              
227             # Visual Materials
228 4     4   56 } elsif (any { $self->{'leader'}->type eq $_ } qw(g k o r)) {
229 2         46 my %mat_params = (
230             'running_time_for_motion_pictures_and_videorecordings' => substr($field_008, 18, 3),
231             'target_audience' => substr($field_008, 22, 1),
232             'government_publication' => substr($field_008, 28, 1),
233             'form_of_item' => substr($field_008, 29, 1),
234             'type_of_visual_material' => substr($field_008, 33, 1),
235             'technique' => substr($field_008, 34, 1),
236              
237             'raw' => substr($field_008, 18, 17),
238             );
239 2 50       12 $Data::MARC::Field008::VisualMaterial::STRICT = $self->{'ignore_data_errors'} ? 0 : 1;
240 2         27 my $material = Data::MARC::Field008::VisualMaterial->new(%mat_params);
241 2         918 %params = (
242             'material' => $material,
243             'material_type' => 'visual_material',
244             );
245              
246             # Mixed Materials
247             } elsif ($self->{'leader'}->type eq 'p') {
248 0         0 my %mat_params = (
249             'form_of_item' => substr($field_008, 23, 1),
250              
251             'raw' => substr($field_008, 18, 17),
252             );
253 0 0       0 $Data::MARC::Field008::MixedMaterial::STRICT = $self->{'ignore_data_errors'} ? 0 : 1;
254 0         0 my $material = Data::MARC::Field008::MixedMaterial->new(%mat_params);
255 0         0 %params = (
256             'material' => $material,
257             'material_type' => 'mixed_material',
258             );
259              
260             } else {
261 0         0 err "Unsupported 008 type.";
262             }
263              
264 13         247 return %params;
265             }
266              
267             sub _serialize_different {
268 6     6   212 my ($self, $material) = @_;
269              
270 6         12 my $ret;
271 6 100       88 if ($material->isa('Data::MARC::Field008::Book')) {
    100          
    100          
    100          
    50          
    100          
    50          
272 1         5 $ret = $material->illustrations.
273             $material->target_audience.
274             $material->form_of_item.
275             $material->nature_of_content.
276             $material->government_publication.
277             $material->conference_publication.
278             $material->festschrift.
279             $material->index.
280             ' '.
281             $material->literary_form.
282             $material->biography;
283              
284             } elsif ($material->isa('Data::MARC::Field008::ComputerFile')) {
285 1         5 $ret = (' ' x 4).
286             $material->target_audience.
287             $material->form_of_item.
288             (' ' x 2).
289             $material->type_of_computer_file.
290             ' '.
291             $material->government_publication.
292             (' ' x 6);
293             } elsif ($material->isa('Data::MARC::Field008::ContinuingResource')) {
294 1         6 $ret = $material->frequency.
295             $material->regularity.
296             ' '.
297             $material->type_of_continuing_resource.
298             $material->form_of_original_item.
299             $material->form_of_item.
300             $material->nature_of_entire_work.
301             $material->nature_of_content.
302             $material->government_publication.
303             $material->conference_publication.
304             (' ' x 3).
305             $material->original_alphabet_or_script_of_title.
306             $material->entry_convention;
307             } elsif ($material->isa('Data::MARC::Field008::Map')) {
308 1         6 $ret = $material->relief.
309             $material->projection.
310             ' '.
311             $material->type_of_cartographic_material.
312             (' ' x 2).
313             $material->government_publication.
314             $material->form_of_item.
315             ' '.
316             $material->index.
317             ' '.
318             $material->special_format_characteristics;
319             } elsif ($material->isa('Data::MARC::Field008::MixedMaterial')) {
320 0         0 $ret = (' ' x 5).
321             $material->form_of_item.
322             (' ' x 10);
323             } elsif ($material->isa('Data::MARC::Field008::Music')) {
324 1         5 $ret = $material->form_of_composition.
325             $material->format_of_music.
326             $material->music_parts.
327             $material->target_audience.
328             $material->form_of_item.
329             $material->accompanying_matter.
330             $material->literary_text_for_sound_recordings.
331             ' '.
332             $material->transposition_and_arrangement.
333             ' ';
334             } elsif ($material->isa('Data::MARC::Field008::VisualMaterial')) {
335 1         6 $ret = $material->running_time_for_motion_pictures_and_videorecordings.
336             ' '.
337             $material->target_audience.
338             (' ' x 5).
339             $material->government_publication.
340             $material->form_of_item.
341             (' ' x 3).
342             $material->type_of_visual_material.
343             $material->technique;
344             }
345              
346 6         349 return $ret;
347             }
348              
349             1;
350              
351             __END__
352              
353             =pod
354              
355             =encoding utf8
356              
357             =head1 NAME
358              
359             MARC::Field008 - Class for parsing and serialization of MARC field 008.
360              
361             =head1 SYNOPSIS
362              
363             use MARC::Field008;
364              
365             my $obj = MARC::Field008->new(%params);
366             my $data_obj = $cnf->parse($field_008);
367             my $field_008 = $cnf->serialize($data_obj);
368              
369             =head1 METHODS
370              
371             =head2 C<new>
372              
373             my $obj = MARC::Field008->new(%params);
374              
375             Constructor.
376              
377             =over 8
378              
379             =item * C<ignore_data_errors>
380              
381             Flag for ignoring material object errors.
382              
383             It's required.
384              
385             Default value is 0.
386              
387             =item * C<leader>
388              
389             MARC leader in L<Data::MARC::Leader> instance.
390              
391             It's required for parse() method only.
392              
393             Default is undef.
394              
395             =item * C<verbose>
396              
397             Verbose mode.
398              
399             Default is 0.
400              
401             =back
402              
403             Returns instance of object.
404              
405             =head2 C<parse>
406              
407             my $data_obj = $cnf->parse($field_008);
408              
409             Parse MARC field 008 string to data object.
410              
411             Returns instance of L<Data::MARC::Field008>.
412              
413             =head2 C<serialize>
414              
415             my $field_008 = $cnf->serialize($data_obj);
416              
417             Serialize L<Data::MARC::Field008> object to string..
418              
419             Returns string.
420              
421             =head1 ERRORS
422              
423             new():
424             From Mo::utils::check_bool():
425             Parameter 'ignore_data_errors' must be a bool (0/1).
426             Value: %s
427             Parameter 'verbose' must be a bool (0/1).
428             Value: %s
429             From Mo::utils::check_isa():
430             Parameter 'leader' must be a 'Data::MARC::Leader' object.
431             Value: %s
432             Reference: %s
433             From Mo::utils::check_required():
434             Parameter 'ignore_data_errors' is required.
435             From Class::Utils::set_params():
436             Unknown parameter '%s'.
437              
438             parse():
439             Bad length of MARC 008 field.
440             Length: %s
441              
442             From Mo::utils::check_required():
443             Parameter 'leader' is required.
444              
445             Errors from L<Data::MARC::Field008>, see documentation.
446              
447             serialize():
448             Bad 'Data::MARC::Field008' instance to serialize.
449              
450             =head1 EXAMPLE1
451              
452             =for comment filename=parse_example.pl
453              
454             use strict;
455             use warnings;
456              
457             use MARC::Field008;
458             use MARC::Leader;
459             use Data::Printer;
460              
461             # Object.
462             my $leader = MARC::Leader->new->parse(' nam a22 4500');
463             my $obj = MARC::Field008->new(
464             'leader' => $leader,
465             );
466              
467             # Parse.
468             my $data = $obj->parse('830304s1982 xr a u0|0 | cze ');
469              
470             # Dump.
471             p $data;
472              
473             # Output:
474             # Data::MARC::Field008 {
475             # parents: Mo::Object
476             # public methods (13):
477             # BUILD
478             # Data::MARC::Field008::Utils:
479             # check_cataloging_source, check_date, check_modified_record, check_type_of_date
480             # Error::Pure:
481             # err
482             # Error::Pure::Utils:
483             # err_get
484             # Mo::utils:
485             # check_isa, check_length_fix, check_number, check_required, check_strings
486             # Readonly:
487             # Readonly
488             # private methods (0)
489             # internals: {
490             # cataloging_source " ",
491             # date_entered_on_file 830304,
492             # date1 1982,
493             # date2 " ",
494             # language "cze",
495             # material Data::MARC::Field008::Book,
496             # material_type "book",
497             # modified_record " ",
498             # place_of_publication "xr ",
499             # raw "830304s1982 xr a u0|0 | cze " (dualvar: 830304),
500             # type_of_date "s"
501             # }
502             # }
503              
504             =head1 EXAMPLE2
505              
506             =for comment filename=serialize_example.pl
507              
508             use strict;
509             use warnings;
510              
511             use MARC::Field008;
512             use MARC::Leader;
513             use Data::MARC::Field008;
514             use Data::MARC::Field008::Book;
515              
516             # Object.
517             my $leader = MARC::Leader->new->parse(' nam a22 4500');
518             my $obj = MARC::Field008->new(
519             'leader' => $leader,
520             );
521              
522             # Data.
523             my $material = Data::MARC::Field008::Book->new(
524             'biography' => ' ',
525             'conference_publication' => '0',
526             'festschrift' => '0',
527             'form_of_item' => 'r',
528             'government_publication' => ' ',
529             'illustrations' => ' ',
530             'index' => '0',
531             'literary_form' => '0',
532             'nature_of_content' => ' ',
533             'target_audience' => ' ',
534             );
535             my $data = Data::MARC::Field008->new(
536             'cataloging_source' => ' ',
537             'date_entered_on_file' => ' ',
538             'date1' => ' ',
539             'date2' => ' ',
540             'language' => 'cze',
541             'material' => $material,
542             'material_type' => 'book',
543             'modified_record' => ' ',
544             'place_of_publication' => ' ',
545             'type_of_date' => 's',
546             );
547              
548             # Serialize.
549             print "'".$obj->serialize($data)."'\n";
550              
551             # Output:
552             # ' s r 000 0 cze '
553              
554             =head1 DEPENDENCIES
555              
556             L<Class::Utils>,
557             L<Data::MARC::Field008>,
558             L<Data::MARC::Field008::Book>,
559             L<Data::MARC::Field008::ComputerFile>,
560             L<Data::MARC::Field008::ContinuingResource>,
561             L<Data::MARC::Field008::Map>,
562             L<Data::MARC::Field008::MixedMaterial>,
563             L<Data::MARC::Field008::Music>,
564             L<Data::MARC::Field008::VisualMaterial>,
565             L<Error::Pure>,
566             L<List::Util>,
567             L<Mo::utils>,
568             L<Scalar::Util>.
569              
570             =head1 SEE ALSO
571              
572             =over
573              
574             =item L<Data::MARC::Field008>
575              
576             Data object for MARC field 008.
577              
578             =back
579              
580             =head1 REPOSITORY
581              
582             L<https://github.com/michal-josef-spacek/MARC-Field008>
583              
584             =head1 AUTHOR
585              
586             Michal Josef Špaček L<mailto:skim@cpan.org>
587              
588             L<http://skim.cz>
589              
590             =head1 LICENSE AND COPYRIGHT
591              
592             © 2025 Michal Josef Špaček
593              
594             BSD 2-Clause License
595              
596             =head1 ACKNOWLEDGEMENTS
597              
598             Development of this software has been made possible by institutional support
599             for the long-term strategic development of the National Library of the Czech
600             Republic as a research organization provided by the Ministry of Culture of
601             the Czech Republic (DKRVO 2024–2028), Area 11: Linked Open Data.
602              
603             =head1 VERSION
604              
605             0.04
606              
607             =cut