Sign In/My Account | View Cart  
advertisement


Listen Print

Blosxoms, Bryars and Blikis
by Simon Cozens | Pages: 1, 2

Everything's a Wiki

So much for blogs, for the time being. The other movement in social software at the moment is Ward Cunningham's wiki. A wiki has three important characteristics: a simple mark-up language, the ability for the viewer to modify the page, and the ability to create links from one wiki page to another.

Despite initial predictions that they'd be unusable due to widespread graffiti, vandalism, and other kinds of kicking down the sandcastle, wikis have turned out to work quite well in practice, with sites like Wikipedia collecting a great store of information from contributors both regular and occasional.

CPAN has a fair collection of wiki implementations, including Kwiki, CGI::Wiki, Apache::MiniWiki, and others. However, there may well be times when it makes sense to create a new implementation, particularly when the wiki is to be embedded in another application.

What does it mean to embed a wiki? An example will demonstrate it best. Imagine a web-mail system like IMP or SquirrelMail. Now we want to add the ability to write a short note or annotation on a given message, so that it can be referred back to later. If I get a mail from my friend Al arranging to meet up for a drink at the pub, I'd want to annotate the mail with Al's mobile phone number, directions to the pub, and the fact that I need to take the book that I borrowed from him last month. Then, in an ideal world, the mail system would collect all the notes, work out the date and time of the meeting, and tell my calendaring software about it, but that's another story for a different time.

The fact is that once we have these sticky notes for mail, we might want to use them to refer to other mail, group them together in fluid topics, and so on. For instance, if I mentioned in the annotation that this was an AlMeeting, I would expect that text to be magically marked up as a link to all the other AlMeeting mails. Here we've got the three elements of a wiki -- annotation editing, a simple markup language, and the ability to link.

While the editing is a simple matter of linking your CGI parameters with your database, something that should be second nature to those who want to avoid writing code, the other two components take a little bit of work. Thankfully, chromatic has written a handy module, Text::WikiFormat.

With WikiFormat, you can pass a text string marked up in wiki format to Text::WikiFormat::format, and it will return you HTML:


print Text::WikiFormat::format(<<EOF);
= A Test Post =

I found this '''very''' interesting WikiLink recently.

EOF

__DATA__
<h1>A Test Post</h1>

<p> <br />
I found this <strong>very</strong> interesting 
<a href="WikiLink">WikiLink</a> recently. <br />
  </p>

This gives us the simple markup, but it doesn't do much about the linkability; for an embedded wiki, we're going to need finer-grained control over how the links are constructed. For instance, we might want to pass the link name to a particular URL with a particular CGI parameter. Thankfully, Text::WikiFormat supports two optional parameters in addition to the text to be formatted: the first is a hash reference overriding how the wiki text is marked up to HTML, and the second is a hash reference of options, such as the URL prefix for links.

So, if we have an application that displays a page given a parameter in the URL, we can just say:

 
Text::WikiFormat::format($text, {},  
        { prefix => "http://www.myhost.int/wiki?page=" }); 

And there we have it, an instant wiki.

Of course, in the context of our webmail application, we may have to do something more convoluted. For instance, we might want a link to SimonCozens to resolve to all mail from that person, if it can be understood as a person who sends email, or to a similarly marked-up set of messages, like an AlMeeting, if it can't. For this, we need to introduce a bit of logic and decide how to form the link.

As we mentioned above, Text::WikiFormat allows us to specify replacements for the way markup is translated to HTML. WikiFormat uses a hash-ref internally to turn wiki "tags" into HTML, and we can, in fact, put in a subroutine reference for the link tag and have that emit the appropriate HTML link.

 
sub markup { 
    my $text = shift; 
    Text::WikiFormat::format(shift, { link => \&my_link });
} 

sub my_link {
    my $linkname = shift;
    my $name = $linkname;
    ($name=$linkname) =~ s/(?<=[a-z])(?=[A-Z])/ /g;
    if (have_mail_from($name)) {
       # Valid correspondent, link to page of their mail
       my $id = correspondent_id($name);
       return qq{<A HREF="/mail/search?correspondent=$id">}.$name.
              "</A>";
    }
    # Not a correspondent, just a wiki page
    return qq{<A HREF="/wiki?$linkname">}.$linkname.
           "</A>";
}

What's going on here? First, we receive the link name in StudlyCaps every time format sees a link. We then convert it to a real name, by inserting a space in the gaps between a lowercase character and an uppercase one. Now we have a name like "Simon Cozens" that we can search our mailstore for, and if we find someone, we can return the URL to a page about their mail. Otherwise, we return a wiki page. We've used our webmail annotations to refer to either real people or to other annotations, stealthily embedding a wiki in the application, with minimal effort.

