use CGI;
“I’m sorry, Dave, I can’t do that.”
cpanm CGI
“You really shouldn’t use that any more. It’s bad for you.”
perldoc CGI
“The rationale for this decision is that CGI.pm is no longer considered good practice for developing web applications, including quick prototyping and small web scripts. There are far better, cleaner, quicker, easier, safer, more scalable, more extensible, more modern alternatives available at this point in time. These will be documented with CGI::Alternatives.”
perldoc CGI::Alternatives
No documentation found for “CGI::Alternatives”.
cpanm CGI::Alternatives
perldoc CGI::Alternatives
“Let me build this strawman that doesn’t actually make good use of
CGI.pm
to show you how you can easily switch to one of half a dozen different frameworks that let you use half a dozen different templating systems launched with half a dozen different embedded web servers, and replace your self-contained 100-line CGI script with half a dozen files located in half a dozen directories. For more fun, my sample code gets mangled if you try to view it as a manpage, so you really should download the raw file from CPAN.”
cpanm --uninstall CGI::Alternatives
cpanm Dancer2
perldoc Dancer2
cpanm --uninstall Dancer2
cpanm Mojolicious
perldoc Mojolicious
perldoc Mojolicious::Lite
use Mojolicious::Lite;
plugin CGI => [ '/' => "trivialscript.cgi" ];
app->start;
use CGI;
…
I thought it would be easy, like in the deal. Knock together a quick Perl script with some command-line options for easy debugging, then add a little bit of GUI-glue to create a simple HTML form that allows me to play with the output and easily tweak the script to add features. Y’know, the way the web was built.
Nope. It’s all
I couldn’t find a single example that showed how to easily replace the
straightforward use of CGI.pm
and its helper functions with any of
the “quicker, easier” alternatives. Pretty much every tutorial starts
with how to build a database-backed login page with the form elements
coded by hand, which is pretty much the exact opposite of what I
wanted.
I’m sure all of these frameworks look great on your Github résumé, but
I was just trying to do something quickly and easily, things that used
to be Perl’s strengths. Hell, I was using
Mason back in 2002 (and since it’s still
around, I may rebuild my old project pages at some point), so it’s not
like I wasn’t aware there were alternatives to CGI.pm
, but what does
the current Mason tutorial do? Show you how to build a database-backed
login page with the form elements coded by hand. Sigh.
What was the project? A complete rewrite of my random-word generator from 2003. The old one was a straightforward digram generator loosely based on Chris Pound’s scripts, that mixed-and-matched his language sample files. The new one is based on looking at the old one and finding nothing worth keeping.
Instead of using digrams again or generalizing to n-grams, I got the
idea to go with n-character unigrams. That is, for N = 3
, an n-gram
generator would take an input word like “ageless”, break it up into
(age, gel, ele, les, ess), and use it to decide what character can
come after “el”. My way splits “ageless” into (age, les, s), picks a
start token, and then randomly selects valid transition tokens until
it reaches an end token.
The fun comes when you feed it multiple source files. It randomly selects from all the valid tokens at each step, so you can transition from ageless to hanageishi to firishtih, ending up with “ageishtih”. IMHO, these discrete N-character tokens preserve a little more of the distinct flavor of the source files, so that a Lovecraft/Norse mix (Móulýr, Dýcgug) is clearly different from a Japanese/Irish/Jargon mix (Mockinkotoji, Tarindent), and, most importantly, feels like a Lovecraft/Norse mix.
Being able to (coughcough) quickly, easily generate the web UI with
CGI.pm
made it possible to focus on the code, improving the
performance and output quality, and I was even able to make it vaguely
pretty with Bootstrap, since I’d already learned the basics of that
when I rebuilt the blog in Hugo (whose templating system has exactly
nothing in common with any of the Perl template modules, of course; so
many new wheels being invented, and not one of them as round as the
old ones…).
I’ll put it online soon. Now that it’s pretty much done, I’m willing
to go through the pain of figuring out how to use Mojolicious::Lite
directly rather than through the CGI shim.
That was… painful. Parameter handling is clumsy as hell, and rendering
is poorly-documented black magic. Actually, I’d give a D to all the
Mojolicious documentation, because it tells you everything about
implementation details and not a damn thing about usage. As far as I
can tell, the only way to find out if you’ve been called in response
to a POST is to see if the array referenced by
$c->req->body_params->pairs
has non-zero length. Yes, you have POST
parameters; no, you don’t.
But you get a very pretty debug page when something goes wrong! It’s not particularly useful, and you need to make sure to disable it before releasing your web app (while also overriding the rainbow-vomiting-dinosaur error page that no sane person would ever want to display), but gosh is it pretty!
How did I end up rendering a page that’s a mix of static text, dynamic
form data, and multiple columns of randomly-generated words? By
building up a large string in memory and then saying $c->render(text => $entirepage)
. Because you only get to call render
once per
route, apparently, and the last call wins. I guess most of your logic
is supposed to be in the fucking templates.
“Quicker, easier”, my ass.
Anyway, the new generator is here.
I moved the form-rendering to the “proper” embedded-perl tag helpers, which was deeply annoying, because the context switch between the real Perl and the embedded made it difficult to preserve the state of checkboxes, which are simply not passed in a POST if their state is off. I ended up having to duplicate the top-level route code, so that the default “on” checkbox value only gets passed to the form on a GET, allowing the oversimplified template logic to work. Also, I took a look at their form validation support, but since I’m more interested in input sanitization, it was a poor fit.
Markdown formatting and simple HTML accepted.
Sometimes you have to double-click to enter text in the form (interaction between Isso and Bootstrap?). Tab is more reliable.