/[webpac2]/trunk/lib/WebPAC/Common.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/lib/WebPAC/Common.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Sat Jul 16 16:00:19 2005 UTC (18 years, 9 months ago) by dpavlin
File size: 6358 byte(s)
lookups cleanup

1 dpavlin 3 package WebPAC::Common;
2    
3     use warnings;
4     use strict;
5    
6     use Log::Log4perl qw(get_logger :levels);
7    
8     =head1 NAME
9    
10     WebPAC::Common - internal methods called from other WebPAC modules
11    
12     =head1 VERSION
13    
14     Version 0.01
15    
16     =cut
17    
18     our $VERSION = '0.01';
19    
20 dpavlin 6 =head1 SYNOPSYS
21 dpavlin 4
22 dpavlin 6 This module defines common functions, and is used as base for other, more
23     specific modules.
24    
25     my $webpac = new WebPAC::Common(
26     filter => {
27     'filter_name_1' => sub {
28     # filter code
29     return length($_);
30     }, ...
31     },
32     }
33    
34 dpavlin 4 =head1 FUNCTIONS
35    
36     =head2 fill_in
37    
38     Workhourse of all: takes record from in-memory structure of database and
39     strings with placeholders and returns string or array of with substituted
40     values from record.
41    
42     my $text = $webpac->fill_in($rec,'v250^a');
43    
44     Optional argument is ordinal number for repeatable fields. By default,
45     it's assume to be first repeatable field (fields are perl array, so first
46     element is 0).
47     Following example will read second value from repeatable field.
48    
49     my $text = $webpac->fill_in($rec,'Title: v250^a',1);
50    
51     This function B<does not> perform parsing of format to inteligenty skip
52     delimiters before fields which aren't used.
53    
54     This method will automatically decode UTF-8 string to local code page
55     if needed.
56    
57     =cut
58    
59     sub fill_in {
60     my $self = shift;
61    
62     my $log = $self->_get_logger();
63    
64     my $rec = shift || $log->logconfess("need data record");
65     my $format = shift || $log->logconfess("need format to parse");
66     # iteration (for repeatable fields)
67     my $i = shift || 0;
68    
69     $log->logdie("infitite loop in format $format") if ($i > ($self->{'max_mfn'} || 9999));
70    
71     # FIXME remove for speedup?
72     $log->logconfess("need HASH as first argument!") if ($rec !~ /HASH/o);
73    
74     if (utf8::is_utf8($format)) {
75     $format = $self->_x($format);
76     }
77    
78     my $found = 0;
79    
80     my $eval_code;
81     # remove eval{...} from beginning
82     $eval_code = $1 if ($format =~ s/^eval{([^}]+)}//s);
83    
84     my $filter_name;
85     # remove filter{...} from beginning
86     $filter_name = $1 if ($format =~ s/^filter{([^}]+)}//s);
87    
88     # do actual replacement of placeholders
89     # repeatable fields
90     $format =~ s/v(\d+)(?:\^(\w))?/$self->get_data(\$rec,$1,$2,$i,\$found)/ges;
91     # non-repeatable fields
92     $format =~ s/s(\d+)(?:\^(\w))?/$self->get_data(\$rec,$1,$2,0,\$found)/ges;
93    
94     if ($found) {
95     $log->debug("format: $format");
96     if ($eval_code) {
97     my $eval = $self->fill_in($rec,$eval_code,$i);
98     return if (! $self->_eval($eval));
99     }
100     if ($filter_name && $self->{'filter'}->{$filter_name}) {
101     $log->debug("filter '$filter_name' for $format");
102     $format = $self->{'filter'}->{$filter_name}->($format);
103     return unless(defined($format));
104     $log->debug("filter result: $format");
105     }
106     # do we have lookups?
107 dpavlin 7 if ($self->{'lookup'}) {
108 dpavlin 4 return $self->lookup($format);
109     } else {
110     return $format;
111     }
112     } else {
113     return;
114     }
115     }
116    
117    
118     =head2 get_data
119    
120     Returns value from record.
121    
122     my $text = $self->get_data(\$rec,$f,$sf,$i,\$found);
123    
124     Arguments are:
125     record reference C<$rec>,
126     field C<$f>,
127     optional subfiled C<$sf>,
128     index for repeatable values C<$i>.
129    
130     Optinal variable C<$found> will be incremeted if there
131     is field.
132    
133     Returns value or empty string.
134    
135     =cut
136    
137     sub get_data {
138     my $self = shift;
139    
140     my ($rec,$f,$sf,$i,$found) = @_;
141    
142     if ($$rec->{$f}) {
143     return '' if (! $$rec->{$f}->[$i]);
144     no strict 'refs';
145     if ($sf && $$rec->{$f}->[$i]->{$sf}) {
146     $$found++ if (defined($$found));
147     return $$rec->{$f}->[$i]->{$sf};
148     } elsif ($$rec->{$f}->[$i]) {
149     $$found++ if (defined($$found));
150     # it still might have subfield, just
151     # not specified, so we'll dump all
152     if ($$rec->{$f}->[$i] =~ /HASH/o) {
153     my $out;
154     foreach my $k (keys %{$$rec->{$f}->[$i]}) {
155     $out .= $$rec->{$f}->[$i]->{$k}." ";
156     }
157     return $out;
158     } else {
159     return $$rec->{$f}->[$i];
160     }
161     }
162     } else {
163     return '';
164     }
165     }
166    
167    
168 dpavlin 3 =head1 INTERNAL METHODS
169    
170     Here is a quick list of internal methods, mostly useful to turn debugging
171     on them (see L<LOGGING> below for explanation).
172    
173     =cut
174    
175     =head2 _eval
176    
177     Internal function to eval code without C<strict 'subs'>.
178    
179     =cut
180    
181     sub _eval {
182     my $self = shift;
183    
184     my $code = shift || return;
185    
186     my $log = $self->_get_logger();
187    
188     no strict 'subs';
189     my $ret = eval $code;
190     if ($@) {
191     $log->error("problem with eval code [$code]: $@");
192     }
193    
194     $log->debug("eval: ",$code," [",$ret,"]");
195    
196     return $ret || undef;
197     }
198    
199     =head2 _sort_by_order
200    
201     Sort xml tags data structure accoding to C<order=""> attribute.
202    
203     =cut
204    
205     sub _sort_by_order {
206     my $self = shift;
207    
208     my $va = $self->{'import_xml'}->{'indexer'}->{$a}->{'order'} ||
209     $self->{'import_xml'}->{'indexer'}->{$a};
210     my $vb = $self->{'import_xml'}->{'indexer'}->{$b}->{'order'} ||
211     $self->{'import_xml'}->{'indexer'}->{$b};
212    
213     return $va <=> $vb;
214     }
215    
216     =head2 _x
217    
218     Convert string from UTF-8 to code page defined in C<import_xml>.
219    
220     my $text = $webpac->_x('utf8 text');
221    
222     Default application code page is C<ISO-8859-2>. You will probably want to
223     change that when creating new instance of object based on this one.
224    
225     =cut
226    
227     sub _x {
228     my $self = shift;
229     my $utf8 = shift || return;
230    
231     # create UTF-8 convertor for import_xml files
232     $self->{'utf2cp'} ||= Text::Iconv->new('UTF-8' ,$self->{'code_page'} || 'ISO-8859-2');
233    
234     return $self->{'utf2cp'}->convert($utf8) ||
235     $self->_get_logger()->logwarn("can't convert '$utf8'");
236     }
237    
238     =head2 _init_logger
239    
240     This function will init C<Log::Log4perl> using provided configuration file.
241    
242     $webpac->_init_logger('/path/to/log.conf');
243    
244 dpavlin 6 If no path to configuration file is given, dummy empty configuration
245     will be create.
246    
247 dpavlin 3 =cut
248    
249     sub _init_logger {
250     my $self = shift;
251     my $file = shift;
252     if ($file) {
253     Log::Log4perl->init($file);
254     } else {
255     my $conf = q( );
256     Log::Log4perl->init( \$conf );
257     }
258     }
259    
260    
261     =head2 _get_logger
262    
263     Get C<Log::Log4perl> object with a twist: domains are defined for each
264     method
265    
266     my $log = $webpac->_get_logger();
267    
268     =cut
269    
270     sub _get_logger {
271     my $self = shift;
272    
273     $self->{'_logger_ok'} ||= $self->_init_logger;
274    
275     my $name = (caller(1))[3] || caller;
276     return get_logger($name);
277     }
278    
279    
280     =head1 LOGGING
281    
282     Logging in WebPAC is performed by L<Log::Log4perl> with config file
283     C<log.conf>.
284    
285     Methods defined above have different levels of logging, so
286     it's descriptions will be useful to turn (mostry B<debug> logging) on
287     or off to see why WabPAC isn't perforing as you expect it (it might even
288     be a bug!).
289    
290     B<This is different from normal Log4perl behaviour>. To repeat, you can
291     also use method names, and not only classes (which are just few)
292     to filter logging.
293    
294    

  ViewVC Help
Powered by ViewVC 1.1.26