Creating the Bliki

With that example of how to create a custom wiki from an existing application, let's return to Bryar and our blogging software.

The concept of a bliki -- a cross between a wiki and a blog -- may seem like a bizarre one at first, but it's such a natural synergy that it's been independently invented by multiple people, including Martin Fowler and many others.

Depending on how you look at it, a bliki is either an ordinary wiki with a blog-style front-end showing the latest posts, or an ordinary blog with wiki-like markup and interconnections between the posts. The only difference between these views is how easy it is to edit the posts. We'll stick with the "ordinary blog" viewpoint, since editing posts over the Web is a boring and solved problem, and one not really related to the technology we're looking at today.

How are we going to extend Bryar to become a bliki? It's obvious that Text::WikiFormat is going to be involved somewhere, and it would be helpful to use the Bryar::DataSource::FlatFile class too. First, we inherit from the FlatFile class, and override the make_document method, which is responsible for turning a filename into a Bryar::Document:


package Bryar::DataSource::FlatFile::Bliki;
use base 'Bryar::DataSource::FlatFile';
use strict;
use Text::WikiFormat;

sub make_document {
    my ($self, $filename) = @_;
}

Here the format will be slightly different -- the filename (such as "MyWikiPost.txt") will be used to form both the title and the ID of the document, and the content of the document will be transformed via WikiFormatter wholesale.


sub make_document {
    my ($self, $file) = @_;
    return unless $file and open my $in, $file;
    my $when = (stat $file)[9];
    my $who = getpwuid((stat $file)[4]);
    $file =~ s/\.txt$//;

    my $dir = dirname($file);
    $dir =~ s{^\./?}{};
    my $category = $dir || "main";

    local $/;
    my $text = <$in>;
    
    return Bryar::Document->new(
        title    => $file,
        content  => Text::WikiFormat::format($text, {}, {prefix => "id_"}),
        epoch    => $when,
        author   => $who,
        id       => $file,
        category => $category,
    );
}

We change the prefix for links to be a relative link of the form id_PostName, since this is how Bryar deals with references to other blog posts, by default. (Of course, we could change this by modifying the FrontEnd class, but this seems to work fine.)

It took 30 lines of code to convert Bryar into a simple bliki, many of which were stolen from the superclass. Now let's look at something a bit different.

Everything's a Blog

I mentioned when introducing Bryar that it was based on the Model-View-Controller (MVC) pattern, although I didn't realize this while designing it.

The MVC pattern is described in this entry in Ward Cunningham's own wiki, as being made up of three parts:

  • A model, therefore is an object representing data or even activity, e.g. a database table or even some plant-floor production-machine process.
  • A view is some form of visualization of the state of the model.
  • A controller offers facilities to change the state of the model.

All kinds of things follow the MVC design. In Bryar, the model is the data source object; the view is the templating object; the controller is the Collector object. A web browser might be described as a controller that contains all its logic, a view which contains the user interface, and the pane of rendered HTML, and the model of the entire Worldwide Web.

But some web-based applications follow Bryar's MVC approach particularly closely. Imagine, for instance, a company's product catalog on the Web. The catalog data will be stored in some kind of database, and will be presented via a templating system, with a controller that will decide which products to show. Isn't that exactly the same as reading some blog posts from a database (albeit potentially one that looks a lot like a filesystem), rendering them via templating system, with a controller deciding which posts to show?

Indeed, many of the views you will want of the catalog data are exactly what you'd want from a blog: display the most recent products, display all products, search by product name or description, and a detailed display of a single product.

We've seen it take 30 lines to turn a blog into a bliki. To turn a blog into a complete product catalog web site takes a subclass of the Bryar::DataSource::DBI class (to talk to the product database) and the Bryar::Document class (to take more details, a URL to a photo, and so on). The rest is a matter of templating, and that's a designer's job!

Social Software

I consider the emergence of interest in social software to be one of the most fascinating trends in software engineering this year. Two of the most powerful and popular aspects of this, wikis and blogs, are particularly well-suited for extension and embedding, and Perl is a particularly well-suited language for achieving this.

Although part of the point of this article was to demonstrate Bryar, there were several other important points. First, that there are plenty of Perl implementations of both wikis and blogs that you can choose from; second, that Perl makes it really easy to create your own blog or wiki and customize to your own purposes, including embedding them in an existing application.

But finally, the point was to encourage you to think about good design and the power of extensible applications; if you can create a tool that is both powerful and generalizable -- just like Perl itself -- it may end up doing wildly different things to what you initially intended!