CGI::Kwiki

This article is about a new Perl module called CGI::Kwiki. With this
module you can create a Wiki Web site in less than a minute. Now that's
quick. Or more appropriately, ``That's Kwik!''

If you've not heard of a Wiki, it's a Web site that allows you to add and
edit pages directly from your browser. Generally, every page on the site
has a link or button that will let you edit the page that you are
reading. When you edit a page, the raw contents of that page come up in
a text edit area in your browser. You can make any changes you want.
When you hit the SAVE button, the changes become live.

To create a new page, you just create a link on the current page to a
page that didn't exist before. Then when you follow the new link, you
are allowed to edit the new page.

Knowledge of HTML is not a prerequisite for using a Wiki. It's not even
a requisite, because the raw Wiki contents that you edit are not
presented as HTML. Wikis use a much more natural markup, that
resembles the messages posted in Usenet news groups. An example can
speak for itself:

== A Page Header for a Sample Wiki Page ==
Here's list of some WikiFormattingCodes:
* Lines that begin '* ' form a bulleted list
* Asterisks might be used to mean *bold* text
* Links like http://www.perl.com work automatically

The only markup that should require further explanation is the text
WikiFormattingCodes. Capitalized words that are mushed together form
a link to another page on the Wiki site.

A Wiki is simply a Web site that is easy for ordinary people to edit. So
where did the Wiki idea come from and why is it important?

I've only been dabbling in the world of Wiki for less than a year.
Rather than answer that question myself, I decided to ask the inventor
of the Wiki. Now by pure coincidence, Ward Cunningham lives but a few
miles from my house and well with in my telephone area code. I decided
to drop him a line, and find out his innermost feelings on his creation:

Brian: Yes, hello. May I speak to Mr. Ward Cunningham?

Ward: Who is this?

Brian: This is Brian Ingerson from Perl.com. I have a few questions.

Ward: Perl?! That's not me! Wall is to blame. Call him.

Brian: No. Wait. It's about the Wiki.

Ward: Ah, yes. The Wiki. Well let's get to business.

Brian: Why did you invent the Wiki?

Ward: Wiki had a predecessor that was a hyper-card stack. I wrote it
to explore hypertext. I wanted to try recording something that was
ragged, something that wouldn't fit into columns. I had this pet theory
that programming ideas were spread by people working together. I set out
to chart the flow of ideas through my company (then Tektronix). This
turned out to be more fun than I ever would have imagined.

When we were really trying to capture a programmer's experience in
software patterns, I remembered that stack and set out to do it over
with the technology of the moment, the World Wide Web. This was
1994. I wrote Wiki to support and enlarge the community writing
software patterns.

Brian: What do you see as Wiki's most-positive contribution to the world?

Ward: Back in 1994, the Web was a pretty wonderful place, with lots of
people putting up stuff just because they thought someone else would
find it interesting or useful. Wiki preserves that feeling in a place
that has become too much of a shopping mall. It reminds people that
sometimes to work together you have to trust each other more than you
have any reason to.

Brian: Are you concerned that there are so many different Wiki
implementations?

Ward: I was concerned once. I wish everyone used my markup instead of
inventing their own. But that didn't happen. Now I realize that the
implementations have done more to spread the idea than I ever could with
my one version. That is the way it is with really simple things.

Just in case you didn't visualize the tongue entering and exiting my
cheek, Ward does not have anything against Perl. To the contrary, he does
almost all his open-source development with it, including his Wiki
software. Try visiting his Wiki site, http://c2.com/cgi/wiki, for an
excellent introduction to Wiki.

As was pointed out, there are many many implementations that have sprung
forth since the Wiki was invented, and many of those were written in
Perl. That's because a Wiki is fairly easy to implement and everyone
seems to want to do it slightly differently.

Most of these implementations are just simple CGI scripts at heart.
Even though they may have gathered dozens of special features over the
years, they are really just ad hoc programs that are not
particularly modularized or designed for extensibility.

