File Coverage

blib/lib/Text/MetaText/Factory.pm
Criterion Covered Total %
statement 76 89 85.3
branch 22 32 68.7
condition 7 22 31.8
subroutine 10 12 83.3
pod 0 4 0.0
total 115 159 72.3


line stmt bran cond sub pod time code
1             #============================================================================
2             #
3             # Text::MetaText::Factory
4             #
5             # DESCRIPTION
6             # Objects of the the MetaText Factory class (Text::MetaText::Factory)
7             # are used to instantiate objects of the MetaText Directive class
8             # (Text::MetaText::Directive) or sub-classes. The default factory
9             # is responsible for parsing the contents of a directive string and
10             # creating from that a specifically configured Directive object. The
11             # MetaText object class (Text::MetaText) uses a factory instance (which
12             # may be user-supplied at run-time) in constructing a parsed ("compiled")
13             # representation of a document. The Factory and Directive classes can
14             # easily be sub-classed to derive more specific objects that can then be
15             # used in the standard MetaText framework.
16             #
17             # AUTHOR
18             # Andy Wardley
19             #
20             # COPYRIGHT
21             # Copyright (C) 1996-1998 Andy Wardley. All Rights Reserved.
22             #
23             # This module is free software; you can redistribute it and/or
24             # modify it under the terms of the Perl Artistic Licence.
25             #
26             #----------------------------------------------------------------------------
27             #
28             # $Id: Factory.pm,v 0.2 1998/09/01 12:59:45 abw Exp abw $
29             #
30             #============================================================================
31            
32             package Text::MetaText::Factory;
33              
34 9     9   82 use strict;
  9         17  
  9         382  
35 9     9   45 use vars qw( $VERSION $DIRECTIVE $ERROR $CONTROL );
  9         87  
  9         583  
36              
37 9     9   7277 use Text::MetaText::Directive;
  9         23  
  9         1796  
