b74760d00ac4d9d984d61d916a26c6e9a5b1fcbc
[webpac2] / lib / WebPAC / Lookup.pm
1 package WebPAC::Lookup;
2
3 use warnings;
4 use strict;
5
6 use WebPAC::Common;
7
8 use base qw/WebPAC::Common/;
9 use File::Slurp;
10 use Data::Dumper;
11
12 my $LOOKUP_REGEX = 'lookup{[^\{\}]+}';
13 my $LOOKUP_REGEX_SAVE = 'lookup{([^\{\}]+)}';
14
15 =head1 NAME
16
17 WebPAC::Lookup - simple normalisation plugin to produce lookup
18
19 =head1 VERSION
20
21 Version 0.01
22
23 =cut
24
25 our $VERSION = '0.01';
26
27 =head1 SYNOPSIS
28
29 This module will produce in-memory lookups for easy resolution of lookups
30 to different records in source files. This will enable you to resolve
31 relational data in source format.
32
33 It can also be use with C<WebPAC::Tree> to produce tree hierarchies.
34
35 Lookups are defined in C<conf/lookup/isis.pm>.
36
37 C<lookup> argument is an array of lookups to create. Each lookup must have C<key> and
38 C<val>. Optional parametar C<eval> is perl code to evaluate before storing
39 value in lookup.
40
41  @lookup = [
42   { 'key' => 'd:v900', 'val' => 'v250^a' },
43   { 'eval' => '"v901^a" eq "Podruèje"',
44     'key' => 'pa:v561^4:v562^4:v461^1',
45     'val' => 'v900' },
46  ];
47
48
49 =head1 FUNCTIONS
50
51 =head2 new
52
53 Create new lookup object.
54
55   my $lookup = new WebPAC::Lookup(
56         lookup_file => '/path/to/conf/lookup/lookup.pm',
57   );
58
59 =cut
60
61 sub new {
62         my $class = shift;
63         my $self = {@_};
64         bless($self, $class);
65
66         my $log = $self->_get_logger();
67
68         my $lookup_file = $self->{'lookup_file'} || $log->logconfess("need path to lookup file in lookup_file parametar");
69
70         my $lookup_code = read_file($lookup_file) || $log->logconfess("can't read lookup file $lookup_file: $!");
71
72         {
73                 no strict 'vars';
74                 do $lookup_file or $log->logdie("Failed to read configuration parameters '$lookup_file' $! $@");
75                 $self->{'lookup_def'} = \@lookup || $log->logdie("lookup config $lookup_file doesn't produce \@lookup array");
76         }
77
78         $log->logconfess("lookup config file isn't ARRAY", sub { Dumper( $self->{'lookup_def'} ) }) if ($self->{'lookup_def'} !~ /ARRAY/o);
79
80         $self ? return $self : return undef;
81 }
82
83 =head2 add
84
85 Create lookup from record using lookup definition.
86
87  $self->add($rec);
88
89 Returns true if this record produced lookup.
90
91 =cut
92
93 sub add($) {
94         my $self = shift;
95
96         my $log = $self->_get_logger();
97
98         my $rec = shift || $log->logconfess("need record to create lookup");
99         $log->logconfess("need HASH as first argument!") if ($rec !~ /HASH/o);
100         $log->logconfess("need HASH as first argument!") if ($self->{'lookup_def'} !~ /ARRAY/o);
101
102         my $n = 0;
103
104         foreach my $i (@{ $self->{'lookup_def'} }) {
105                 $log->logconfess("need key") unless defined($i->{'key'});
106                 $log->logconfess("need val") unless defined($i->{'val'});
107
108                 $n++;
109
110                 if (defined($i->{'eval'})) {
111                         # eval first, so we can skip fill_in for key and val
112                         my $eval = $self->fill_in($rec,$i->{'eval'}) || next;
113                         if ($self->_eval($eval)) {
114                                 my $key = $self->fill_in($rec,$i->{'key'}) || next;
115                                 my @val = $self->fill_in($rec,$i->{'val'}) || next;
116                                 $log->debug("stored $key = ",sub { join(" | ",@val) });
117                                 push @{$self->{'lookup'}->{$key}}, @val;
118                         }
119                 } else {
120                         my $key = $self->fill_in($rec,$i->{'key'}) || next;
121                         my @val = $self->fill_in($rec,$i->{'val'}) || next;
122                         $log->debug("stored $key = ",sub { join(" | ",@val) });
123                         push @{$self->{'lookup'}->{$key}}, @val;
124                 }
125         }
126
127         return $n;
128 }
129
130 =head2 lookup
131
132 Perform lookups on format supplied to it.
133
134  my $text = $lookup->lookup('[v900]');
135
136 Lookups can be nested (like C<[d:[a:[v900]]]>).
137
138 =cut
139
140 sub lookup {
141         my $self = shift;
142
143         my $log = $self->_get_logger();
144
145         my $tmp = shift || $log->logconfess("need format");
146
147         if ($tmp =~ /$LOOKUP_REGEX/o) {
148                 my @in = ( $tmp );
149
150                 $log->debug("lookup for: ",$tmp);
151
152                 my @out;
153                 while (my $f = shift @in) {
154                         if ($f =~ /$LOOKUP_REGEX_SAVE/o) {
155                                 my $k = $1;
156                                 if ($self->{'lookup'}->{$k}) {
157                                         foreach my $nv (@{$self->{'lookup'}->{$k}}) {
158                                                 my $tmp2 = $f;
159                                                 $tmp2 =~ s/lookup{$k}/$nv/g;
160                                                 push @in, $tmp2;
161                                         }
162                                 } else {
163                                         undef $f;
164                                 }
165                         } elsif ($f) {
166                                 push @out, $f;
167                         }
168                 }
169                 $log->logconfess("return is array and it's not expected!") unless wantarray;
170                 return @out;
171         } else {
172                 return $tmp;
173         }
174 }
175
176 =head1 AUTHOR
177
178 Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>
179
180 =head1 COPYRIGHT & LICENSE
181
182 Copyright 2005 Dobrica Pavlinusic, All Rights Reserved.
183
184 This program is free software; you can redistribute it and/or modify it
185 under the same terms as Perl itself.
186
187 =cut
188
189 1; # End of WebPAC::Lookup