Mojolicious: Do It For The Candy!
Most of my recent blog posts about Mojolicious have revolved around its non-blocking capabilities. I like to write about those because I think that it is those capabilities that can bring new eyes to Perl from other languages, much like Node.js brought eyes to server-side javascript (for the same reason). That said, lately I have had excuses to show off Mojolicious and when I have done so, it has been some of the other cool features that have garnered the “Ooooh”s and “Aaaah”s from onlookers.
In this article I will show you some of those extras, like accessing your generated pages and even app itself direcly from the command line. I will also show how testing can be easy, powerful, expressive and yet still readably beautiful.
Revisiting the WebSocket Example
A while back I demonstrated a simple Mojolicious WebSocket app. This app simply:
- renders a page with the current state of a database table
- takes input from a form
- sends the data as JSON over a WebSocket
- inserts the data into the database table
- renders a new HTML row and sends it to the client for insertion in the HTML table
I am going to use this app for two reasons, first it will demonstrate the candy I want to show off and second it gives me a chance to brush the app up for recent (and even not so recent) Mojolicious updates. So lets take a look:
The app only requires Mojolicious and a few DBI modules to run it, so with cpanm run
cpanm Mojolicious DBI DBD::SQLite DBIx::Connector
And then to run the app (called websocket.pl
) run
perl websocket.pl daemon
From there you can open a browser to either localhost:3000
or 127.0.0.1:3000
to use the app yourself.
Improvements to the App
Since you last saw this app, I have tweaked just a few things:
- It uses the JSON-over-websocket architecture that Mojolicious now provides
- send data structures to the client via the
json
pseudo-op - receive data structures via the
json
websocket event
- send data structures to the client via the
- It uses DBIx::Connector to maintain the DB connection
- It uses the new
render_to_string
method rather than the now-removedpartial
stash key
Command Line Candy: The get Command
Of course when you are developing your application, you often run some simple tests by hand as you go. To do so you find yourself switching between your editor and your browser, refreshing and scrolling to find out if your change worked.
Mojolicious provides you with another option. From a command line, just as you would start your application, you can instead use Mojo::UserAgent to get a page straight from your app itself. For example you can run
perl websocket.pl get /
to see what your landing page HTML looks like.
You can then use Mojo::DOM to inspect, say, the head
tag to make sure it looks ok,
perl websocket.pl get / head
After you use the app to add a few records, you might want to see the state of the table
perl websocket.pl get / '#table'
or even examine a certain row (say, the second one)
perl websocket.pl get / '#table tr' 1
Command Line Candy: The eval Command
The get
command is great for inspecting the output of your app.
Sometimes, though, you really want deeper access to your app.
For example, if you want to see the current state of the database, you can of course drop to the db shell to do the query yourself, but is that the way the app sees the data? How often do people forget to update hand-rolled administration scripts when schemas change or servers get moved? What happens when someone tries to insert data by hand and forgets that new piece of necessary info?
The eval
command will startup a local instance of the app, much like the get
command does, but then rather than getting a page, it lets you run a command or even series of commands against the running app.
This is really useful for interacting with the app in the same way that it would behave on its own.
In the example app, I can see what data the select
helper returns, just by running
perl -MData::Dumper websocket.pl eval 'print Dumper app->select'
Then again, since you often want to print output or even dumped structures, we have shortcuts for that too.
Use -v
to print the last statement result or -V
to dump that same result via Data::Dumper
.
In that way the previous example can be
perl websocket.pl eval -V 'app->select'
Eval can be handy for initialization too. The app does have a line that will self-initialize, but you could manually initialize the database by doing
perl websocket.pl eval 'app->create_table'
And then maybe inject some data
perl websocket.pl eval 'app->insert( Joel => 30 )'
Or clear it out again
perl websocket.pl eval 'app->empty_table'
Beyond just the convenience of these commands, you actually know that it is using the same mechanisms that your app actually uses, not just the way that you remember your schema/configuration/workflow from the last time you looked at it.
And if it turns out that you really like the eval
command and find yourself administering your app with it, you can even codify those into your own commands.
As an example, I provide a setup command for my Mojolicious-based Galileo CMS.
Testing Candy Too
The other piece of candy that has attracted the eyes of onlookers at my recent events is the wonderful testing provided by Test::Mojo library.
Just like the get
command, testing with Test::Mojo is done by instantiating the app and then making requests of that app via Mojo::UserAgent.
Also like the get
command, returned responses can be inspected using CSS selectors, this time wrapped into Test::More-friendly chainable methods.
When testing apps that use WebSockets, Test::Mojo comes through for you too! It can send and receive WebSocket messages so you aren’t tied to using browser-driven testing for the interaction with the WebSocket.
Check out how wonderfully readable the tests for our example app can be!
Do it for the Candy!
So if Mojolicious’ non-blocking capabilities are more power than you need, or you just aren’t interested in them, you just might want to use it for the other nice features that come along for free!
Then again, if non-blocking does appeal to you, you might want to see the fully non-blocking websocket-capable Golf Scoreboard App I recently put together for a company outing. It was built off the base code from the example app above, and it shows off some of the non-blocking candy too :-)
Hi Joel
I’m amazed how simple and clean this all looks.
Mojolicious Rocks! && Perl Rocks!.
this is a really cool example of Mojolicious, the command line candy and testing are very useful. Thanks for writing this.
Hi Joel,
I’m just getting my head around Mojolicious and found your posts really helpful. One thing I found in the test for the websocket script was that I had to change line 32 from:
$row = Mojo::DOM->new($html)->find(‘tr td’)->text;
to
@row = Mojo::DOM->new($html)->find(‘tr td’)->map(‘text’)->each;
Otherwise I got the following error: Can’t locate object method “text” via package “Mojo::Collection”. I’m not quite sure why I was getting the error, surely the method would be found even if it was returning undef? Are you able to explain what’s happening, sorry if that’s a bit of noob question.
Thanks again for the great posts.