File Coverage

blib/lib/MARC/Schema.pm
Criterion Covered Total %
statement 77 78 98.7
branch 28 30 93.3
condition 10 12 83.3
subroutine 11 11 100.0
pod 2 3 66.6
total 128 134 95.5


line stmt bran cond sub pod time code
1             package MARC::Schema;
2              
3 5     5   313582 use strict;
  5         9  
  5         234  
4 5     5   34 use warnings;
  5         10  
  5         440  
5              
6             our $VERSION = '0.16';
7              
8 5     5   6900 use Cpanel::JSON::XS;
  5         36458  
  5         480  
9 5     5   2434 use File::Share ':all';
  5         181047  
  5         966  
10 5     5   2806 use File::Slurper 'read_binary';
  5         59188  
  5         359  
11 5     5   41 use Scalar::Util qw(reftype);
  5         7  
  5         4385  
12              
13             sub new {
14 6     6 0 173025 my ($class, $arg_ref) = @_;
15 6   100     55 my $self = $arg_ref // {};
16 6         21 bless $self, $class;
17 6         23 $self->_initialize();
18 6         42 return $self;
19             }
20              
21             sub _initialize {
22 6     6   40 my ($self) = shift;
23 6 100       38 if (!$self->{fields}) {
24 5         21 $self->{fields} = $self->_load_schema();
25             }
26 6         40 return;
27             }
28              
29             sub _load_schema {
30 5     5   9 my ($self) = shift;
31 5         7 my $json;
32 5 100       18 if ($self->{file}) {
33 1         6 $json = read_binary($self->{file});
34             }
35             else {
36 4         29 $self->{file} = dist_file('MARC-Schema', 'marc-schema.json');
37 4         912 $json = read_binary($self->{file});
38             }
39 5         326931 my $schema = decode_json($json);
40              
41 5         151167 return $schema->{fields};
42             }
43              
44             sub check {
45 31     31 1 94 my ($self, $record, %options) = @_;
46              
47 31 100       108 $record = $record->{record} if reftype $record eq 'HASH';
48              
49 31         88 $options{counter} = {};
50 31         62 return map {$self->check_field($_, %options)} @$record;
  558         1392  
51             }
52              
53             sub check_field {
54 558     558 1 1165 my ($self, $field, %options) = @_;
55              
56 558         1506 my $tag = $field->[0];
57              
58 558         1294 my $spec = $self->{fields}->{$tag};
59              
60 558 100       1218 if (!$spec) {
61 1 50       5 if (!$options{ignore_unknown_fields}) {
62 1         12 return ({tag => $tag, error => 'unknown field', type => 'field'});
63             }
64             else {
65 0         0 return ();
66             }
67             }
68              
69 557 100 66     2376 if ($options{counter} && !$spec->{repeatable}) {
70 324 100       2414 if ($options{counter}{$field->[0]}++) {
71             return (
72             {
73 1         9 tag => $tag,
74             error => 'field is not repeatable',
75             type => 'field',
76             }
77             );
78             }
79             }
80              
81 556         1871 my @errors;
82 556 100       1193 if ($spec->{subfields}) {
83 404         537 my %sfcounter;
84 404         1090 my (undef, undef, undef, @subfields) = @$field;
85 404         717 while (@subfields) {
86 649         2485 my ($code, undef) = splice @subfields, 0, 2;
87 649         1239 my $sfspec = $spec->{subfields}->{$code};
88              
89 649 100       1071 if ($sfspec) {
    50          
90 648 100 100     1396 if (!$sfspec->{repeatable} && $sfcounter{$code}++) {
91 1         14 push @errors,
92             {
93             tag => $tag,
94             error => 'subfield is not repeatable',
95             type => 'subfield',
96             value => $code,
97             };
98             }
99             }
100             elsif (!$options{ignore_unknown_subfields}) {
101 1         6 push @errors,
102             {
103             tag => $tag,
104             error => "unknown subfield",
105             type => 'subfield',
106             value => $code,
107             };
108             }
109             }
110             }
111              
112 556 100       3547 if ($spec->{indicator1}) {
113 221         665 my (undef, $code, @other) = @$field;
114 221   100     438 $code //= ' ';
115             my (@matches)
116 221         357 = grep {$code =~ /^[$_]/} keys %{$spec->{indicator1}->{codes}};
  845         9245  
  221         823  
117              
118 221 100       853 if (@matches > 0) {
119              
120             # everything is ok
121             }
122             else {
123 4         35 push @errors,
124             {
125             tag => $tag,
126             error => 'unknown first indicator',
127             type => 'indicator',
128             value => $code,
129             };
130             }
131             }
132              
133 556 100       1281 if ($spec->{indicator2}) {
134 158         432 my (undef, undef, $code, @other) = @$field;
135 158   50     312 $code //= ' ';
136             my (@matches)
137 158         196 = grep {$code =~ /^[$_]/} keys %{$spec->{indicator2}->{codes}};
  1028         8806  
  158         565  
138              
139 158 100       571 if (@matches > 0) {
140              
141             # everything is ok
142             }
143             else {
144 1         8 push @errors,
145             {
146             tag => $tag,
147             error => 'unknown second indicator',
148             type => 'indicator',
149             value => $code,
150             };
151             }
152             }
153              
154 556         1630 return @errors;
155             }
156              
157             1;
158             __END__