1
# vim: tabstop=4 shiftwidth=4 expandtab
5
Inside the C{contrib/} directory, you'll see the C{plugins/} directory. To
6
install a given plugin, move the plugin file you want from the C{contrib/}
7
directory to the C{libs/plugins/} directory of your installation.
9
Some plugins take effect immediately, like the C{conditionalhttp.py} and the
10
C{statusnotfound.py}. Some requires a little bit more information in using it,
11
like files to store data, or some variables to put inside your flavour
12
templates. Do read the plugin file itself to see what extra steps you need
13
to do before installing it.
15
Below is a basic documentation for plugin developers and it exposes them
16
of what callbacks are available to them and documents on how to use them
19
B{The BlosxomRenderer plugin callbacks}
21
The L{BlosxomRenderer} plugins supports set of callback functions based on the
22
blosxom 2.0 callbacks. The names arguments are different, but the
23
L{BlosxomRenderer} callbacks are called at the same points that the blosxom 2.0
26
All of the BlosxomRenderer callbacks take the same three arguments
28
The available blosxom renderer callbacks are:
30
- L{cb_head} (corresponds to blosxom 2.0 head)
31
- L{cb_date_head} (corresponds to blosxom 2.0 date)
32
- L{cb_story} (corresponds to blosxom 2.0 story)
33
- L{cb_foot} (corresponds to blosoxm 2.0 foot)
35
In PyBlosxom, the functionality some of the blosxom 2.0 callbacks are taken
36
care of by callback chains.
38
- The blosxom 2.0 entries callback is handled by L{cb_filelist}
39
- The blosxom 2.0 filter callback is handled by L{cb_prepare}
40
- The blosxom 2.0 sort callback is handled by L{cb_prepare}
43
from libs.Request import Request
44
from libs.renderers.blosxom import BlosxomRenderer
45
from libs.entries.base import EntryBase
46
from libs.pyblosxom import PyBlosxom
50
A callback to prepare data before a renderin.
52
This callback is called before we go through the renderer. Arguments
55
- C{'request'} - The L{Request} object at the particular moment
57
Most plugins can use the prepare chain to either transform or add to the
58
L{Request.getData()} dict. Some plugins could also use the C{'entry_list'}
59
list of entries and modify data there.
61
Here's an example of a prepare chain plugin::
65
This plugin shows the number of entry we are going to print and
66
place the result in $countNoOfEntries
68
request = args['request']
69
data = request.getData()
70
config = request.getConfiguration()
71
# Can anyone say Ternary? :)
72
IF = lambda a,b,c:(a() and [b()] or [c()])[0]
74
num_entry = config['num_entries']
75
entries = len(data['entry_list'])
77
data['countNoOfEntries'] = IF(num_entry > entries, num_entry, entries)
79
@param args: A dict containing a L{Request()} object
85
def cb_logrequest(args = {'filename': 'A file',
86
'return_code': 'A http return code', 'request': Request()}):
88
This callback is responsible for logging a typical request.
90
A dict, C{args} is given containing:
92
- C{'filename'} - a filename (typically a base filename)
93
- C{'return_code'} - A HTTP error code (e.g 200, 404, 304)
94
- C{'request'} - a L{Request} object
96
No return is expected from this callback. This is usually called at the
97
last point of rendering
99
A typical contents of args::
100
filename = config.get('logfile', '')
101
{'filename': filename,
102
'return_code': '200',
103
'request': Request()}
105
@param args: A dict containing the keys request, filename and return_code
111
def cb_filestat(args = {'filename': 'A file', 'mtime': os.stat('/')}):
113
A callback that returns a file C{stat} based on the arguments received.
115
The args received is a dict containing:
117
- C{'filename'} - a physical file and
118
- C{'mtime'} - what is returned by C{os.stat} function.
120
Plugins are supposed to transform the value of mtime if a certain condition
121
is met, according to the plugin. All plugins that registers C{cb_filestat}
122
are given a chance to take a peek at the args.
124
A typical contents of args::
125
filename = '/home/someone/blosxom/cat/file.txt'
126
{'filename': filename,
127
'mtime': os.stat(filename)}
129
@param args: A dict with two keys, filename and mtime
135
def cb_filelist(args = {'request' : Request()}):
137
A callback to generate a list of L{EntryBase} subclasses.
139
If C{None} is returned, then the callback chain will try the next plugin in
142
@param args: A dict containing a L{Request()} object
144
@returns: None or list of L{EntryBase}.
150
def cb_entryparser(args = {'txt': 'A blosxom text entryparser'}):
152
A callback that tranforms a dict, containing a list of keys - the extension
153
of files it can take, and a function reference, that accepts two arguments,
154
a filename, and the standard request object.
156
The function is supposed to return a dict, at least containing the key
157
C{'title'} and C{'story'}. Entryparsers can use other callback facilities
158
like L{cb_preformat} and the L{cb_postformat} callbacks. See
159
L{libs.pyblosxom.PyBlosxom.defaultEntryParser} on how to use such facilities.
161
All outputs of entryparsers (and together with preformatters and
162
postformatters) will be cached by the caching mechanisms.
164
Plugins are supposed to add more keys as the extension of the file it can
165
handle. A plugin can also replace the standard txt entryparser if the need
166
be. All plugins that registers C{cb_filestat} are given a chance to take a
167
peek at the args, append to it, or modify it (not advisable).
169
By default, typical contents of args::
170
{'txt': L{libs.pyblosxom.PyBlosxom.defaultEntryParser}}
172
Here's an example code that reads *.plain files::
175
def cb_entryparser(args):
177
Register self as plain file handler
179
args['plain'] = parse
182
def parse(filename, request):
184
We just read everything off the file here, using the filename as
188
entryData['title'] = os.path.basename(filename)
189
entryData['story'] = file(filename).read()
192
Upon a successful registration, pyblosxom will now read all *.plain and
193
*.txt files from the data directory
195
@param args: A dict that comtains function references to entryparsers
201
def cb_preformat(args =
202
{'parser': 'somepreformatter',
203
'story': ['The\n','text\n'],
204
'request': Request()}):
206
A callback for preformatters.
208
A preformatter is a text transformation tool. Only one preformatter can
209
run at an entry at a time. In this chain, all preformatters are called
210
until one returns a string and not C{None}.
212
Preformatters should act on the parser, and if it matches what the
213
preformatter can handle it can carry on an deal with the story.
217
- C{'parser'} - A string that determines whether a preformatter should run
218
- C{'story'} - A list containing lines of text (with '\\n' included)
219
- C{'request'} - a L{Request} object
221
A typical preformat plugin look like::
223
def cb_preformat(args):
224
if args['parser'] == 'linebreaks':
225
return parse(''.join(args['story']))
228
# A preformatter to convert linebreak to its HTML counterpart
229
text = re.sub('\\n\\n+','</p><p>',text)
230
text = re.sub('\\n','<br />',text)
231
return '<p>%s</p>' % text
233
@param args: A dict containing a L{Request()} object, parser identifier and
236
@returns: A string containing formatted text
242
def cb_postformat(args = {'entry_data': {}, 'request': Request()}):
244
A callback for postformatters
246
Postformatters are callbacks that may make further modification to the
247
entry text, called after a preformatter, it can also be used for extensive
248
operations on a particular entry, adding extra keys to the given
249
'entry_data' dict. If a cache is used in a particular installation, the
250
resulting data will be saved in the cache, so using this chain may not be
251
useful for dynamic data like comment counts, for example. Acceptable
254
- Adding a word count
255
- Using a macro replacement plugin (Radio Userland glossary)
257
- A 'more' text processor
259
A typical C{args} contains the following:
261
- C{'entry_data'} - A dict that minimally contains a C{'title'} and a
263
- C{'request'} - A typical L{Request} object
265
@param args: A dict containing a L{Request()} object, and an entry_data dict
270
def cb_start(args = {'request': Request()}):
272
A start up callback for plugins
274
The start callback can be used to perform initialization of a callback.
275
Use this callback for any setup code that your plugin needs, like
277
- reading saved data from a file
278
- checking to make sure configuration variables are set
280
@param args: A dict containing a L{Request()} object
285
def cb_end(args = {'request' : Request()}):
287
A finalization callback for plugins
289
The end callback can be used to perform finalization for a callback.
290
Use the end callback to clean up after your plugin has executed. This
293
- save data to a file
294
- clean up any temporary files
296
@param args: A dict containing a L{Request()} object
302
def cb_head(args = {'renderer':'The Blosxom renderer',
303
'entry':'The entry to render',
304
'template':'The template to be filled in'}):
306
A callback that is called before a head flavour template is rendered
308
C{cb_head} is called before the variables in the entry are substituted
309
into the template. This is the place to modify the head template based
310
on the entry content. You can also set variables on the entry that will
311
be used by the C{cb_story} or C{cb_foot} templates. You have access to
312
all the content variables via entry.
314
Blosxom 2.0 calls this callback 'head'
318
- C{'renderer'} - the L{BlosxomRenderer} that called the callback
319
- C{'entry'} - a L{EntryBase} to be rendered
320
- C{'template'} - a string containing the flavour template to be processed
322
@param args: a dict containing a L{BlosxomRenderer}, L{EntryBase}, and template
327
def cb_date_head(args = {'renderer':'The Blosxom renderer',
328
'entry':'The entry to render',
329
'template':'The template to be filled in'}):
331
A callback that is called before a date_head flavour template is rendered
333
C{cb_head} is called before the variables in the entry are substituted
334
into the template. This is the place to modify the date_head template
335
based on the entry content. You have access to all the content variables
338
Blosxom 2.0 calls this callback 'date'
342
- C{'renderer'} - the L{BlosxomRenderer} that called the callback
343
- C{'entry'} - a L{EntryBase} to be rendered
344
- C{'template'} - a string containing the flavour template to be processed
346
@param args: a dict containing a L{BlosxomRenderer}, L{EntryBase}, and template
351
def cb_story(args = {'renderer':'The Blosxom renderer',
352
'entry':'The entry to render',
353
'template':'The template to be filled in'}):
355
A callback that is called before a story flavour template is rendered
357
C{cb_story} is called before the variables in the entry are substituted
358
into the template. This is the place to modify the story template based
359
on the entry content. You have access to all the content variables via
362
Blosxom 2.0 calls this callback 'story'
366
- C{'renderer'} - the L{BlosxomRenderer} that called the callback
367
- C{'entry'} - a L{EntryBase} to be rendered
368
- C{'template'} - a string containing the flavour template to be processed
370
@param args: a dict containing a L{BlosxomRenderer}, L{EntryBase}, and template
375
def cb_foot(args = {'renderer':'The Blosxom renderer',
376
'entry':'The entry to render',
377
'template':'The template to be filled in'}):
379
A callback that is called before a footflavour template is rendered
381
C{cb_foot} is called before the variables in the entry are substituted
382
into the template. This is the place to modify the foot template based
383
on the entry content. You have access to all the content variables via
386
Blosxom 2.0 calls this callback 'foot'
390
- C{'renderer'} - the L{BlosxomRenderer} that called the callback
391
- C{'entry'} - a L{EntryBase} to be rendered
392
- C{'template'} - a string containing the flavour template to be processed
394
@param args: a dict containing a L{BlosxomRenderer}, L{EntryBase}, and template