So, I’ve used Perl 6 for a few days. I’m trying to write a wiki, because that’s what I like to do, and that also what I use every day. I’ve been maintaining and running Oddmuse since 2003. I know what I want. I’ve been down every dead end, I sometimes feel. Now I want to learn the language using a real project and that’s what it is.

The current state, from a programming perspective:

It uses Cro as the web framework, meaning it can run stand-alone, without Apache or nginx. It’s no longer a CGI script. I expect that most people will still use a regular web server as the front end for all their applications because of caching, logging, encryption, access control and all that.

It uses Markdown to generate the HTML. I’ve started using Markdown more and more. I no longer recommend Wiki Creole.

It uses Mustache templates to generate the layout and everything around the actual wiki page “content.” No more printing as we go in order to appear faster.

The storage backend is a class that delegates everything to the actual storage class. Right now I’ve only implemented file-based storage, but if I keep all access going through this storage class then that will make replacing it with git or a SQLite a breeze.

For the moment, configuration happens via environment variables: which storage backend to use, which data directory to use if you use files as your backend, what links to show at the top, it’s all environment variables.

This means that translating the interface means setting a bunch of environment variables and editing the templates.

There are tests!

File locking when writing files (for the file storage backend).

Keeping (numbered) backups of page files.

Random test directories for parallel testing

The software, from a user perspective:

View pages written in Markdown and rendered as HTML.

Edit pages as Markdown.

Fields available: text, summary, author, and a checkbox for minor changes

List recent changes.

A rudimentary filter for recent is available as a proof of concept: it allows you to specify how many items to see.

IP addresses are transformed into four octets and shown as little flag icons if no author was provided. This makes it likely that you can detect who edited a bunch of pages without revealing their IP number of host name.

Old page revisions can be examined.

Showing the latest change for every page on Recent Changes

Diff with old page revisions

Missing features:

unified layout

merge in case of conflicts

expiration of old page revisions

admin passwords

banning regular expressions

locking the site

locking pages

question asking for first time posters

rolling back changes

RSS feed

tags

search

comments

Missing big ideas:

a plugin system

markup rules which users can add, ideally by merging grammars (this enables us to have rules that protect text from further processing, such as code blocks; this requires the notion of rule precedence)

a backend implementation using SQLite

More to come! I’m running out of time and I have to go. Here’s an idea: draft pages. They are like real pages but they don’t show up in search or feeds. Hah!

Anyway, I was talking to @tyil and thought that I should write this stuff down. Not sure who the intended audience is for these things. I feel like I’m too confused right now to understand where the problem is to be found, how can I create an issue, and where, and with what suggestion? Perhaps my future self is the audience for this blog post. One day I’ll wonder how newbies get into Perl 6 and what their issues are and I’ll be able to come back to this blog post and see myself struggling.

So, for a start, these are the things that immediately jumped out at me:

missing integration of Perl 6 docs into the man system

system missing a good Cro manual for offline use (I brought the laptop along on a trip)

missing good search for when I know what I want but don’t know the signal, twiggils and operators

I bought Perl 6 Deep Dive by Andrew Shitov and I’m surprised at how quickly I’m running out of information in the book. It was a good read to get started and to motivate myself. Good enough to actually pull me into starting this project. That’s cool. But the next point is the sort of documentation I’ve had trouble finding.

For example:

I’m trying to have a class called Storage which delegates all the important method calls to another class which I want to load at run time. In this case, it’s going to be Storage::File . How to do it? I searched for “delegation” and the like and ended up on documents that were deprecated. I figured it would have to involve require somewhere, and then something like that “synopsis” or whatever it was. I don’t really care about the “synopsis” and “exegesis” and all the other funny ways the language was developed now that I’m actually trying to get stuff done. I’m a different kind of user, I know – but this is the kind of user that we will have to pull in. In the end I asked on the #perl6 channel on IRC and found something that works:

class Storage { my $class = %*ENV<storage> || 'Storage::File'; require ::($class); has $!delegate handles <get-page put-page get-template put-change get-changes> = ::($class).new; }

This illustrates two points: I might have found out about “handles” but I didn’t find it in the book. The index doesn’t mention “delegation”. Apparently this is called a “trait”. The index doesn’t mention “traits”. But even knowing all these keywords, I can’t find out about these things by starting with p6doc objects .

And that brings me to another topic: p6doc .

I didn’t realize that was a separate thing that I would have to install.

