/[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 4 - (hide 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 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    
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 dpavlin 3 =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