/[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 6 - (show annotations)
Sat Jul 16 14:44:38 2005 UTC (18 years, 9 months ago) by dpavlin
File size: 6580 byte(s)
added WebPAC::Input::ISIS

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

  ViewVC Help
Powered by ViewVC 1.1.26