File Coverage

lib/Text/Macros.pm
Criterion Covered Total %
statement 37 37 100.0
branch 6 8 75.0
condition 4 6 66.6
subroutine 7 7 100.0
pod 1 4 25.0
total 55 62 88.7


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Text::Macros.pm - an object-oriented text macro engine
5              
6             =head1 SYNOPSIS
7              
8             use Text::Macros;
9              
10             # poetic:
11             my $macro_expander = new Text::Macros qw( {{ }} );
12             $text = expand_macros $macro_expander $data_object, $text;
13              
14             # noisy:
15             $macro_expander = Text::Macros->new( "\Q[[", "\Q]]", 1 );
16             print $macro_expander->expand_macros( $data_object, $text );
17              
18             =cut
19              
20              
21             package Text::Macros;
22              
23 1     1   8062 use strict;
  1         2  
  1         41  
24              
25 1     1   7 use vars qw( $VERSION );
  1         2  
  1         1820  
26             $VERSION = '0.04';
27              
28             =head1 DESCRIPTION
29              
30             Typical usage might look like this:
31              
32             =over 4
33              
34             my $template = <
35             To: [[ RecipientEmail ]]
36             From: [[ SenderEmail ]]
37             Subject: Payment Past Due on Account # [[ AccountNum ]]
38              
39             Dear [[ RecipientName ]]:
40             Your payment of [[ PaymentAmount ]] is [[ DaysPastDue ]] days past due.
41             EOF
42              
43             # get a data object from somewhere, e.g.:
44             my $data_object = $database->get_record_object( 'acctnum' => $account_num );
45              
46             # make a macro expander:
47             my $macro_expander = Text::Macros->new( "\Q[[", "\Q]]" );
48              
49             # expand the macros in the template:
50             my $email_text = $macro_expander->expand_macros( $data_object, $template );
51              
52             =back
53              
54             To support this, a "data object" would need to exist which would need to
55             define methods which will be used as macro names, e.g. like this:
56              
57             =over 4
58              
59             package RecordObject;
60             sub RecipientEmail { $_[0]->{'RecipientEmail'} }
61             sub SenderEmail { $_[0]->{'SenderEmail'} }
62             sub AccountNum { $_[0]->{'AccountNum'} }
63             sub RecipientName { $_[0]->{'RecipientName'} }
64             sub PaymentAmount { $_[0]->{'PaymentAmount'} }
65             sub DaysPastDue { $_[0]->{'DaysPastDue'} }
66              
67             =back
68              
69             Alternatively, the data object class might have AUTOLOAD defined, for example
70             like this:
71              
72             =over 4
73              
74             package RecordObject;
75             sub AUTOLOAD {
76             my $self = shift;
77             my $name = $AUTOLOAD;
78             $name =~ s/.*:://;
79             $self->{$name}
80             }
81              
82             =back
83              
84             If this is the case, then the macro expander should be instructed not to
85             assert that the macro names encountered are valid for the object -- since
86             CAN might fail, even though the calls will be handled by AUTOLOAD.
87             To do this, pass a true value for the third value to the constructor:
88              
89             =over 4
90              
91             my $macro_expander = Text::Macros->new( "\Q[[", "\Q]]", 1 );
92              
93             =back
94              
95              
96             Macros can take arguments. Any strings which occur inside the macro text
97             after the macro name will be passed as arguments to the macro method call.
98             By default, the macro name and any arguments are all separated by newlines.
99             You can override this behavior; see the documentation of parse_args, below.
100              
101             Example:
102              
103             =over 4
104              
105             $macro_expander = new Macros qw( {{ }} );
106              
107             print $macro_expander->expand_macros( $cgi_query,
108             "You entered {{ param
109             Name }} as your name."
110             );
111              
112             =back
113              
114             This will replace the substring
115              
116             {{ param
117             Name }}
118              
119             with the result of calling
120              
121             =over 4
122              
123             $cgi_query->param("Name")
124              
125             =back
126              
127             (Obviously this example is a little contrived.)
128              
129              
130             =head1 METHODS
131              
132             =head2 The Constructor
133              
134             =over 4
135              
136             Text::Macros->new( $open_delim, $close_delim, $no_CAN_check, $parse_args_cr );
137              
138             =back
139              
140             The delimiters are regular expressions; this gives you the greatest power in
141             determining how macros are to be detected in the text.
142             But it means that if you simply want them to be considered literal strings,
143             then you must quotemeta them.
144              
145             Since the macro expander will be calling object methods, you have an option:
146             do you want any encountered macro names to be required to be valid for the
147             given object? Or do you have some kind of autoloading in effect, which will
148             handle undefined methods?
149              
150             If you have some kind of autoloading, pass a true value for the third
151             argument to new(). If you want the expander to assert CAN for each method,
152             pass false (the default).
153              
154             The fourth argument, $parse_args_cr, is a reference to a sub which implements
155             your macro argument parsing policy. See the section on parse_args, below.
156              
157             =cut
158              
159             sub new {
160 6     6 0 290 my $pkg = shift;
161 6         39 bless {
162             open_delim => shift,
163             close_delim => shift,
164             no_CAN_check => shift,
165             parse_args_cr => shift, # code ref
166             }, $pkg;
167             }
168              
169              
170             =head2 The Main Method: Expand Macros
171              
172             =over 4
173              
174             $text = $macro_expander->expand_macros( $data_object, $text );
175              
176             =back
177              
178             The $data_object argument is not an object of the Macros package.
179             Rather, this is the object upon which the macro will be called as a method.
180              
181             expand_macros() returns the result of replacing all the macros it finds
182             with their appropriate expansions. Note that recursion can occur; that is,
183             if the expansion of a macro results in text which also contains a valid
184             macro, that new macro will also be expanded. The text will be scanned
185             for macros, and those macros will be expanded, until none are found.
186              
187             =cut
188              
189             sub expand_macros {
190 14     14 0 800 my $self = shift;
191 14         24 my $object = shift;
192 14         19 local $_ = shift; # the string to expand macros in.
193              
194 14         32 my $open_delim = $self->{'open_delim'};
195 14         16 my $close_delim = $self->{'close_delim'};
196              
197 14         333 while (
198             s(($open_delim)(.*?)($close_delim)) {
199 15         43 local $Text::Macros::open = $1;
200 15         23 local $Text::Macros::close = $3;
201 15         36 $self->call_macro( $object, $self->_call_parse_args( $2 ) )
202             }se
203             ) { } # all the work is done in the predicate.
204              
205 12         165 $_;
206             }
207              
208              
209              
210             =head2 A Utility Method: Call Macro
211              
212             =over 4
213              
214             $macro_expander->call_macro( $data_object, $macro_name, @arguments );
215              
216             =back
217              
218             This is used internally by expand_macros(), but you can call it directly if you wish.
219              
220             Essentially all this does is this:
221              
222             =over 4
223              
224             $macro_expander->call_macro( $data_object, $macro_name, @arguments );
225              
226             =back
227              
228             results in the call:
229              
230             =over 4
231              
232             $data_object->$macro_name( @arguments );
233              
234             =back
235              
236             All the macros supported by the data object can be predefined,
237             or you might have some kind of autoloading mechanism in place for it.
238             If you have autoloading in effect, you should have passed a true value as
239             the third argument to new(). If you pass false (the default),
240             the call_macro() will check to see that the object CAN do the method;
241             and if it can't an exception will be thrown.
242              
243             Note: data objects' macro methods must return a string.
244             They can take any number of arguments, which will all be strings.
245              
246             =cut
247              
248             sub call_macro {
249 15     15 0 64 my $self = shift;
250 15         16 my $object = shift;
251 15 50 33     83 defined $_[-1] && $_[-1] eq '' and pop @_; # drop last item if empty.
252 15         19 my $func = shift;
253 15         22 $func =~ s/^\s+//;
254 15         25 $func =~ s/\s+$//;
255 15 100 100     133 $self->{'no_CAN_check'} or $object->can( $func ) or die "Can't $func!";
256 13         49 $object->$func( @_ )
257             }
258              
259              
260             =head2 Parsing the Macro Arguments: parse_args
261              
262             This is used internally by expand_macros().
263              
264             expand_macros tries to call the sub which was passed by reference as the
265             fourth argument to new(), if there was one. If no such coderef was given
266             to the constructor, then expand_macros calls the parse_args method in the
267             Text::Macros class, which implements the default behavior of splitting
268             the arg text on newlines, triming off leading/trailing whitespace, and
269             then dropping any list elements which are '' (empty strings).
270              
271             To implement some behavior other than the default, you may derive a class
272             from Text::Macros which overrides parse_args. The parse_args method
273             takes the Text::Macros object reference as the first arg (as usual), and
274             the macro text as the second argument. This is all the text between the
275             delimiters, as it occurs in the template text. This method is responsible
276             for extracting the macro name and the values of any arguments from the
277             macro text. It is advisable that the parse_args routine strip any leading
278             and trailing whitespace from the argument values. (It happens automatically
279             for the macro name, though, so you needn't worry about that.)
280              
281             Example:
282              
283             =over 4
284              
285             package MyMacroParser;
286             @ISA = qw( Text::Macros );
287             sub parse_args {
288             my( $self, $macro_text ) = @_;
289             # return a list of args extracted from $macro_text...
290             }
291              
292             =back
293              
294             And then, of course, you would instantiate a MyMacroParser rather than a
295             Text::Macros. Everything else about its usage would be identical.
296              
297             If you prefer, you can redefine the Text::Macros::parse_args sub directly.
298             That might look something like this:
299              
300             =over 4
301              
302             *Text::Macros::parse_args = sub {
303             my( $self, $macro_text ) = @_;
304             # return a list of args extracted from $macro_text...
305             };
306              
307             =back
308              
309             Alternatively, you may pass a code reference as the fourth argument to new().
310             The arguments to and results from this sub are the same as for the parse_args
311             method, as described above, even though it is not (necessarily) a method itself.
312              
313             The precedence is this: if a sub was passed to new(), that is called;
314             if not, the parse_args() of the derived class is called, if defined;
315             if not, the parse_args() of the base class (Text::Macros) is called.
316              
317             =cut
318              
319             # PRIVATE: DO NOT OVERRIDE!
320             sub _call_parse_args {
321 15     15   27 my( $self, $macro_text ) = @_;
322 15 100       38 if ( defined $self->{'parse_args_cr'} ) {
323 1 50       6 ref($self->{'parse_args_cr'}) =~ /CODE/
324             or die "parse_args_cr is not a code ref!";
325 1         5 return( $self->{'parse_args_cr'}->( $self, $macro_text ) );
326             }
327 14         103 return( $self->parse_args( $macro_text ) );
328             }
329              
330             #
331             # default behavior; this can be overridden in a derived class.
332             # the parse_args() method -- in the base class and in any derived class --
333             # is ALWAYS superceded by a sub passed as the fourth argument to new().
334             #
335             sub parse_args {
336 13     13 1 16 my( $self, $macro_text ) = @_;
337             return(
338 16         208 grep { length }
  16         31  
339 13         32 map { s/^\s+//; s/\s+$//; $_ }
  16         33  
  16         37  
340             split /\n/, $macro_text
341             );
342             }
343              
344             =head1 EXAMPLES
345              
346             Brief examples of all these usage techniques can be found in the test script,
347             test.pl, which accompanies this distribution. Any questions can be directed
348             to the author via email.
349              
350             =cut
351              
352              
353             1;
354              
355             __END__