Quotes-O-Matic

TL;DR

Serving interesting quotes through a simple Mojolicious::Lite application is not difficult, enjoy Quotes-O-Matic.

Our journey to transform a thread of tweets into a simple web page providing random wisdom (which we started with post Scrape a Thread of Tweets a few days ago) is coming to an end, because we’re now adding an important piece to the puzzle:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
#!/usr/bin/env perl
use 5.024;
use warnings;
use experimental qw< postderef signatures >;

use Mojo::JSON 'j';
use Mojo::File 'path';
use Mojolicious::Lite;

no warnings qw< experimental::postderef experimental::signatures >;

use constant DEFAULT_FILENAME => 'quotes.json';

my $config = load_config();

get '/' => sub ($c) {
   my $quote = get_quote($config);
   $c->render(
      footer => undef,
      header => undef,
      url => undef,
      title => 'Change Title!',
      template => 'quote',
      $quote->%*,
   );
};

app->start;

sub get_quote ($conf) {
   my $aref = $conf->{quotes};
   return {
      $conf->%*,
      quote => $aref->[rand $aref->@*],
   };
}

sub load_config (@args) {
   my $quotes_path = shift(@args) // get_default_path()
      // die "Can't find a suitable quotes file to serve";
   return j path($quotes_path)->slurp;
}

sub get_default_path {
   for my $dir_candidate ('.', path(__FILE__)->dirname->to_string) {
      my $path = path($dir_candidate)->child(DEFAULT_FILENAME)->to_string;
      return $path if -e $path;
   }
   return;
}

__DATA__

@@ quote.html.ep
%# Starting from boilerplate at
%# https://github.com/lukehaas/HTML5-Minimal-Boilerplate
<!doctype html>
<html lang="en">
   <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <title><%= $title %></title>
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <meta property="og:title" content="<%= $title %>">
      <style type="text/css">
body {
   margin: 0;
   padding: 0;
}
div.wrapper {
   text-size: 10px;
   margin: auto;
   padding: 1em;
   width: 500px;
}
header {
   text-align: center;
}
blockquote#quotation {
   font-family: monospace;
}
main ul {
   text-align: center;
}
main ul li {
   display: inline;
   list-style-type: none;
   padding: 0 0.5em;
}
      </style>
   </head>
   <body>
      <div class="wrapper">
         <header><h1><%= $header // $title %></h1></header>
         <main>
            <blockquote id="quotation"><%= $quote->{text} %></blockquote>
            <ul id="further">
            <% if (defined $quote->{url}) { %>
               <li><a href="<%= $quote->{url} %>">original</a></li>
            <% } %>
            <% if (defined $url) { %>
               <li><a href="<%= $url %>">see also...</a></li>
            <% } %>
               <li><a href="">again</a></li>
            </ul>
         </main>
         <footer>
         </footer>
      </div>
   </body>
</html>

In case GitLab is giving issues, take a look at the local version.

The code pretty much explain itself. We’re relying upon an input file in JSON format (named quotes.json, line 12) which we hunt for either in the current directory, or in the program’s directory (line 45).

The internal structure of the file is the same we described before in the previous post about jq magic. Line 41 does the heavylifting of reading the whole contents of the file (via slurp) and turn that into an anonymous has (calling j on the JSON text).

Selection of a random quote is an old trick in Perl (line 34): generate a random number between 0 (inclusive) and the number of items in an array (exclusive) and use that as an index inside the array itself: it will be turned into an integer and used to extract one item.

The handler for the only supported endpoint can be understood reading through the Mojolicious tutorial.

See you soon!

Nothing more to add… apart wishing you happy hacking!


Comments? Octodon, , GitHub, Reddit, or drop me a line!