/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 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 =head1 SYNOPSYS
21
22 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 =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 if ($self->{'lookup'}) {
108 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 =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 If no path to configuration file is given, dummy empty configuration
245 will be create.
246
247 =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