File Coverage

blib/lib/PICA/Path.pm
Criterion Covered Total %
statement 79 95 83.1
branch 47 58 81.0
condition 15 29 51.7
subroutine 8 11 72.7
pod 4 6 66.6
total 153 199 76.8


line stmt bran cond sub pod time code
1             package PICA::Path;
2 6     6   24797 use strict;
  6         19  
  6         187  
3 6     6   33 use warnings;
  6         13  
  6         301  
4              
5             our $VERSION = '0.32';
6              
7 6     6   35 use Carp qw(confess);
  6         13  
  6         343  
8 6     6   53 use Scalar::Util qw(reftype);
  6         22  
  6         416  
9              
10 6     6   5570 use overload '""' => \&stringify;
  6         5269  
  6         55  
11              
12             sub new {
13 16     16 1 7289 my ($class, $path) = @_;
14              
15 16 100       623 confess "invalid pica path" if $path !~ /
16             ([012*.][0-9*.][0-9*.][A-Z@*.]) # tag
17             (\[([0-9*.]{2})\])? # occurence
18             (\$?([_A-Za-z0-9]+))? # subfields
19             (\/(\d+)?(-(\d+)?)?)? # position
20             /x;
21              
22 13         38 my $field = $1;
23 13         24 my $occurrence = $3;
24 13 100       39 my $subfield = defined $5 ? "[$5]" : "[_A-Za-z0-9]";
25              
26 13         22 my @position;
27 13 100       33 if (defined $6) { # from, to
28 8         26 my ($from, $dash, $to, $length) = ($7, $8, $9, 0);
29              
30 8 100       18 if ($dash) {
31 6 100 66     149 confess "invalid pica path" unless defined($from // $to); # /-
32             }
33              
34 7 100       15 if (defined $to) {
35 2 50 33     7 if (!$from and $dash) { # /-X
36 0         0 $from = 0;
37             }
38 2         7 $length = $to - $from + 1;
39             } else {
40 5 100       14 if ($8) {
41 3         16 $length = undef;
42             } else {
43 2         5 $length = 1;
44             }
45             }
46              
47 7 50 66     28 if (!defined $length or $length >= 1) {
48 7 100 100     26 unless (!$from and !defined $length) { # /0-
49 6         15 @position = ($from, $length);
50             }
51             }
52             }
53              
54 12         38 $field =~ s/\*/./g;
55 12         157 $field = qr{$field};
56            
57 12 100       36 if (defined $occurrence) {
58 1         11 $occurrence =~ s/\*/./g;
59 1         9 $occurrence = qr{$occurrence};
60             }
61              
62 12         79 $subfield = qr{$subfield};
63              
64 12         57 bless [ $field, $occurrence, $subfield, @position ], $class;
65             }
66              
67             sub match_field {
68 0     0 1 0 my ($self, $field) = @_;
69              
70 0 0 0     0 if ( $field->[0] =~ $self->[0] &&
      0        
71             (!$self->[1] || (defined $field->[1] && $field->[1] =~ $self->[1])) ) {
72 0         0 return $field;
73             }
74              
75             return
76 0         0 }
77              
78             sub match_subfields {
79 3     3 1 8 my ($self, $field) = @_;
80              
81 3         6 my $subfield_regex = $self->[2];
82 3         5 my $from = $self->[3];
83 3         6 my $length = $self->[4];
84              
85 3         4 my @values;
86              
87 3         12 for (my $i = 2; $i < @$field; $i += 2) {
88 3 50       14 if ($field->[$i] =~ $subfield_regex) {
89 3         8 my $value = $field->[$i + 1];
90 3 100       8 if (defined $from) {
91 2 100       7 $value = $length ? substr($value, $from, $length) :
92             substr($value, $from);
93 2 50 50     9 next if '' eq ($value // '');
94             }
95 3         10 push @values, $value;
96             }
97             }
98              
99 3         13 return @values;
100             }
101              
102             sub record_fields {
103 0     0 0 0 my ($self, $record) = @_;
104              
105 0 0       0 $record = $record->{record} if reftype $record eq 'HASH';
106 0         0 return [ grep { $self->match_field($_) } @$record ];
  0         0  
107             }
108              
109             sub record_subfields {
110 0     0 0 0 my ($self, $record) = @_;
111              
112 0 0       0 $record = $record->{record} if reftype $record eq 'HASH';
113              
114 0         0 my @values;
115              
116 0         0 foreach my $field (grep { $self->match_field($_) } @$record) {
  0         0  
117 0         0 push @values, $self->match_subfields($field);
118             }
119              
120 0         0 return @values;
121             }
122              
123             sub stringify {
124 9     9 1 9565 my ($self, $short) = @_;
125              
126             my ($field, $occurrence, $subfields) = map {
127 9 100       25 defined $_ ? do {
  27         52  
128 19         112 s/^\(\?[^:]*:(.*)\)$/$1/;
129 19         55 s/\./*/g;
130 19         63 $_ } : undef
131             } ($self->[0], $self->[1], $self->[2]);
132              
133 9         20 my $str = $field;
134              
135 9 100       26 if (defined $occurrence) {
136 1         2 $str .= "[$occurrence]";
137             }
138              
139 9 100 66     51 if (defined $subfields and $subfields ne '[_A-Za-z0-9]') {
140 4         28 $subfields =~ s/\[|\]//g;
141 4 100 66     19 unless( $short and $subfields !~ /^\$/ ) {
142 3         6 $str .= '$';
143             }
144 4         7 $str .= $subfields;
145             }
146              
147 9         22 my ($from, $length, $pos) = ($self->[3], $self->[4]);
148 9 100       21 if (defined $from) {
149 4 100       12 if ($from) {
150 3         6 $pos = $from;
151             }
152 4 100 66     22 if (!defined $length) {
    100          
    100          
153 1 50       4 if ($from) {
154 1         2 $pos = "$from-";
155             }
156             } elsif ($length > 1) {
157 1         3 $pos .= '-' . ($from + $length - 1);
158             } elsif ($length == 1 && !$from) {
159 1         3 $pos = 0;
160             }
161             }
162              
163 9 100       23 $str .= "/$pos" if defined $pos;
164              
165 9         31 $str;
166             }
167              
168             1;
169             __END__