File Coverage

blib/lib/MARC/MIR/Template.pm
Criterion Covered Total %
statement 89 97 91.7
branch 18 30 60.0
condition 3 4 75.0
subroutine 18 19 94.7
pod 0 8 0.0
total 128 158 81.0


line stmt bran cond sub pod time code
1             package MARC::MIR::Template;
2 1     1   36107 use Modern::Perl;
  1         2  
  1         6  
3 1     1   1124 use YAML ();
  1         12432  
  1         2073  
4 1     1 0 3 sub FOR_MIR { 0 }
5 10     10 0 67 sub FOR_DATA { 1 }
6 1     1 0 9 sub OPT { 2 }
7              
8             our $DEBUG = 0;
9             our $VERSION = '0.1';
10              
11             # ABSTRACT: templating system for marc records
12              
13             sub _data_control {
14 1     1   1 my $k = shift;
15             sub {
16 1     1   3 my ( $out, $content ) = @_;
17 1 50       5 ref $content and die "trying to load a ref in $k";
18 1         6 $$out{ $k } = $content;
19             }
20 1         10 }
21              
22             sub _data_data {
23 2     2   5 my ( $field, $tag ) = @_;
24             sub {
25 2     2   6 my ( $out, $content ) = @_;
26 2         3 push @{ $$out{$field}[0] }, [ $tag, $content ];
  2         165  
27             }
28 2         11 }
29              
30             sub _data_prepare_data {
31 1     1   3 my ( $template, $k, $v ) = @_;
32 1         9 while ( my ( $subk, $subv ) = each %$v ) {
33 2         6 $$template[FOR_DATA]{ $subv } = _data_data $k, $subk;
34             }
35             }
36              
37 6     6 0 35 sub by_tag { $$a[0] cmp $$b[0] }
38              
39             sub _data_mvalued {
40 3     3   5 my ( $k, $rspec ) = @_;
41 3         9 my %spec = map { $$rspec{$_} => $_ } keys %$rspec;
  6         23  
42             sub {
43 1     1   10 my ( $out, $v ) = @_;
44 1         4 push @{ $$out{$k} }
  2         3  
45             , map {
46 1         1 my $item = $_;
47             # TODO: optimize by not sorting every subfield ?
48             # (it's 2am, sorry)
49 4 50       12 [ map {
50 2         5 my $tag = $spec{$_} or die;
51             map {
52 4 100       7 if ( ref ) { map [ $tag, $_], @$_ }
  4         13  
  1         7  
53 3         18 else { [ $tag, $_ ] }
54             } $$item{$_}
55             } keys %$item ]
56             } @$v
57             }
58 3         33 }
59              
60             sub new {
61 1     1 0 31697 my ( $pkg, $spec, $options ) = @_;
62 1         3 my $template = [ $spec ];
63 1         10 while ( my ( $k, $v ) = each %$spec ) {
64 5         9 given ( ref $v ) {
65 5         22 when ('') { $$template[FOR_DATA]{ $v } = _data_control $k }
  1         4  
66 4         6 when ('HASH') { _data_prepare_data $template, $k, $v }
  1         5  
67 3         6 when ('ARRAY') {
68 3         8 my ( $mvalued, $fieldspec ) = @$v;
69 3         10 $$template[FOR_DATA]{ $mvalued } = _data_mvalued $k, $fieldspec;
70             }
71             }
72             };
73 1   50     10 $template->[OPT] = $options || {};
74 1         6 bless $template, __PACKAGE__;
75             }
76              
77             sub debug {
78 0     0 0 0 my $self = shift;
79 0         0 for ($self->[OPT]{debug}) {
80 0 0       0 @_ and $_ = shift;
81 0         0 return $_;
82             }
83             }
84              
85             sub data {
86 1     1 0 480 my ( $template, $source ) = @_;
87 1         3 my $out = {};
88 1         9 while ( my ( $k, $v ) = each %$source ) {
89 4 50       25 my $cb = $$template[FOR_DATA]{ $k } or next;
90 4         12 $cb->( $out, $v );
91             }
92 3         4 [ map {
93 1         9 my $field = $_;
94 3         5 my $data = $$out{$field};
95 3 100       9 if ( ref $data ) {
96 3         13 map {
97             # sorting keys clearly is a middleware! so the next line must
98             # be replaced by
99             # [ $field, $_ ]
100             # also remove the t/00*
101 2         4 [$field, [ sort by_tag @$_ ] ]
102             } @$data
103             }
104 1         3 else { [ $field, $data ] }
105             } sort keys %$out ]
106              
107             }
108              
109             sub _set_or_push_value {
110 8     8   13 my ( $target, $key, $v ) = @_;
111 8         17 for ( $$target{$key} ) {
112 8 100       17 if (defined) {
113             # so it happens to be multivalued
114 2 100       6 if (ref) { push @$_, $v } # and i knew it :)
  1         7  
115 1         4 else { $_ = [$_, $v] } # gee!
116             }
117             # the first time: just store $v
118 6         24 else { $_ = $v }
119             }
120             }
121              
122             sub _mir_hash {
123 3     3   7 my ( $data, $spec, $subfields ) = @_;
124 3         4 for my $s ( @$subfields ) {
125 8         18 my ( $tag, $v ) = @$s;
126 8         11 my $key = $$spec{ $tag };
127 8 50       17 if ( defined $key ) { _set_or_push_value $data, $key, $v }
  8         13  
128 0 0       0 else { $DEBUG && warn "can't manage $tag" }
129             }
130             }
131              
132             sub mir {
133 1     1 0 3392 my ( $template, $fields ) = @_;
134 1         7 my $tmpl = $$template[FOR_MIR];
135 1         3 my %data;
136 1         3 for (@$fields) {
137 4         453 my ($tag,$v,$ind) = @$_;
138 4 50       43 my $spec = $$tmpl{ $tag } or do {
139 0 0       0 say STDERR "unsuported,$tag" if $template->debug;
140 0         0 next;
141             };
142 4 100       12 if ( my $ref = ref $spec ) {
143 3 100       13 if ( $ref eq 'HASH' ) { _mir_hash \%data, $spec, $v }
  1 50       4  
144             elsif ( $ref eq 'ARRAY' ) {
145 2   100     3 push @{ $data{ $$spec[0] } ||= [] }
  2         15  
146             , my $entry = {};
147 2         7 _mir_hash $entry, $$spec[1], $v
148             }
149 0         0 else { die "don't know how to manage $ref" }
150             }
151 1         4 else { $data{$spec} = $v }
152             }
153 1         6 \%data;
154             }
155              
156             1;