/[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 4 - (show annotations)
Sat Jul 16 12:37:18 2005 UTC (18 years, 9 months ago) by dpavlin
File size: 6253 byte(s)
more work on lookups, example configuration layout

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

  ViewVC Help
Powered by ViewVC 1.1.26