One notable exception is the CGI::Wiki module by Kate ``Kake'' Pugh. This
relatively new CPAN distribution is designed to be a Wiki framework.
The various bits of functionality are encapsulated into class modules
that can be extended by end users. As far as I know, this project is the
first attempt in Perl to modularize the Wiki concept. It's about time!

The second attempt is a completely different module called CGI::Kwiki;
the subject of this article. When I evaluated CGI::Wiki, I found it a
little too heavy for my needs. It had about a dozen prerequisite
modules and required an SQL database. CGI::Kwiki by comparison requires
no extra modules besides those that come with Perl, and stores its Web
pages as plain text files.

I find this preferable, because I can install a new Kwiki in seconds
(literally) and I have the full arsenal of Unix commands at my disposal
for manipulating the content. In fact, the default search facility for
CGI::Kwiki is just a method call that invokes the Unix command grep.

Another compelling aspect of CGI::Kwiki is that every last bit of it is
extensible, and extending it is trivial. About the only thing you can't
easily change is the fact that it is written in Perl.

Because of this, I have probably set up more than a dozen Kwiki
sites in the past month, and customized each one according to my
needs. In this article, I'll show you how to do the same thing.

So just how easy is it to install a Kwiki? Well, that depends on how many
of the basics you already have in place. You need a Web server and
Perl, of course. You also need to have the CGI::Kwiki module installed
from CPAN. That's about it.

For the sake of a specific example, let's say that you are running the
Apache Web server (version 1.3.x) and that
/home/johnny/public_html/cgi-bin/ is a CGI-enabled directory. With
that setup in place, you can issue the following commands to create a
new Kwiki:

At this point, if you do an ls command inside the my-kwiki
directory, then you should see two files (index.cgi and config.yaml).
index.cgi is just a point of execution for the CGI::Kwiki class
modules, and config.yaml is little more than a list of which class
modules are being used. You should also see a directory called
database, where all your Kwiki pages are stored as individual plain
text files.

These files will become important later as we explore how to customize Kwiki
to your personal needs or whims.

If you are having trouble configuring Apache for CGI, then here is the basic
httpd.conf section that I use for my personal Kwikis:

When you first visit your newly installed Kwiki, you'll notice that
there are a number of default pages already installed. Most notably is
the one called HomePage, because that's the one you'll see first. This
page requests that you change it as soon as possible. Go ahead and give
it a try. Click the EDIT button.

You should see the text of HomePage laid out in Kwiki format inside an
editable text area. Make some changes and click the SAVE button. The first
thing you'll probably want to know is exactly how all the little Kwiki markup
characters work.

CGI::Kwiki has a set of default formatting rules that reflect my favorites
from other Wikis. Some are from WardsWiki, some from MoinMoin, some from
UseMod. All of them are customizable. More on that shortly. For now, let's go
over the basics.

The first thing to learn is how to create a link. A link to another page on
the site is made by squishing two or more words together in CamelCase. If the
page doesn't exist yet, then that's OK. Clicking on it will allow you to create the
new page from scratch. This is how Wikis grow.

You can also create an external link by simply starting some text with
http:. Like http://c2.com/cgi/wiki, the original Wiki Web site. Sometimes you
want an internal link that isn't CamelCase. Just put the link text inside
square brackets. If you want the link to be external, then add the http:
component inside the brackets:

The second most-common formatting rule I use is preformatted text. This is
used for things like Perl code examples. Text that is preformatted is
automatically immune to futher Wiki processing. To mark text as preformatted
you just indent it. This is similar to the approach that POD takes:

sub backwards_string {
return join '', reverse split '', shift;
}

One of the FormattingRules that I personally like is the ability to create
HTML tables. You do it like this (if you're a bowler):

Kwiki has a fairly rich set of default formatting rules. You'll find
an exhaustive list of all the rules right inside your new Kwiki. The
page is called KwikiFormattingRules. To find this page (and every
other page on your Kwiki) click the RecentChanges link at the top of
the current page.

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.

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.

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:

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.

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:

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:

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.

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:

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.

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)

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)

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!

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!