5a812d92a71a4434700934b98b86ec6e5ed56a89
[matthijs/upstream/blosxom-plugins.git] / gavinc / mason_blocks
1 # Blosxom Plugin: mason_blocks
2 # Author(s): Gavin Carr <gavin@openfusion.com.au>
3 # Version: 0.001000
4
5 package mason_blocks;
6
7 use strict;
8
9 # --- Configurable variables -----
10
11 # Debug verbosity
12 my $debug_level = 0;
13
14 # --------------------------------
15
16 sub start { 1 };
17
18 sub head {
19   my($pkg, $currentdir, $head_ref) = @_;
20   munge_blocks($head_ref);
21   return 1;
22 }
23
24 sub story {
25   my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
26   munge_blocks($story_ref);
27   return 1;
28 }
29
30 sub foot {
31   my($pkg, $currentdir, $foot_ref) = @_;
32   munge_blocks($foot_ref);
33   return 1;
34 }
35
36 sub munge_blocks {
37   my ($flavour_ref) = @_;
38
39   my @flavour = ();
40   my ($doc, @if, @else, @if_blocks, @else_blocks);
41   @if = @else = @if_blocks = @else_blocks = ();
42   for (split /\n/, $$flavour_ref) {
43     # Ignore lines beginning with '%#'
44     next if m/^%\s*#/;
45
46     # Ignore if in doc block <%doc> .... </%doc> (at beginning of lines)
47     if (m!^</%doc>! && $doc) {
48       $doc = 0;
49       next;
50     } elsif ($doc) {
51       next;
52     } elsif (m!^<%doc>!) {
53       $doc = 1;
54       next;
55     }
56
57     # Minimalist version - if, } else {, } only, nesting supported
58     if (m/^%\s*if\b/) {
59       my $if = $_;
60       $if =~ s/^%\s*if\s*//;
61       $if =~ s/\s*{\s*$//;
62       # New block, record condition, and add new entries to other arrays
63       push @if, $if;
64       push @else, 0;
65       push @if_blocks,   [];
66       push @else_blocks, [];
67       next;
68     }
69     elsif (m/^%\s*\}\s*else\s*\{/) {
70       # Else at same level - set current else flag to true
71       $else[$#else] = 1;
72       next;
73     }
74     elsif (m/^%\s*\}/) {
75       # End of block - pull latest entries from all arrays
76       my $if = pop @if;
77       my $else = pop @else;
78       my $if_block = pop @if_blocks;
79       my $else_block = pop @else_blocks;
80       warn "end_block: if '$if', if block " . 
81         scalar(@$if_block) . " lines, else block " . 
82         scalar(@$else_block) . " lines\n" 
83           if $debug_level;
84       # Check condition, and replace current line with appropriate flattened block
85       if (eval "$if") {
86         $_ = join "\n", @$if_block;
87       } else {
88         $_ = join "\n", @$else_block;
89       }
90     }
91     
92     # Regular line - add to @else_blocks, @if_blocks, or @flavour
93     if (@else && $else[$#else]) {
94       push @{$else_blocks[$#else_blocks]}, $_;
95     }
96     elsif (@if) {
97       push @{$if_blocks[$#if_blocks]}, $_;
98     }
99     else {
100       push @flavour, $_;
101     }
102   }
103
104   $$flavour_ref = join "\n", @flavour;
105 }
106
107 1;
108
109 __END__
110
111 =head1 NAME
112
113 mason_blocks - blosxom plugin to support simple mason-style if-blocks
114 in blosxom flavours/templates
115
116 =head1 SYNOPSIS
117
118     # In a flavour or template file ...
119
120     # Mason-style conditionals
121     % if ($pagetype::pagetype ne 'story') {
122     <a href="$permalink::story#comments">Comments ($feedback::count) &raquo;</a>
123     % } else {
124     <a href="$permalink::story#leave_comment">Leave a comment &raquo;</a>
125     % }
126
127     # Mason-style comments
128     %# Only show a comments section if there are comments
129     % if ($feedback::count > 0) {
130     $feedback::comments
131     % }
132
133     # Mason-style block comments
134     <%doc>
135     This is a great big
136     multi-line, extremely important
137     comment.
138     </%doc>
139
140
141 =head1 DESCRIPTION
142
143 mason_blocks is a blosxom plugin implementing simple conditional and
144 commment blocks using mason-style syntax (as in the HTML::Mason perl
145 templating system), for use in blosxom flavour and template files.
146
147 =head2 CONDITIONALS
148
149 mason_blocks supports simple if and if-else blocks using lines beginning
150 with the '%' character (which must be the first character on the line)
151 e.g.
152
153     % if ($pagetype::pagetype eq 'story') {
154     <a href="$permalink::story#leave_comment">Leave a comment &raquo;</a>
155     % }
156
157 and
158
159     % if ($pagetype::pagetype ne 'story') {
160     <a href="$permalink::story#comments">Comments ($feedback::count) &raquo;</a>
161     % } else {
162     <a href="$permalink::story#leave_comment">Leave a comment &raquo;</a>
163     % }
164
165 Whitespace is not significant, but braces are required and should match, 
166 just as in perl. The if-conditions can comprise any valid perl condition.
167
168 =head2 COMMENTS
169
170 Two comment styles are also supported. Single line comments must begin with
171 a '%' character, followed by optional whitespace, follwed by a '#' character,
172 and continue only to the end of the line e.g.
173
174     %# This is a completely profound and illuminating comment
175     % # As is this
176
177 Block comments must begin with a <%doc> token (at the beginning of a line)
178 and end with a </%doc> token (also at the beginning of a line). All text
179 between these two tokens is treated as a comment and not included in output.
180 For example:
181
182     <%doc>
183     More enlightening profundities from your template author
184     Explaining why this stuff is as ugly as it is ...
185     </%doc>
186
187 Block comments cannot be nested.
188
189 =head2 VS. INTERPOLATE_FANCY
190
191 mason_blocks was initially born out of my frustration with older versions 
192 of interpolate_fancy not supporting nested constructs properly (though I'd
193 also been frustrated with the syntax and the limits on the conditionals
194 available). 
195
196 I thought for an experiment I'd see how hard simple non-nested 
197 conditionals using a mason-style syntax would be, and it turned out to be
198 not very difficult at all. I no longer use interpolate_fancy at all - my
199 limited use cases seem better met using mason_blocks.
200
201 As I see it, mason_blocks has the following advantages over 
202 interpolate_fancy:
203
204 =over 4
205
206 =item Nesting support
207
208 Earlier versions of interpolate_fancy had problems with nested 
209 constructs. I believe that this has been fixed in the later versions
210 updated by Matthijs Kooijman (>= version 20060111). 
211
212 mason_blocks fully supports nested conditionals.
213
214 =item If-Else Constructs
215
216 mason_blocks supports simple if-else blocks, instead of making you
217 use 'if x eq 1; if x ne 1' pairs. It does not currently support 
218 elsif, however.
219
220 =item Full perl conditions
221
222 mason_blocks allows you to use full perl conditions (including composite
223 conditions) instead of being limited to simple conditions using only the
224 most common operators. For instance, all of the following require hoop
225 jumping with interpolate_fancy:
226
227 =over 4
228
229 =item if ($foo >= 3)
230
231 =item if (substr($foo, 3, 1) eq 'X')
232
233 =item if ($pagetype::pagetype eq 'story' && $feedback::comments > 0)
234
235 =back
236
237 =back
238
239 mason_blocks does not provide any of interpolate_fancy's interpolation 
240 or action functionality, however.
241
242
243 =head1 USAGE
244
245 mason_blocks should probably be loaded relatively late, since you'll
246 often want to use various plugin package variables in your conditionals.
247
248 It uses the 'head', 'story', and 'footer' hooks, rather than 'interpolate',
249 so it should be able to be used alongside any of the interpolate plugins
250 if you wish.
251
252
253 =head1 SEE ALSO
254
255 HTML::Mason, for the block syntax (the module is not used or required by 
256 this plugin, however).
257
258 Blosxom: http://blosxom.sourceforge.net/
259
260
261 =head1 BUGS
262
263 Please report bugs either directly to the author or to the blosxom 
264 development mailing list: <blosxom-devel@lists.sourceforge.net>.
265
266
267 =head1 TODO
268
269 - add elsif support
270
271
272 =head1 AUTHOR
273
274 Gavin Carr <gavin@openfusion.com.au>, http://www.openfusion.net/
275
276 =head1 LICENSE
277
278 Copyright 2007, Gavin Carr.
279
280 This plugin is licensed under the same terms as blosxom itself i.e.
281
282 Permission is hereby granted, free of charge, to any person obtaining a
283 copy of this software and associated documentation files (the "Software"),
284 to deal in the Software without restriction, including without limitation
285 the rights to use, copy, modify, merge, publish, distribute, sublicense,
286 and/or sell copies of the Software, and to permit persons to whom the
287 Software is furnished to do so, subject to the following conditions:
288
289 The above copyright notice and this permission notice shall be included
290 in all copies or substantial portions of the Software.
291
292 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
293 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
294 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
295 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
296 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
297 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
298 OTHER DEALINGS IN THE SOFTWARE.
299
300 =cut
301
302 # vim:ft=perl