38              
39             require 5.004;
40              
41              
42              
43             #========================================================================
44             # ----- CONFIGURATION -----
45             #========================================================================
46            
47             $VERSION = sprintf("%d.%02d", q$Revision: 0.2 $ =~ /(\d+)\.(\d+)/);
48             $DIRECTIVE = 'Text::MetaText::Directive'; # default directive type
49              
50             # define the control parameters valid for each directive type
51             $CONTROL = {
52             DEFINE => { map { $_ => 1 } qw( IF UNLESS ) },
53             SUBST => { map { $_ => 1 } qw( IF UNLESS FORMAT FILTER ) },
54             INCLUDE => { map { $_ => 1 } qw( IF UNLESS FORMAT FILTER ) },
55             BLOCK => { map { $_ => 1 } qw( PRINT TRIM ) },
56             };
57              
58              
59              
60             #========================================================================
61             # ----- PUBLIC METHODS -----
62             #========================================================================
63            
64             #========================================================================
65             #
66             # new(\%cfg)
67             #
68             # Object constructor. A reference to a hash array of configuration
69             # options may be passed which is then delegated to _configure() to
70             # process.
71             #
72             # Returns a reference to a newly created Text::MetaText::Factory object.
73             #
74             #========================================================================
75              
76             sub new {
77 14     14 0 69 my $self = shift;
78 14   33     84 my $class = ref($self) || $self;
79 14         35 my $cfg = shift;
80              
81              
82             # make me an object
83 14         50 $self = bless { }, $class;
84              
85             # the configuration hash, $cfg, may contain an entry $cfg->{ DIRECTIVE }
86             # which names the directive class which the factory is expected to
87             # instantiate. If this is undefined, the $DIRECTIVE variable in the
88             # class package (which may be a sub-class) and in the current (base-
89             # class) package are checked, in that order, and used if defined.
90             {
91             # turn off strict reference checking for this block so that we can
92             # construct a variable name in the calling package without warning
93 9     9   136 no strict 'refs';
  9         25  
  9         8770  
  14         29  
94              
95             $self->{ DIRECTIVE } = # specified in...
96             $cfg->{ DIRECTIVE } # ...the $cfg hashref
97 14   33     89 || ${ "$class\::DIRECTIVE" } # ...the calling package, $class
98             || $DIRECTIVE; # ...the current (base) package
99             }
100              
101             # we call _configure() which in this base class does very little but
102             # acts as a convenient hook for sub-classes. The return value of
103             # _configure() indicates if the constructor should return a $self
104             # reference to indicate success (any true value) or undef to indicate
105             # failure (any false value)
106 14 50       1282 $self->_configure($cfg)
107             ? $self
108             : undef;
109             }
110              
111              
112              
113             #========================================================================
114             #
115             # create_directive($text)
116             #
117             # The public method create_directive() is called by Text::MetaText when
118             # is has identified a text string enclosed in the MetaText magic marker
119             # tokens (default: '%%' ... '%%') which it needs converting to a
120             # Directive object. The text string to be converted is passed in the
121             # only parameter, $text.
122             #
123             # Returns a reference to a newly created Text::MetaText::Directive
124             # object, or derivative. On error, undef is returned and an appropriate
125             # error message will be stored internally, available through the public
126             # error() method.
127             #
128             #========================================================================
129              
130             sub create_directive {
131 230     230 0 294 my $self = shift;
132 230         386 my $text = shift;
133              
134 230         419 my $directive = { };
135 230         285 my ($type, $ident);
136 0         0 my ($tokens, $token);
137 0         0 my ($name, $value);
138 0         0 my ($ucname, $uctype);
139              
140              
141             # save the original parameter text string
142 230         546 $directive->{ PARAMSTR } = $text;
143              
144             # split the text string into lexical tokens
145 230         517 $tokens = $self->_split_text($text);
146              
147             # identify the type (first token) in the parameter string
148 230 50 33     1275 unless (defined($type = shift @$tokens) && ! ref($type)) {
149 0         0 $self->_error("Missing directive keyword");
150 0         0 return undef;
151             }
152              
153             # keep an UPPER CASE $type to avoid using case insensitive regexen
154 230         426 $uctype = uc $type;
155              
156              
157             # parse the directive parameters according to the directive type
158             TYPE: {
159            
160             # END(BLOCK|IF)? directive ignores everything
161 230 100       250 $uctype =~ /^END(BLOCK|IF)?$/o && do {
  230         604  
162 19         37 $ident = '';
163 19         32 last TYPE;
164             };
165              
166             # DEFINE directive has optional identifier and params
167 211 100       818 $uctype =~ /^DEFINE$/o && do {
168              
169             # identifier must be a simple variable
170 37 50 33     355 $ident = (@$tokens && !ref($tokens->[0]))
171             ? shift(@$tokens)
172             : '';
173 37         71 last TYPE;
174             };
175            
176             # INCLUDE/SUBST/BLOCK have mandatory identifier and
177             # optional params
178 174 100       614 $uctype =~ /^(INCLUDE|SUBST|BLOCK)$/o && do {
179              
180             # check there is a simple text identifier
181 97 50 33     443 unless (@$tokens && !ref($tokens->[0])) {
182 0         0 $self->_error("No identifier in $type directive");
183 0         0 return undef;
184             };
185 97         147 $ident = shift(@$tokens);
186 97         166 last TYPE;
187             };
188              
189             # if the type isn't recognised, we assume it's a basic SUBST
190 77         94 $ident = $type;
191 77         122 $type = $uctype = 'SUBST';
192             }
193              
194             # save identifier (as is) and keyword (in upper case)
195 230         846 $directive->{ TYPE } = $uctype;
196 230         403 $directive->{ IDENTIFIER } = $ident;
197              
198             # initialise parameter hash
199 230         435 $directive->{ PARAMS } = {};
200              
201             # examine, process and store the additional directive parameters
202 230         448 foreach $token (@$tokens) {
203            
204             # extract/create a name, value pair from token (array or scalar)
205 178 100       704 ($name, $value) = ref($token) eq 'ARRAY'
206             ? @$token
207             : ($token, 0);
208              
209             # un-escape any escaped characters in the value
210 178         308 $value =~ s/\\(.)/$1/go;
211              
212             # keep an UPPER CASE copy of the name
213 178         240 $ucname = uc $name;
214              
215             # is this a "control" parameter?
216 178 100       500 if (defined $CONTROL->{ $uctype }->{ $ucname }) {
217             # control params are forced to upper case
218 58         171 $directive->{ $ucname } = $value;
219             }
220             # otherwise, it's a normal variable parameter
221             else {
222 120         502 $directive->{ PARAMS }->{ $name } = $value;
223             }
224             }
225              
226              
227             # create a new Directive and check everything worked OK
228 230 50       1032 unless (defined($directive = $self->{ DIRECTIVE }->new($directive))) {
229             # we need to construct a soft reference to the error function in
230             # the Directive base class
231 9     9   63 no strict 'refs';
  9         25  
  9         7566  
232              
233             $self->_error("Directive constructor failed: %s",
234 0   0     0 &{ $self->{ DIRECTIVE } . "\::error" } || '');
235             }
236              
237             # return undef or reference to newly constructed directive
238 230         828 $directive;
239             }
240              
241              
242              
243             #========================================================================
244             #
245             # directive_type()
246             #
247             # Public method used by calling objects to determine the class type of
248             # the directives that the Factory creates via the create_directive()
249             # method.
250             #
251             # Returns a string containing the class name.
252             #
253             #========================================================================
254              
255             sub directive_type {
256 85     85 0 120 my $self = shift;
257              
258 85         231 $self->{ DIRECTIVE };
259             }
260              
261              
262              
263             #========================================================================
264             #
265             # error()
266             #
267             # Returns the current object error message, stored internally in
268             # $self->{ ERROR } or undef if no error condition is recorded. If the
269             # first (implicit) parameter isn't an object reference, then this must
270             # have been called as a package function rather than an object method.
271             # In this case, the contents of the package variable, $ERROR, is
272             # returned. e.g.
273             #
274             # $factory->error(); # returns $self->{ ERROR }
275             # Text::MetaText::Factory::error(); # returns $ERROR
276             #
277             # Returns an error string or undef if no error condition is currently
278             # raised.
279             #
280             #========================================================================
281              
282             sub error {
283 0     0 0 0 my $self = shift;
284              
285             defined $self
286             ? $self->{ ERROR }
287 0 0       0 : $ERROR;
288             }
289              
290              
291              
292             #========================================================================
293             # ----- PRIVATE METHODS -----
294             #========================================================================
295            
296             #========================================================================
297             #
298             # _configure(\%cfg)
299             #
300             # Private initialisation method called by the new() constructor.
301             # This acts as a hook method for derived classes who may wish to do
302             # specific initialisation. Errors can be reported in the _configure()
303             # method by calling $self->_error(...)
304             #
305             # Returns 1 on success, undef on failure. Derived methods must follow
306             # this protocol if they utilise the base class constructor, new(), and
307             # return a true/undef value to indicate if the method was successful or
308             # not. This affects whether or not the constructor returns a new object
309             # or undef to indicate failure.
310             #
311             #========================================================================
312              
313             sub _configure {
314 14     14   33 my $self = shift;
315 14   50     54 my $cfg = shift || { };
316              
317              
318             # do nothing - just return success
319 14         113 1;
320             }
321              
322              
323              
324             #========================================================================
325             #
326             # _split_text($text)
327             #
328             # Utility routine to split the input text, $text, into lexical tokens.
329             # The tokens are identified as single words which are pushed directly
330             # onto a "@tokens" list, or " = " pairs which are
331             # coerced into a two-element array ([0] => variable, [1] => value) which
332             # is then stored in the list by reference.
333             #
334             # A reference to the list of tokens is returned. On error, undef is
335             # returned and the internal ERROR string will be set.
336             #
337             #========================================================================
338              
339             sub _split_text {
340 230     230   269 my $self = shift;
341 230         357 my $text = shift;
342 230         1267 my @tokens = ();
343              
344              
345             # some simple definitions of elements we use in the regex
346 230         285 my $word = q((\S+)); # a word
347 230         265 my $space = q(\s*); # optional space
348 230         388 my $quote = q("); # single or double quote characters
349 230         258 my $escape = "\\\\"; # an escape \\ (both '\' escaped)
350 230         351 my $anyquote = "[$quote]"; # class for quote chars
351 230         367 my $equals = "$space=$space"; # '=', with optional whitespace
352              
353             # within a quoted phrase we might find escaped quotes, e.g.
354             # name = "James \"Charlie\" Brown"; to detect this, we scan
355             # for sequences of legal characters (not quotes or escapes) up until
356             # the first quote or escape; if we find an escape, we jump past the
357             # next character (possible a quote) and repeat the process, and repeat
358             # the process, and so on until we *don't* find an escape as the next
359             # character; that implies it's an unescaped quote and the string ends.
360             # (don't worry if that slipped you by - just think of it as magic)
361              
362 230         341 my $okchars = "[^$quote$escape]*";
363 230         477 my $qphrase = "$anyquote ( $okchars ($escape.$okchars)* ) $anyquote";
364              
365              
366             # split directive parameters; note that our definitions from
367             # above have embedded substrings ( ) so we need to be a little
368             # careful about counting backreferences accurately...
369 230         2236 while ($text =~
370             /
371             $word $equals $qphrase # $1 = $2 (NB: $2 contains $3)
372             | # e.g. (foo) = "(bar baz)"
373             $word $equals $word # $4 = $5
374             | # e.g. (foo) = (bar)
375             $qphrase # $6 (NB: $6 contains $7)
376             | # e.g. "(foo bar)"
377             $word # $8
378             # e.g. (foo)
379             /gxo) { # 'o' - compile regex once only
380              
381 505 100 33     2377 if ($6 or $8) {
382             # if $6 or $8 is defined, we found a simple flag. This gets
383             # pushed directly onto the tokens list
384 336 50       2408 push(@tokens, defined($6) ? $6 : $8);
385             }
386             else {
387             # $6 and $8 undefined so use $1 = $2, or $4 = $5. This
388             # "name = value" pair get pushed onto the token list as
389             # an array reference
390 169 100       1342 push(@tokens, [
    100          
391             defined($1) ? $1 : $4,
392             defined($1) ? $2 : $5
393             ]);
394             }
395             }
396              
397             # return a reference to the tokens list
398 230         708 \@tokens;
399             }
400              
401              
402              
403             #========================================================================
404             #
405             # sub _error($errmsg, @params)
406             #
407             # Formats the error message format, $errmsg, and any additional parameters,
408             # @params with sprintf and sets the $self->{ ERROR } variable with the
409             # resulting string. This is then available via the public error() method.
410             # The package variable, $ERROR, is also set so that the error can be
411             # determined when the constructor fails (and hence there would be no $self
412             # in which to store $self->{ ERROR }). Calling error() as a package
413             # function, rather than an object method, triggers this response.
414             #
415             # If $errmsg is undefined, the $self->{ ERROR } variable is undefined to
416             # effectively clear any previous error condition.
417             #
418             #========================================================================
419              
420             sub _error {
421 0     0     my $self = shift;
422 0           my $msg = shift;
423              
424 0 0         $self->{ ERROR } = $ERROR = defined ($msg)
425             ? sprintf($msg, @_)
426             : undef;
427             }
428              
429              
430              
431             1;
432              
433             =head1 NAME
434              
435             Text::MetaText::Factory - Factory class for instatiating Directive objects.
436              
437             =head1 SYNOPSIS
438              
439             use Text::MetaText::Factory;
440             my $factory = Text::MetaText::Factory->new(\%cfg);
441              
442             =head1 DESCRIPTION
443              
444             The Text::MetaText::Factory module is used by Text::MetaText to instantiate
445             Text::MetaText::Directive objects. The Factory and Directive classes can
446             be sub-classed to create a more specific processing system.
447              
448             =head1 AUTHOR
449              
450             Andy Wardley Eabw@kfs.orgE
451              
452             See also:
453              
454             http://www.kfs.org/~abw/
455              
456             =head1 REVISION
457              
458             $Revision: 0.2 $
459              
460             =head1 COPYRIGHT
461              
462             Copyright (c) 1996-1998 Andy Wardley. All Rights Reserved.
463              
464             This program is free software; you can redistribute it and/or modify it
465             under the terms of the Perl Artistic License.
466              
467             =head1 SEE ALSO
468              
469             For more information, see the main Text::MetaText documentation:
470              
471             perldoc Text::MetaText
472            
473             For more information about the author and other Perl development work:
474              
475             http://www.kfs.org/~abw/
476             http://www.kfs.org/~abw/perl/
477             http://www.cre.canon.co.uk/perl/
478              
479             For more information about Perl in general:
480              
481             http://www.perl.com/
482              
483             =cut
484              
485