CGI::Kwiki
by Brian Ingerson
|
Pages: 1, 2
KustomizingKwiki
To those of you familiar with the Wiki world, this has all been fairly pedestrian stuff so far. Here's where I think that things get interesting. As I stated before, every last part of the Kwiki software is changable, customizable and extensible. Best of all, it's easy to do.
CGI::Kwiki is made up of more than a dozen class modules. Each class is responsible for a specific piece of the overall Kwiki behavior. To change something about a particular class, you just subclass it with a module of your own.
Some of the more important CGI::Kwiki classes are:
- CGI::Kwiki::Formatter
This is the most-common class to extend. It's where all the formatting rules are codified.
- CGI::Kwiki::Database
This class loads and stores the Kwiki pages.
- CGI::Kwiki::Template
Defines the HTML that gives the look and feel to your Kwiki.
- CGI::Kwiki::Driver
Controls the entire CGI process.
- CGI::Kwiki::Config
An abstraction for reading the config file parameters.
Kwiki knows what classes to use by looking in it's config file. So if you want
to subclass something, then the first thing you would do is change the config.yaml
entry to point to your new class. Let's start with a easy one.
A Kwik and Dirty Tweak
Kwiki will turn a word or phrase inside *asterisks* to bold text.
This is similar to the way you might do it in text e-mail. But WardsWiki
uses '''triple quotes''' for bolding. Let's change your Kwiki to do
it like Ward does.
First, create a file called MyFormatter.pm. You can put it right inside your
Kwiki installation directory, and Kwiki will find it. The contents of the file
should look like this:
package MyFormatter;
use base 'CGI::Kwiki::Formatter';
sub bold {
my ($self, $text) = @_;
$text =~ s#'''(.*?)'''#<b>$1</b>#g;
return $text;
}
1;
Now, change the config.yaml file to use this line:
formatter_class: MyFormatter
The Kwiki formatting engine will now call your subroutine with
pieces of text that are eligible to contain bold formatting.
Sections of text that are already preformatted code will not be
passed to your bold() method. And as you can see, MyFormatter is
a subclass of CGI::Kwiki::Formatter so all the other formatting
behaviors remain intact.
Kwiki's Formatting Engine
Let's look under the hood at CGI::Kwiki's hotrod formatting engine. You'll need to be familiar with it to do any serious formatting changes. Conceptually, it's rather simple. It works like this.
- The text starts out as one big string.
- There is a list of formatting routines that are applied in a certain order.
- The string is passed to the first formatting routine. This routine may change the original text. It may also break the text into a number of substrings. It then return the strings it has created and manipulated.
- Each of the substrings is run through the next formatting routine in line.
- Sometimes, a formatting routine will want to make sure that no further routines touch a particular substring. It can do this by returning a hard reference to that string.
- After all the substrings have been passed through every routine, they are joined back together to form one long string.
The specific routines and their order of execution is determined by
another method called process_order(). The process_order method just
returns a list of method names in the order they should be called. The
default process_order method is:
sub process_order {
return qw(
function
table code header_1 header_2 header_3
escape_html
lists comment horizontal_line
paragraph
named_http_link no_http_link http_link
no_wiki_link wiki_link force_wiki_link
bold italic underscore
);
}
The best way to get a good feel for how to do things is to look over the CGI::Kwiki::Formatter module itself.
KontentKontrol
The biggest fear that many people have of setting up a Wiki site is that someone will come along and destroy all their pages. This happens from time to time, but in general people just don't do it. It's really not that cool of a trick to pull off. Someone could even write a program to destroy a Wiki, but if they were that smart, hopefully they'd be mature enough not to do it.
As of this writing, CGI::Kwiki doesn't do anything to protect your data. But remember, it's just code. Let's now extend your code to do a simple backup, everytime a page is written.
Possibly the simplest way to back up files on Unix is to use RCS. Let's make the Kwiki perform an RCS checkin every time it saves a page.
This time we need to extend the database class. Change the config file like so:
database_class: MyDatabase
Then write a file called MyDatabase.pm that looks like:
package MyDatabase;
use base 'CGI::Kwiki::Database';
sub store {
my $self = shift;
my ($file) = @_;
$self->SUPER::store(@_);
system(qq{ci -q -l -m"saved" database/$file backup/$file,v});
}
1;
Note: Be sure to add a backup directory that the CGI program can write to:
mkdir backup
chmod 777 backup
In this case the store method calls its parent method to handle this
actual database store. But then it invokes an extra rcs command to
backup the changes to the file.
Hopefully these examples will give you an idea of how to go about making other types of modifications to CGI::Kwiki. If you make a whole set of cohesive and generally useful extensions, then please consider putting them on CPAN as module distribution.
A Kwiki in Every Pot
The classic use for a Wiki site is to provide a multi-user forum for some topic of interest. In this context, Wiki is a great collaboration tool. People can add new ideas, and revise old ones. The Wiki serves as both an archive and a news site. Most Wikis provide a search mechanism and a RecentChanges facility.
But I think this only scratches the surface of Wiki usage possibilities. Since a Kwiki is so easy to create, I now find myself doing it all the time. It's almost like I'm creating a new wiki for every little thing I set out to do. Here's a few examples:
- Personal Planning
I have a personal wiki for keeping track of my projects. I keep it on my laptop.
- Module Development
Every Perl module I write these days has its own Kwiki in the directory. I use them mainly for creating Test::FIT testing tables. (See Test::FIT on CPAN). But I can also use it for project notes and documentation. Since I can extend the Kwiki, I can make it export the pages to POD if I want.
- Autobiowiki
I am seriously considering writing the stories of my life in a Wiki. If I can get others to to the same, then the Wikis could be linked using Ward's SisterSite mechanism. This would create one big story. (See http://c2.com/cgi/wiki)
- Project Collaboration
For my bigger projects I like to create a user community based around a Wiki. Using Test::FIT I can actually get my users to write failing tests for my projects. And they can help write documentation, report bugs, share recipes, etc. (See http://fit.freepan.org and http://yaml.freepan.org)
Conclusion
One final point of interest; this entire article was written in a Wiki format. I needed to submit it to my editor in POD format, which he in turn formatted into the HTML you are reading now. I accomplished this by simply using an extension of CGI::Kwiki::Formatter that produces POD instead of HTML!
NOTE: The raw content of this article along with the formatter program can be found at http://www.freepan.org/ingy/articles/kwiki/
Editor's note: http://www.kwiki.org has been created as the official kwiki home page.
About the Author
Brian Ingerson has been programming for more than 20 years, and hacking Perl for five of those. He is dedicated to improving the overall quality of scripting languages including Perl, Python and Ruby. He currently hails from Portland, Ore.; the very location of this year's O'Reilly Open Source Convention. How convenient!

