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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3 by dpavlin, Sat Jul 16 11:07:38 2005 UTC revision 10 by dpavlin, Sat Jul 16 20:35:30 2005 UTC
# Line 17  Version 0.01 Line 17  Version 0.01
17    
18  our $VERSION = '0.01';  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    =head2 progress_bar
169    
170    Draw progress bar on STDERR.
171    
172     $webpac->progress_bar($current, $max);
173    
174    =cut
175    
176    sub progress_bar {
177            my $self = shift;
178    
179            my ($curr,$max) = @_;
180    
181            my $log = $self->_get_logger();
182    
183            $log->logconfess("no current value!") if (! $curr);
184            $log->logconfess("no maximum value!") if (! $max);
185    
186            if ($curr > $max) {
187                    $max = $curr;
188                    $log->debug("overflow to $curr");
189            }
190    
191            $self->{'last_pcnt'} ||= 1;
192            $self->{'start_t'} ||= time();
193    
194            my $p = int($curr * 100 / $max) || 1;
195    
196            # reset on re-run
197            if ($p < $self->{'last_pcnt'}) {
198                    $self->{'last_pcnt'} = $p;
199                    $self->{'start_t'} = time();
200            }
201    
202            if ($p != $self->{'last_pcnt'}) {
203    
204                    my $t = time();
205                    my $rate = ($curr / ($t - $self->{'start_t'} || 1));
206                    my $eta = ($max-$curr) / ($rate || 1);
207                    printf STDERR ("%5d [%-38s] %-5d %0.1f/s %s\r",$curr,"=" x ($p/3)."$p%>", $max, $rate, $self->fmt_time($eta));
208                    $self->{'last_pcnt'} = $p;
209                    $self->{'last_curr'} = $curr;
210            }
211            print STDERR "\n" if ($p == 100);
212    }
213    
214    =head2 fmt_time
215    
216    Format time (in seconds) for display.
217    
218     print $webpac->fmt_time(time());
219    
220    This method is called by L<progress_bar> to display remaining time.
221    
222    =cut
223    
224    sub fmt_time {
225            my $self = shift;
226    
227            my $t = shift || 0;
228            my $out = "";
229    
230            my ($ss,$mm,$hh) = gmtime($t);
231            $out .= "${hh}h" if ($hh);
232            $out .= sprintf("%02d:%02d", $mm,$ss);
233            $out .= "  " if ($hh == 0);
234            return $out;
235    }
236    
237    #
238    #
239    #
240    
241  =head1 INTERNAL METHODS  =head1 INTERNAL METHODS
242    
243  Here is a quick list of internal methods, mostly useful to turn debugging  Here is a quick list of internal methods, mostly useful to turn debugging
# Line 93  This function will init C<Log::Log4perl> Line 314  This function will init C<Log::Log4perl>
314    
315    $webpac->_init_logger('/path/to/log.conf');    $webpac->_init_logger('/path/to/log.conf');
316    
317    If no path to configuration file is given, dummy empty configuration
318    will be created. If any mode which inherits from this one is called
319    with C<debug> flag, it will turn logging to debug level.
320    
321  =cut  =cut
322    
323  sub _init_logger {  sub _init_logger {
# Line 102  sub _init_logger { Line 327  sub _init_logger {
327                  Log::Log4perl->init($file);                  Log::Log4perl->init($file);
328          } else {          } else {
329                  my $conf = q( );                  my $conf = q( );
330                    if ($self->{'debug'}) {
331                            $conf = << '_log4perl_';
332    
333    log4perl.rootLogger=INFO, SCREEN
334    
335    log4perl.logger.WebPAC.=DEBUG
336    
337    log4perl.appender.SCREEN=Log::Log4perl::Appender::Screen
338    log4perl.appender.SCREEN.layout=PatternLayout
339    log4perl.appender.SCREEN.layout.ConversionPattern=%d %p> %F{1}:%L %M - %m%n
340    
341    _log4perl_
342                    }
343                  Log::Log4perl->init( \$conf );                  Log::Log4perl->init( \$conf );
344          }          }
345  }  }

Legend:
Removed from v.3  
changed lines
  Added in v.10

  ViewVC Help
Powered by ViewVC 1.1.26