/[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 6 - (hide 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 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 4 #my $LOOKUP_REGEX = '\[[^\[\]]+\]';
21     #my $LOOKUP_REGEX_SAVE = '\[([^\[\]]+)\]';
22     my $LOOKUP_REGEX = 'lookup{[^\{\}]+}';
23     my $LOOKUP_REGEX_SAVE = 'lookup{([^\{\}]+)}';
24    
25 dpavlin 6 =head1 SYNOPSYS
26 dpavlin 4
27 dpavlin 6 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 dpavlin 4 =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 dpavlin 3 =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 dpavlin 6 If no path to configuration file is given, dummy empty configuration
251     will be create.
252    
253 dpavlin 3 =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