When you run p6doc --help , it tells you stuff about p6doc build and p6doc list . When you do that, you see a lot of topics. When you then try p6doc slurp or p6doc "sub slurp" you’ll get a No such type error. How does it work? What do I need to do?

, it tells you stuff about and . When you do that, you see a lot of topics. When you then try or you’ll get a error. How does it work? What do I need to do? When I run p6doc Str because I want to learn about join I find information about the vector flag. Searching for concat also doesn’t help. It must be some operator? Try p6doc operators , search for join , and then it dawns on me that it works on lists. Python: echo 'print(",".join(["1", "2"]))' | python3 . Perl: perl6 -e 'say [1, 2].join(",")' . Oh well.

because I want to learn about I find information about the vector flag. Searching for also doesn’t help. It must be some operator? Try , search for , and then it dawns on me that it works on lists. Python: . Perl: . Oh well. Are there native file locks? I’m looking at p6doc IO , IO, IO::Path, and I don’t see “lock” mentioned anywhere. On the #perl6 channel somebody tells me about IO::Handle . Yay!

And then there are all those little things that bite.

ternary operator is x ?? y !! z instead of x ? y : z

instead of regular expressions are very different now

map requires a comma after the block

here docs are different

And many other things besides. As I’m too new to the language I don’t understand why things have to be “same same but different”. I hope there’s is a grandiose pay-off, I guess?

Here’s an example of how access to the hash elements no longer uses braces but angled brackets, the regular expression is different, the braces aren’t used when creating the hash, and map takes a comma after the block:

my $menu = %*ENV<menu> || "Home, Changes"; my @pages = $menu.split(/ ',' \s* /); my %params = id => $id, pages => [ map { id => $_ }, @pages ];

The Pod is also subtly different and the documentation confused me a bit. There are many options. What the suggested way of doing it? Is this good? Should I be using #| instead?

=head3 put-page =begin pod Pages are saved in the C<page> subdirectory with the <md> extension. =end pod method put-page (Page $page!) is export { my $dir = %*ENV<dir> || '.'; my $path = "$dir/page/$($page.name).md"; spurt $path, $page.text, :enc('UTF-8'); }

Anyway, that’s the kind of stuff I’m thinking about when I write Perl 6 code.

Oh, and recently my application has this super aggravating tendency: Often, when making changes (and this only started showing up recently!), I get an error.

♻ Restarting edit (edit) ⚠ edit ===SORRY!=== ⚠ edit This type (NQPMu) does not support associative operations

The strange thing is that no matter what change I make, that fixes it. So now I have a second shell open where I just do the following:

echo >> lib/Storage/File.pm6

And then it works!

♻ Restarting edit (edit) 📓 edit Listening at http://localhost:20000

Apparently, all I have to do is trigger a recompilation.

When I’m testing, same thing.

dir=. storage=Storage::File prove6 -l -v t/edit.t

This causes an error:

===SORRY!=== This type (NQPMu) does not support associative operations t/edit.t .. Dubious, test returned 1 No subtests run All tests successful. Test Summary Report ------------------- t/edit.t (Wstat: 256 Tests: 0 Failed: 0) Non-zero exit status: 1 Parse errors: No plan found in TAP output Files=1, Tests=0, 4 wallclock secs Result: FAILED

The fix is simple:

echo >> lib/Storage/File.pm6

The result:

ok 1 - Status is acceptable ok 2 - Content type is acceptable ok 3 - Body is acceptable 1..3 ok 1 - GET /edit/About ok 1 - Status is acceptable ok 2 - Content type is acceptable ok 3 - Body is acceptable 1..3 ok 2 - POST /save ok 3 - page name correct ok 4 - page content saved ok 5 - changes correct ok 6 - year ok 7 - time ok 8 - major change ok 9 - page name ok 10 - code ok 11 - summary ok 1 - Status is acceptable ok 2 - Content type is acceptable ok 3 - Body is acceptable 1..3 ok 12 - POST /save ok 13 - year ok 14 - time ok 15 - minor change ok 16 - page name ok 17 - author ok 18 - summary 1..18 t/edit.t .. ok All tests successful. Files=1, Tests=18, 6 wallclock secs Result: PASS

How weird is that? I asked on the #perl6 channel and one of the people there was curious and was interested in fixing this. Sadly, I was unable to produce a small working example. I tried for quite a while. I have no idea what causes this.

Tags: Oddmuse 6 Perl 6