view release on metacpan or search on metacpan
# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.010.
Changes
LICENSE
MANIFEST
META.json
META.yml
Makefile.PL
README
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_
devdata/https_mojolicious.io_blog_2018_12_02_automatic-reload-for-rapid-development_
devdata/https_mojolicious.io_blog_2018_12_03_higher-order-promises_
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_
devdata/https_mojolicious.io_blog_2018_12_06_making-a-list-with-yancy_
devdata/https_mojolicious.io_blog_2018_12_07_openapi_
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_
devdata/https_mojolicious.io_blog_2018_12_09_add-a-theme-system-to-your-mojolicious-app_
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_
devdata/https_mojolicious.io_blog_2018_12_13_taking-on-roles_
devdata/https_mojolicious.io_blog_2018_12_14_a-practical-example-of-mojo-dom_
devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_
devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_
devdata/https_mojolicious.io_blog_2018_12_18_a-view-to-a-pod_
devdata/https_mojolicious.io_blog_2018_12_19_you-only-export-twice_
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_
devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_
devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_
devdata/https_mojolicious.io_blog_2018_12_25_special-thanks_
devscripts/update
dist.ini
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_02.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_03.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_04.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_05.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_06.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_07.pm
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_08.pm
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@joelaberger" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/01/welcome-mojoconf-recap/" property="og:url">
<meta content="Day 1: Welcome & MojoConf Recap" property="og:title">
<meta content="The 2018 Mojolicious Advent Calendar begins with a recap of MojoConf 2018." property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/01/welcome-mojoconf-recap/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 1: Welcome & MojoConf Recap - mojolicious.io</title>
<meta content="Joel Berger" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_ view on Meta::CPAN
<time class="date" datetime="2018-12-01">Dec 1, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="View from fjord" src="/blog/2018/12/01/welcome-mojoconf-recap/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Welcome to another year of the Mojolicious Advent Calendar!
2018 has been very good to Mojolicious and I could think of no better way to kick off this calendar than with a recap of the 2018 Nordic Perl Workshop and MojoConf held in Oslo, Norway.</p>
</section>
<section id="section-2">
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_ view on Meta::CPAN
<p>On a personal note, I especially enjoyed this trip because I was able to take a few extra days to visit the West of Norway, home to the iconic fjords.
I visited Bergen and several of its Perlers before taking a fjord tour by boat and train.
It would have been the perfect trip if my bag hadn't decided that it wanted to stay an extra few days in Iceland where I'd had a delayed stop-over.</p>
<p>Still I had an amazing times and saw once in a lifetime sights!
Thanks to Christopher and Jonis and all the people whoe were my companions for the trip!</p>
<h2>Nordic Perl Workshop and MojoConf</h2>
<p>The Oslo Perl Mongers know how to throw Perl events!
This year I actually was there twice, having been once before for the <a href="http://blogs.perl.org/users/joel_berger/2018/04/perl-toolchain-summit-2018.html">Perl Toolchain Summit</a>.</p>
<p>Nordic Perl Workshop is, as its name implies, a regional workshop for Perl enthusiats to gather and talk Perl together.
This year however, it was co-branded as MojoConf 2018; the previous MojoConf was also held in Oslo in 2014.</p>
<p>There were lots of great talks, both on Mojolicious and on Perl in general.
You can <a href="https://www.youtube.com/playlist?list=PL3IiTqgYQ8s0DeRIHW6fXJ4w-BJIMHuDS">see them all</a> on the <a href="https://www.youtube.com/channel/UCgk2wCZr5Rk-cewLTtQA_Fg">NPW Youtube Channel</a>.
For brevity, I'll just highlight a few here.</p>
<h3>Keynote</h3>
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_ view on Meta::CPAN
Because of that fear, I like live demos because it <a href="https://youtu.be/dDH10srLgVc?t=343">engages the audience</a> and makes code-heavy talks more physical.</p>
<p>Of course everyone knows the problems of live demos!
Fear that they might fail in all kinds of embarrasing ways must surely be why more people don't attempt them.
Well this time I hit the most embarrassing of them all.</p>
<p>I realize the problems inherent with live demos and so I do what I can to prevent them: I practice, over and over.
This time, gentle reader, I learned a new lesson:</p>
<blockquote>
<p>Practicing your live demo includes practicing logging in.
<cite>Joel Berger, today</cite></p>
</blockquote>
<p>That's right, I forgot the login credentials to my own demo.</p>
<p>That said, most of the talk still worked.
So beyond that first lesson, here's one more: even experienced speakers mess up, we shrug and move on.
Don't let fear of failure stop you from speaking to groups of like minded colleagues about the work you do.</p>
<p>The talk is about migrating from a Lite app to a full app.
If you find yourself feeling afraid or confused in moving to a full app, or if you read the Mojolicious documentation and wonder how it applies to a full app, give this a watch.
Bonus material about modern Javascript at the end too.</p>
<p><iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen frameborder="0" height="480" src="https://www.youtube.com/embed/ycAXeOKLCGc" width="854"></iframe></p>
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_ view on Meta::CPAN
<p>Right before the lightning talks, call it an hour before, conference co-organizer Marcus Ramberg mentioned that he wished there was at least one more lightning talk to fill out the time.
I had had one more talk idea and even had a vague outline of structure in my head, so on the spur of the moment I told him I'd do it.
The result was a bit rough (of course), and I've since cleaned it up if I should get a chance to do it again, but it was still fun I think.
If you're in the mood and have 5 minutes, what my rant about SAML.</p>
<p><iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen frameborder="0" height="480" src="https://www.youtube.com/embed/xno08-KGJyY" width="854"></iframe></p>
<h3>Finally</h3>
<p>Have some fun, watch the talks from the conference, and if you enjoy what you see, consider coming to the next MojoConf!
I want to thank all of the organizers, the venue <a href="http://www.teknologihuset.no/">Teknologihuset</a> and the conference partner/sponsor <a href="https://www.ksat.no/">KSAT</a>.
I had a great time and I can't wait for the next one!</p>
</section>
<small><p>Original image by Joel Berger.</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/mojoconf/">mojoconf</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/cc767569f5863a7c261991ee5b23f147">
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/03/18/graphql-openapi/index.html" rel="prev"><strong>Previous Article</strong> Mojolicious, OpenAPI - and GraphQL</a></li>
<li class="next"><a href="/blog/2018/12/02/automatic-reload-for-rapid-development/index.html" rel="next"><strong>Next Article</strong> Day 2: Automatic Reload for Rapid Development </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_01_welcome-mojoconf-recap_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_02_automatic-reload-for-rapid-development_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@preaction" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/02/automatic-reload-for-rapid-development/" property="og:url">
<meta content="Day 2: Automatic Reload for Rapid Development" property="og:title">
<meta content="Learn how to reload both the server and client on changes during application development." property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/02/automatic-reload-for-rapid-development/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 2: Automatic Reload for Rapid Development - mojolicious.io</title>
<meta content="Doug Bell" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_02_automatic-reload-for-rapid-development_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_02_automatic-reload-for-rapid-development_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_02_automatic-reload-for-rapid-development_ view on Meta::CPAN
<time class="date" datetime="2018-12-02">Dec 2, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Mojolicious art and reload icon, original artwork by Doug Bell" src="/blog/2018/12/02/automatic-reload-for-rapid-development/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Developing webapps with <a href="http://mojolicious.org">Mojolicious</a> is a lot of fun!
Using <a href="https://mojolicious.org/perldoc/morbo">the <code>morbo</code> server</a> for
development, every change to my webapp causes a restart to load my changes.
This way the next request I make has all my new code!</p>
devdata/https_mojolicious.io_blog_2018_12_02_automatic-reload-for-rapid-development_ view on Meta::CPAN
<p>Part of what makes Mojolicious so much fun is how easy it is. <a href="https://github.com/preaction/Mojolicious-Plugin-AutoReload/blob/v0.003/lib/Mojolicious/Plugin/AutoReload.pm#L56-L92">The entire
plugin is only 40 lines of
code</a>.</p>
<p>And now, with Mojolicious::Plugin::AutoReload, developing in Mojolicious is
just a little easier, and a little more fun!</p>
</section>
<small><p>Original artwork by Doug Bell, released under CC-BY-SA 4.0. It includes
a screenshot of the Mojolicious.org website (fair use), the Mojolicious
logo (CC-BY-SA 4.0), and a
<a href="https://commons.wikimedia.org/wiki/File:Refresh_icon.svg">"reload"</a>
icon from Wikimedia Commons (CC0: Public domain)</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/development/">development</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/4bdc4922059d58a0fcbf8f35652dc254.png">
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/01/welcome-mojoconf-recap/index.html" rel="prev"><strong>Previous Article</strong> Day 1: Welcome & MojoConf Recap</a></li>
<li class="next"><a href="/blog/2018/12/03/higher-order-promises/index.html" rel="next"><strong>Next Article</strong> Day 3: Higher Order Promises </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_02_automatic-reload-for-rapid-development_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_03_higher-order-promises_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@briandfoy_perl" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/03/higher-order-promises/" property="og:url">
<meta content="Day 3: Higher Order Promises" property="og:title">
<meta content="Create new, complex Promises by composing Promises" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/03/higher-order-promises/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 3: Higher Order Promises - mojolicious.io</title>
<meta content="brian d foy" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_03_higher-order-promises_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_03_higher-order-promises_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_03_higher-order-promises_ view on Meta::CPAN
<time class="date" datetime="2018-12-03">Dec 3, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="fractal cauliflower" src="/blog/2018/12/03/higher-order-promises/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<h2>Create new, complex Promises by composing Promises</h2>
<p>Mojolicious 7.49 added an its own implementation of the <a href="https://promisesaplus.com">Promises/A+ specification</a>. mohawk wrote about these in <a href="https://mojolicious.io/blog/2017/12/14/day-14-you-promised-to-call/">Day 14: You Promis...
</section>
<section id="section-2">
<p>A Promise is a structure designed to eliminate nested callbacks (also known as <a href="http://callbackhell.com">"callback hell"</a>). A properly written chain of Promises has a flat structure that easy to follow linear...
<p>A higher-order Promise is one that comprises other Promises and bases its status on them. The <a href="https://metacpan.org/pod/Mojo::Promise::Role::HigherOrder">Mojo::Promise::Role::HigherOrder</a> distribution provides three roles that you can m...
<h3>All</h3>
<p>An <code>all</code> promise resolves only when all of its Promises also resolve. If one of them is rejected, the <code>all</code> Promise is rejected. This means that the overall Promise knows what to do if one is rejected and it doesn't need ...
devdata/https_mojolicious.io_blog_2018_12_03_higher-order-promises_ view on Meta::CPAN
<h2>Conclusion</h2>
<p>It's easy to make new Promises out of smaller ones to represent complex situations. You can combine the Promises that Mojolicious creates for you with your own handmade Promises to do almost anything you like.</p>
</section>
<small><p><a class="external text" href="https://www.flickr.com/photos/joeshlabotnik/3059554662/" rel="nofollow">Image</a> by <a href="https://www.flickr.com/photos/joeshlabotnik/">Joe Shlabotnik</a> <a href="https://creativecommons.org...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/promises/">promises</a>,
<a href="/blog/tag/advent/">advent</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/168427dea0a034607ee7850f3de98ea2.jpg">
</div>
<div class="about">
<h5>brian d foy</h5>
<p><a href="http://www252.pair.com/~comdog/">brian d foy</a> is the author of <a href="https://www.masteringperl.org/">Mastering Perl</a> and <a href="https://www.learningperl6.com/">Learning Perl 6</a>, and the co-author of <...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/02/automatic-reload-for-rapid-development/index.html" rel="prev"><strong>Previous Article</strong> Day 2: Automatic Reload for Rapid Development</a></li>
<li class="next"><a href="/blog/2018/12/04/testing-hooks-and-helpers/index.html" rel="next"><strong>Next Article</strong> Day 4: Testing Hooks and Helpers </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_03_higher-order-promises_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@preaction" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/04/testing-hooks-and-helpers/" property="og:url">
<meta content="Day 4: Testing Hooks and Helpers" property="og:title">
<meta content="How to easily test hooks and helpers using Test::Mojo" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/04/testing-hooks-and-helpers/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 4: Testing Hooks and Helpers - mojolicious.io</title>
<meta content="Doug Bell" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
<time class="date" datetime="2018-12-04">Dec 4, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Scientific calculator on a mathematics textbook" src="/blog/2018/12/04/testing-hooks-and-helpers/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p><a href="https://mojolicious.org/perldoc/Test/Mojo">Test::Mojo</a>, the
<a href="http://mojolicious.org">Mojolicious</a> testing tool, has a lot of ways to
<a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Testing">test routes in web
applications</a>
(even for <a href="https://metacpan.org/pod/Test::Mojo::Role::PSGI">testing in other web
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
<section id="section-2">
<h1>Hooks</h1>
<p>To thoroughly test hooks, I need to find ways to configure my test
cases. I could count on my application to do it, and find the right
routes to test the right behavior. But, that creates larger tests that
integrate different parts and makes test failures harder to debug. What
I want is to isolate the thing I'm testing. The best way to do that is
to create routes that test only what I want to test.</p>
<p>What if I have a hook to log exceptions to a special log file, like so:</p>
<pre><code>#!/usr/bin/env perl
use Mojolicious::Lite;
# Log exceptions to a separate log file
hook after_dispatch => sub {
my ( $c ) = @_;
return unless my $e = $c->stash( 'exception' );
state $path = $c->app->home->child("exception.log");
state $log = Mojo::Log->new( path => $path );
$log->error( $e );
};
app->start;
</code></pre>
<p>To test this, once I've loaded my app and created a Test::Mojo object,
I'm free to add more configuration to my app, including new routes!
These routes can set up exactly the right conditions for my test.</p>
<pre><code># test.pl
use Test::More;
use Test::Mojo;
use Mojo::File qw( path );
my $t = Test::Mojo->new( path( 'myapp.pl' ) );
# Add a route that generates an exception
$t->app->routes->get(
'/test/exception' => sub { die "Exception" },
);
$t->get_ok( '/test/exception' )->status_is( 500 );
my $log_content = path( 'exception.log' )->slurp;
like $log_content, qr{Exception}, 'exception is logged';
done_testing;
</code></pre>
<p>Sure, this is technically testing a route. But, it's useful to know that
I can edit my application after I load it (but before any routes are
exercised). I often spawn additional Test::Mojo objects, sometimes using
the default
<a href="https://mojolicious.org/perldoc/Mojo/HelloWorld">Mojo::HelloWorld</a>
application to test different plugins.</p>
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
test hooks, I can make my own routes for testing. When I need to test
helpers, I can do so by directly calling them. The narrower the scope of
the test, the easier debugging of test failures!</p>
</section>
<small><p>Photo from pexels.com, licensed CC0.</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/testing/">testing</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/4bdc4922059d58a0fcbf8f35652dc254.png">
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/03/higher-order-promises/index.html" rel="prev"><strong>Previous Article</strong> Day 3: Higher Order Promises</a></li>
<li class="next"><a href="/blog/2018/12/05/compound-selectors/index.html" rel="next"><strong>Next Article</strong> Day 5: Compound Selectors are Easier than Regexes </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@briandfoy_perl" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/05/compound-selectors/" property="og:url">
<meta content="Day 5: Compound Selectors are Easier than Regexes" property="og:title">
<meta content="Extract HTML quickly and easily with Mojo::DOM" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/05/compound-selectors/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 5: Compound Selectors are Easier than Regexes - mojolicious.io</title>
<meta content="brian d foy" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
<time class="date" datetime="2018-12-05">Dec 5, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Sled dogs waiting to run" src="/blog/2018/12/05/compound-selectors/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>When people tell me that I can't (they mean shouldn't) parse HTML with a regex, I say "hold my beer". It isn't a matter of skill or attitude so much as convenience. Doing it the right way was not always so e...
</section>
<section id="section-2">
<p>The trick was always to isolate the interesting HTML. I could do that excising all of the data around the interesting parts:</p>
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
<pre><code>use v5.28;
use utf8;
use strict;
use warnings;
use open qw(:std :utf8);
use charnames qw();
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $url = 'https://blog.emojipedia.org/new-unicode-9-emojis/';
my $tx = $ua->get( $url );
die "That didn't work!\n" if $tx->error;
say $tx->result
->dom
->find( 'ul:not( [class] ) li a' )
->map( 'text' )
->map( sub {
my $c = substr $_, 0, 1;
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
<h2>Conclusion</h2>
<p>Even for an old programmer like me, dealing with HTML through CSS Selectors applied by Mojolicious is much easier than what I was doing before (which was dirty and much easier than doing it correctly). With a little skill creating compound selecto...
</section>
<small><p><a class="external text" href="https://www.flickr.com/photos/feuilllu/101083313/in/photolist-9W5xK-SWEcv6-qmMqBb-9W66e-umaBj-7Gkg2a-bnmWDf-jZPHK7-bAgNFi-bnmW3J-Hd8y3-dYNuYc-Hd9o9-22MW7qW-6qZWkL-7yzScF-24W5o6o-bBNUMi-5QPxcD-boz...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/promises/">promises</a>,
<a href="/blog/tag/advent/">advent</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/168427dea0a034607ee7850f3de98ea2.jpg">
</div>
<div class="about">
<h5>brian d foy</h5>
<p><a href="http://www252.pair.com/~comdog/">brian d foy</a> is the author of <a href="https://www.masteringperl.org/">Mastering Perl</a> and <a href="https://www.learningperl6.com/">Learning Perl 6</a>, and the co-author of <...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/04/testing-hooks-and-helpers/index.html" rel="prev"><strong>Previous Article</strong> Day 4: Testing Hooks and Helpers</a></li>
<li class="next"><a href="/blog/2018/12/06/making-a-list-with-yancy/index.html" rel="next"><strong>Next Article</strong> Day 6: Making A List with Yancy </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_06_making-a-list-with-yancy_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@preaction" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/06/making-a-list-with-yancy/" property="og:url">
<meta content="Day 6: Making A List with Yancy" property="og:title">
<meta content="Santa's list building just got easier!" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/06/making-a-list-with-yancy/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 6: Making A List with Yancy - mojolicious.io</title>
<meta content="Doug Bell" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_06_making-a-list-with-yancy_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_06_making-a-list-with-yancy_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_06_making-a-list-with-yancy_ view on Meta::CPAN
<time class="date" datetime="2018-12-06">Dec 6, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Santa making a list" src="/blog/2018/12/06/making-a-list-with-yancy/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>In these modern times, with billions of people in the world, Santa needs a
modern system to keep track of his naughty/nice list. Lucky for Santa, modern
Perl has a modern web framework, <a href="http://mojolicious.org">Mojolicious</a>.</p>
</section>
devdata/https_mojolicious.io_blog_2018_12_06_making-a-list-with-yancy_ view on Meta::CPAN
background" src="success.png"></p>
<p>Another successful Xmas, powered by <a href="http://mojolicious.org">Mojolicious</a>!</p>
</section>
<small><p><a href="https://pxhere.com/en/photo/1263707">Banner image</a> CC0 Public Domain</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/yancy/">yancy</a>,
<a href="/blog/tag/example/">example</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/4bdc4922059d58a0fcbf8f35652dc254.png">
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/05/compound-selectors/index.html" rel="prev"><strong>Previous Article</strong> Day 5: Compound Selectors are Easier than Regexes</a></li>
<li class="next"><a href="/blog/2018/12/07/openapi/index.html" rel="next"><strong>Next Article</strong> Day 7: MetaCPAN, Mojolicious and OpenAPI </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_06_making-a-list-with-yancy_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_07_openapi_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@ssoriche" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/07/openapi/" property="og:url">
<meta content="Day 7: MetaCPAN, Mojolicious and OpenAPI" property="og:title">
<meta content="Overview of how OpenAPI was integrated into MetaCPAN with Mojolicious." property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/07/openapi/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 7: MetaCPAN, Mojolicious and OpenAPI - mojolicious.io</title>
<meta content="Shawn Sorichetti" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_07_openapi_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_07_openapi_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_07_openapi_ view on Meta::CPAN
<time class="date" datetime="2018-12-07">Dec 7, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Contract signing" src="/blog/2018/12/07/openapi/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>During this years <a href="http://www.olafalders.com/2018/11/21/metahack-3-wrap-report/">meta::hack 3</a>, I was extremely fortunate to work with <a href="https://twitter.com/joelaberger">Joel Berger</a> on integrating/documentin...
<h2>What is it?</h2>
<p>OpenAPI is a specification for designing, documenting, validating and driving your RESTful API. It can be used to provide documentation to an existing API, or when creating a new one.</p>
devdata/https_mojolicious.io_blog_2018_12_07_openapi_ view on Meta::CPAN
<p>The <a href="https://github.com/OAI/OpenAPI-Specification">OpenAPI Specification repository</a> includes full documentation and many examples of varying levels of details.</p>
<p>The <a href="https://openapi-map.apihandyman.io">OpenAPI Map</a> is an interactive site to aid in working with the OpenAPI Specification.</p>
</section>
<small><p>Photo by <a href="https://unsplash.com/photos/GJao3ZTX9gU">Cytonn Photography on Unsplash</a></p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/development/">development</a>,
<a href="/blog/tag/openapi/">openapi</a>,
<a href="/blog/tag/api/">api</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/b6d0ff68c2e0d081aba1a94e0f413e8c">
</div>
<div class="about">
<h5>Shawn Sorichetti</h5>
<p>Shawn is a long time Perl developer, with a tendency toward infrastructure, tooling, databases and devops.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/06/making-a-list-with-yancy/index.html" rel="prev"><strong>Previous Article</strong> Day 6: Making A List with Yancy</a></li>
<li class="next"><a href="/blog/2018/12/08/authenticating-with-ldap/index.html" rel="next"><strong>Next Article</strong> Day 8: Authenticating with LDAP </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_07_openapi_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="https://mojolicious.io/blog/2018/12/08/authenticating-with-ldap/" property="og:url">
<meta content="Day 8: Authenticating with LDAP" property="og:title">
<meta content="Learn how to add LDAP authentication to a Mojolicious full app" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/08/authenticating-with-ldap/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 8: Authenticating with LDAP - mojolicious.io</title>
<meta content="Boyd Duffee" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
<time class="date" datetime="2018-12-08">Dec 8, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Who goes there?" src="/blog/2018/12/08/authenticating-with-ldap/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>There are still quite a few people using LDAP in production,
but for those who are new to it,
LDAP is a directory with a tree-structure that's optimised for very fast lookups.
It used to be very common as a centralised authentication system
and if you're using Active Directory, you're using LDAP (mostly).
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
<h3>Route - lib/MyApp.pm</h3>
<p>First off, a confession. I never really got into Lite Apps.
I know it's <a href="https://www.youtube.com/watch?v=ycAXeOKLCGc">easy</a>
to <a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Growing">grow them into Full Apps</a>,
but I was under pressure to crank out a solution when I started and never got back to it.
The result is that this post is about authenticating a <strong>Full App</strong> and isn't as
svelte as the other posts talking about their Lite apps.</p>
<p>Jumping straight in, let's assume that you already have a Login page
in your templates and it has a form which posts data to <code>/login</code>.
If you've got a route like this</p>
<pre><code>$r->post('/login')->name('do_login')->to('Secure#on_user_login');
</code></pre>
<p>to send the credentials to your controller. Or if you're cool with
<a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Routing#Named-routes">named routes</a>,
your template might include this line</p>
<pre><code><form action="<%= url_for 'do_login' %>" method="POST">
</code></pre>
<p>Pro tip: You can even simplify it to</p>
<pre><code>%= form_for 'do_login'
</code></pre>
<p>which does it all for you including the <code>method</code> if the route only handles <code>POST</code>.</p>
<h3>Controller - lib/MyApp/Controller/Secure.pm</h3>
<p>Let's get started by cribbing from the
<a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Cookbook#Basic-authentication1">Mojolicious Cookbook</a>.</p>
<pre><code>package MyApp::Controller::Secure;
use Mojo::Base 'Mojolicious::Controller';
sub on_user_login {
my $self = shift;
my $username = $self->param('username');
my $password = $self->param('password');
if (check_credentials($username, $password)) {
$self->render(text => 'Hello Bender!');
}
else {
$self->render(
text => '<h2>Login failed</h2><a href="/login">Try again</a>',
format => 'html',
status => 401
);
}
}
sub check_credentials {
my ($username, $password) = @_;
return $username eq 'Bender' && $password eq 'rocks';
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
</code></pre>
<h2>Storing passwords - MojoX::Auth::Simple</h2>
<p>We can agree that hard-coding usernames and passwords is not sustainable.
If you can connect to a database, any database that your Perl
<a href="https://metacpan.org/pod/DBI">DBI</a> module can connect to,
then you might think that
<a href="https://metacpan.org/pod/MojoX::Auth::Simple">MojoX::Auth::Simple</a>
will solve your problems. Further reading will tell you that it only
provides the helper methods <code>log_in</code>, <code>is_logged_in</code> and <code>log_out</code>
which are useful for everything around the authentication, but not the
authentication itself. But, since you're using a database now, you
could change the <code>check_credentials</code> to something better than this
(wot was cooked up on a Friday afternoon and not tested)</p>
<pre><code>sub check_credentials {
my ($username, $password) = @_;
my $statement = <<'SQL'; # NO! Don't do this!
SELECT username FROM user_passwd
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
return password_verify($password, $encoded);
}
</code></pre>
<p><a href="https://metacpan.org/pod/Mojolicious::Plugin::Scrypt">Mojolicious::Plugin::Scrypt</a>
will use the Scrypt algorithm,
but can also use Argon2 (which was recommended to me at LPW), Bcrypt and more.
So, assuming that you've stored your password with
<code>my $encoded = $app->scrypt($password);</code>
the <code>on_user_login</code> sub becomes</p>
<pre><code>sub check_credentials {
my ($username, $password) = @_;
my $statement = 'SELECT password FROM user_passwd WHERE username = ?';
my $sth = $dbh->prepare($statement);
$sth->execute($username) or return;
my ($encoded) = $sth->fetchrow_array();
$sth->finish();
# WAIT! where did $self come from
return $self->scrypt_verify($password, $encoded);
}
</code></pre>
<p>Oh, dear. The above crashes because of a design decision made early on in the writing process.
I invoked <code>check_credentials</code> as a plain sub, not the method of an object.
Using a Plugin depends on having the controller available, so the following changes are necessary.</p>
<pre><code>sub on_user_login {
my $self = shift;
...
if ($self->check_credentials($username, $password)) {
...
}
sub check_credentials {
my ($self, $username, $password) = @_;
...
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
my $message = $ldap->bind( $base_DN );
my $search = $ldap->search( base => $base_DN,
filter => join('=', $user_attr, $username),
attrs => [$user_id],
);
my $user_id = $search->pop_entry();
return unless $user_id; # does this user exist in LDAP?
# this is where we check the password
my $login = $ldap->bind( $user_id, password => $password );
# return 1 on success, 0 on failure with the ternary operator
return $login->code == LDAP_INVALID_CREDENTIALS ? 0
: 1;
}
</code></pre>
<p>where you have a file <code>ldap_config.yml</code> in the top-level directory that looks a little like</p>
<pre><code># config values for connecting to LDAP
server: ldap.example.com
baseDN: dc=users,dc=example,dc=com
username: userid
id: dn
</code></pre>
<p>where the values on the right match the attributes in your LDAP schema.</p>
<p>Just making the logic clear in the last step, I've imported a constant
from Net::LDAP called <code>LDAP_INVALID_CREDENTIALS</code> and I use that to check
against the result from the server.</p>
<pre><code>use Net::LDAP qw/LDAP_INVALID_CREDENTIALS/;
...
return ($login->code == LDAP_INVALID_CREDENTIALS) ? 0 : 1;
}
</code></pre>
<p>The logic is a little back to front with the ternary operator, but
if the code I get from the server is <code>LDAP_INVALID_CREDENTIALS</code>
then I return <code>0</code>, a fail, otherwise I return <code>1</code>,
which is a true value for the <code>if</code> in the body of the <code>on_user_login</code>
function.</p>
<p>Yes, you're right once again. I probably should be using
<a href="https://metacpan.org/pod/Mojolicious::Plugin::Config">Mojolicious::Plugin::Config</a>
to handle config files. It's on my TODO list.</p>
<h2>Sessions</h2>
<p>Want more power managing sessions? Well then, you want
<a href="https://metacpan.org/pod/MojoX::Session">MojoX::Session</a>
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
You can force the session to match on IP address to hinder session hijacking.
or add more data to the session cookie.</p>
<p>It works well with
<a href="https://metacpan.org/pod/MojoX::Auth::Simple">MojoX::Auth::Simple</a>.
The module documentation page gives you a great example.
You just have to ensure that the name given to
<a href="https://mojolicious.org/perldoc/Mojolicious/Controller#url_for">url_for</a> in</p>
<pre><code><% } else { %>
<div>Not logged in; <form action="<%= url_for 'login' %>" method="POST">
<input type="submit" value="Login"></form></div>
<% } %>
</code></pre>
<p>(here it's <em>login</em>) matches the name you used in your route</p>
<pre><code>$r->post('/login')->name('do_login')->to('Secure#on_user_login');
</code></pre>
<p>which I named <em>do_login</em>. Using
<a href="https://mojolicious.io/blog/2017/12/03/day-3-using-named-routes/">named routes</a>
gives you the flexibility of changing URLs without much hassle.</p>
<h2>Where next?</h2>
<p>I go through the whole process of authenticating and maintaining sessions at my
<a href="https://github.com/duffee/Mojolicious_session_example">Mojolicious session tutorial</a>
which will be getting some updates in the New Year to reflect what I've learned.
Contributions welcome!</p>
</section>
<small><p><a href="https://www.flickr.com/photos/maxlfly/1834725880/">Image</a> by <a href="https://www.flickr.com/people/85105517@N00">Alex Grech</a> <a href="https://creativecommons.org/licenses/by/2.0" title="Creative Commons Attribu...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/ldap/">LDAP</a>,
<a href="/blog/tag/authentication/">authentication</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="/static/duffee.jpg">
</div>
<div class="about">
<h5>Boyd Duffee</h5>
<p>Boyd Duffee has been hanging around the <a href="https://metacpan.org/author/DUFFEE">edges</a> of the Perl ecosystem for many moons, picking up new bits of shiny to make SysAdmining more interesting. He's interested in...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/07/openapi/index.html" rel="prev"><strong>Previous Article</strong> Day 7: MetaCPAN, Mojolicious and OpenAPI</a></li>
<li class="next"><a href="/blog/2018/12/09/add-a-theme-system-to-your-mojolicious-app/index.html" rel="next"><strong>Next Article</strong> Day 9: Add a theme system to your Mojolicious app </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_08_authenticating-with-ldap_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_09_add-a-theme-system-to-your-mojolicious-app_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="https://mojolicious.io/blog/2018/12/09/add-a-theme-system-to-your-mojolicious-app/" property="og:url">
<meta content="Day 9: Add a theme system to your Mojolicious app" property="og:title">
<meta content="https://mojolicious.io/blog/2018/12/09/add-a-theme-system-to-your-mojolicious-app/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 9: Add a theme system to your Mojolicious app - mojolicious.io</title>
<meta content="Luc Didry" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_09_add-a-theme-system-to-your-mojolicious-app_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_09_add-a-theme-system-to-your-mojolicious-app_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_09_add-a-theme-system-to-your-mojolicious-app_ view on Meta::CPAN
<time class="date" datetime="2018-12-09">Dec 9, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Four lines of paint drawn on a roller, in green, red, orange and blue" src="/blog/2018/12/09/add-a-theme-system-to-your-mojolicious-app/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>You wrote an awesome Mojolicious app, and people use it.
Marvellous!
But users may want to modify the theme of your app: change the logo, use another CSS framework, such sort of things.</p>
<p>Modifying the theme of a Mojolicious app is quite easy: add, modify or delete things in <code>public</code> and <code>templates</code>.
But all those direct modifications may not survive on update of the app: they will simply be erased by the files of the new version.</p>
<p>Let's see how we can provide a way to have a theme system in a Mojolicious application, that allows users to have a custom theme without pain and without risk of losing it on updates.</p>
</section>
<section id="section-2">
<h2>A fresh application</h2>
devdata/https_mojolicious.io_blog_2018_12_09_add-a-theme-system-to-your-mojolicious-app_ view on Meta::CPAN
Users will now be able to change the style of it without fearing losing their changes on updates (though they will need to check the changes they made in case the default theme changed a lot).</p>
<p>You may even provides different themes yourself, like I did for my <a href="https://framagit.org/fiat-tux/hat-softwares/lstu">URL-shortening app, Lstu</a>àðÂÂÂ</p>
</section>
<small><p><a href="https://unsplash.com/photos/46juD4zY1XA">Photo</a> by <a href="https://unsplash.com/@davidpisnoy">David Pisnoy</a>, <a href="https://unsplash.com/license">Unsplash license</a> (quite similar to public domain)</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/theme/">theme</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="/static/ldidry.png">
</div>
<div class="about">
<h5>Luc Didry</h5>
<p>Luc Didry is a sysAdmin and Perl developer, in love with Perl since he discovered it 10 years ago, and a Mojolicious enthusiast.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/08/authenticating-with-ldap/index.html" rel="prev"><strong>Previous Article</strong> Day 8: Authenticating with LDAP</a></li>
<li class="next"><a href="/blog/2018/12/10/minion-stands-alone/index.html" rel="next"><strong>Next Article</strong> Day 10: Minion Stands Alone </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_09_add-a-theme-system-to-your-mojolicious-app_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@preaction" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/10/minion-stands-alone/" property="og:url">
<meta content="Day 10: Minion Stands Alone" property="og:title">
<meta content="Learn how to use the Minion job queue without needing a Mojolicious web application" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/10/minion-stands-alone/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 10: Minion Stands Alone - mojolicious.io</title>
<meta content="Doug Bell" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_ view on Meta::CPAN
<time class="date" datetime="2018-12-10">Dec 10, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Minion logo in front of a faded Mojolicious cloud, original artwork by Doug Bell" src="/blog/2018/12/10/minion-stands-alone/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>The <a href="https://mojolicious.org/perldoc/Minion">Minion job queue</a> is an
incredibly useful tool, but sometimes I need to use it for non-web
projects. So, how can I use Minion without needing
a <a href="http://mojolicious.org">Mojolicious</a> web application?</p>
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_ view on Meta::CPAN
plugin Minion => {
SQLite => 'sqlite:' . app->home->child('minion.db'),
};
app->minion->add_task(
check_url => sub( $job, $url ) {
my $start = time;
my $tx = $job->app->ua->head( $url );
my $elapsed = time - $start;
$job->app->log->info(
sprintf 'Fetching %s took %.3f seconds', $url, $elapsed
);
# If there's an error loading the web page, fail the job
if ( $tx->error ) {
$job->app->log->error(
sprintf 'Error loading URL (%s): %s (%s)',
$url, @{ $tx->error }{qw( code message )},
);
return $job->fail(
sprintf '%s: %s', @{ $tx->error }{qw( code message )}
);
}
$job->finish( $elapsed );
},
);
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_ view on Meta::CPAN
<p>Once the worker starts up, it will immediately begin processing the jobs
I told it to run.</p>
<p>And that's it! I'm using Minion without a Mojolicious
web application. View the source of the <a href="minion.pl">Minion app</a> and the
<a href="enqueue.pl">enqueue.pl script</a>.</p>
</section>
<small><p>Original artwork by Doug Bell, released under CC-BY-SA 4.0. It includes
a screenshot of the Mojolicious.org website (fair use), the Mojolicious
logo (CC-BY-SA 4.0), and the Minion logo (CC-BY-SA 4.0)</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/minion/">minion</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/4bdc4922059d58a0fcbf8f35652dc254.png">
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/09/add-a-theme-system-to-your-mojolicious-app/index.html" rel="prev"><strong>Previous Article</strong> Day 9: Add a theme system to your Mojolicious app</a></li>
<li class="next"><a href="/blog/2018/12/11/who-watches-the-minions/index.html" rel="next"><strong>Next Article</strong> Day 11: Who Watches The Minions </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@preaction" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/11/who-watches-the-minions/" property="og:url">
<meta content="Day 11: Who Watches The Minions" property="og:title">
<meta content="Check the status of a Minion job queue using commands and the Minion::Admin UI" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/11/who-watches-the-minions/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 11: Who Watches The Minions - mojolicious.io</title>
<meta content="Doug Bell" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_ view on Meta::CPAN
<time class="date" datetime="2018-12-11">Dec 11, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Minion logo in the middle of binocular circles, original artwork by Doug Bell" src="/blog/2018/12/11/who-watches-the-minions/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Now that I have a <a href="https://mojolicious.org/perldoc/Minion">Minion job
queue</a>, I need to take care of
it properly. Are the workers working (have they seized the means of
production)? Are jobs completing successfully? Are there any errors?
What are they?</p>
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_ view on Meta::CPAN
to view the details of that job (the same as the <code>job</code> command shows).</p>
<p><img alt="A web browser showing the details of a single Minion job as
JSON" src="03-job-details.png"></p>
<p>The Minion Admin UI is a great addition to a great tool! <a href="minion.pl">View the entire
source of the Minion app</a></p>
</section>
<small><p>Original artwork by Doug Bell, released under CC-BY-SA 4.0. It includes
the Minion logo (CC-BY-SA 4.0)</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/minion/">minion</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/4bdc4922059d58a0fcbf8f35652dc254.png">
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/10/minion-stands-alone/index.html" rel="prev"><strong>Previous Article</strong> Day 10: Minion Stands Alone</a></li>
<li class="next"><a href="/blog/2018/12/12/dancer-and-minion/index.html" rel="next"><strong>Next Article</strong> Day 12: Using Minion in Dancer Apps </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@cromedome" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/12/dancer-and-minion/" property="og:url">
<meta content="Day 12: Using Minion in Dancer Apps" property="og:title">
<meta content="Overview of how to use Minion from within a Dancer application." property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/12/dancer-and-minion/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 12: Using Minion in Dancer Apps - mojolicious.io</title>
<meta content="Jason Crome" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
<time class="date" datetime="2018-12-12">Dec 12, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Stylistic photograph of Disney-style minion toys" src="/blog/2018/12/12/dancer-and-minion/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>At <code>$work</code>, we have built an API with <a href="https://metacpan.org/pod/Dancer">Dancer</a> that generates PDF documents and XML files. This API is a critical component of an insurance enrollment system: PDFs are genera...
immediately, and the XML is delivered to the carrier as soon as it becomes available. Since the XML often takes a significant amount of time to generate, the job is generated in the background so as not to tie up the
application server for an extended amount of time. When this was done, a homegrown process management system was developed, and works by <code>fork()</code>ing a process, tracking its pid, and hoping we can later successfully
reap the completed process.</p>
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
use MyJob::JobQueue;
use MyJob::Log4p;
use MyJob::Util::Logger;
use MyJob::Util::SysTools qw(get_hostname);
my $config = MyJob::Config->new->config;
my $hostconfig = get_hostconfig();
my $minion = MyJob::JobQueue->new;
my $worker = $minion->runner->worker;
my $log_eng = MyJob::Log4p->new({ logger_name => "Minion" });
my $logger = MyJob::Util::Logger->new->logger($log_eng);
</code></pre>
<p>The above is mostly typical boilerplate for us. Read our configuration, and create a logger the worker can use.</p>
<p>Next, when a job is dequeued, we want to log that the worker picked up a job (needed for auditing purposes) and we alter the process name so if a process hangs, we know what that process
was attempting to run. If an unchecked exception occurs in a job, the worker will catch it and log it for us:</p>
<pre><code>$worker->on( dequeue => sub( $worker, $job ) {
my $id = $job->id;
my $notes = $job->info->{ notes };
my $title = $notes->{ title };
my $guid = $notes->{ guid };
$job->on( spawn => sub( $job, $pid ) {
$0 = "$title $guid";
$logger->info( "$title: Created child process $pid for job $id by parent $$ - $guid");
});
$job->on( failed => sub( $job, $error ) {
chomp $error;
$logger->error( $error );
});
});
</code></pre>
<p>To help us for future capacity planning, we want our workers to tell us if they are running at peak capacity, so log when this event occurs:</p>
<pre><code>$worker->on( busy => sub( $worker ) {
my $max = $worker->status->{ jobs };
$logger->log( "$0: Running at capacity (performing $max jobs)." );
});
</code></pre>
<p>Now, we apply the configuration (read below) to the worker. When the worker starts, it tells us information about how it was configured (this was really useful during development):</p>
<pre><code>my $max_jobs = $hostconfig->{ max_children };
my @queues = @{ $hostconfig->{ queues }};
if( $minion->has_invalid_queues( @queues ) ){
print "Invalid job queues specified: " . join( ',', $minion->get_invalid_queues( @queues ) );
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
if( exists $minion_config->{ $hostname }) {
return $minion_config->{ $hostname };
} else {
return $minion_config->{ default };
}
}
</code></pre>
<h2>Monitoring the Workers</h2>
<p>Our Minion dashboard was virtually identical to the one that @preaction posted in <a href="https://mojolicious.io/blog/2018/12/11/who-watches-the-minions/#section-2">Who Watches the Minions?</a>.
If you'd like to know more, I highly recommend reading his article.</p>
<h2>Outcome</h2>
<p>Within about a two-week timespan, we went from having zero practical knowledge of Minion to having things up and running. We've made some refinements and improvements along the way, but the quick turnaround
is a true testament to the simplicity of working with Minion.</p>
<p>We now have all the necessary pieces in place to scale our XML rendering both horizontally and vertically: thanks to Minion, we can easily run XML jobs across multiple boxes, and can more efficiently run
more jobs concurrently on the same hardware as before. This setup allows us to grow as quickly as our customer base does.</p>
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
<li><a href="https://metacpan.org/pod/Dancer2">Dancer2</a></li>
<li><a href="https://metacpan.org/pod/Minion">Minion</a></li>
</ul>
</section>
<small><p>Banner image: <a href="https://www.flickr.com/photos/enerva/9068467267">One Eyed Minion</a> by <a href="https://www.flickr.com/photos/enerva/">Sonny Abesamis</a> licensed <a href="https://creativecommons.org/licenses/by/2.0/">...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/development/">development</a>,
<a href="/blog/tag/dancer/">dancer</a>,
<a href="/blog/tag/minion/">minion</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="http://0.gravatar.com/avatar/fcf781200bb62080ccf106bac3d24937">
</div>
<div class="about">
<h5>Jason Crome</h5>
<p>Jason is a Dancer Core Team member, pilot, and hockey-player-wannabe. He likes hacking Perl for fun and profit, but neither piña coladas nor getting caught in the rain.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/11/who-watches-the-minions/index.html" rel="prev"><strong>Previous Article</strong> Day 11: Who Watches The Minions</a></li>
<li class="next"><a href="/blog/2018/12/13/taking-on-roles/index.html" rel="next"><strong>Next Article</strong> Day 13: Taking on Roles </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_13_taking-on-roles_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@briandfoy_perl" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/13/taking-on-roles/" property="og:url">
<meta content="Day 13: Taking on Roles" property="og:title">
<meta content="Need a little extra in your class?" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/13/taking-on-roles/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 13: Taking on Roles - mojolicious.io</title>
<meta content="brian d foy" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_13_taking-on-roles_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_13_taking-on-roles_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_13_taking-on-roles_ view on Meta::CPAN
<time class="date" datetime="2018-12-13">Dec 13, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Elgin Theater" src="/blog/2018/12/13/taking-on-roles/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>In my previous Advent article, I created <a href="/blog/2018/12/03/higher-order-promises/">higher-order promises</a> and showed you how to use them. I didn't show you the magic of how they work. Now I'll develop another e...
</section>
<section id="section-2">
<p>There are times that I want <a href="https://mojolicious.org/perldoc/Mojo/File">Mojo::File</a> to act a bit differently than it does. Often I have a path where I want to combine only the basename with a different directory. I end...
<pre><code>use Mojo::File qw(path);
my $path = Mojo::File->new( '/Users/brian/bin/interesting.txt' );
my $dir = Mojo::File->new( '/usr/local/bin' );
my $new_path = $dir->child( $path->basename );
devdata/https_mojolicious.io_blog_2018_12_13_taking-on-roles_ view on Meta::CPAN
}
my $file = Mojo::File
->with_roles( '+MyUtils' )
->new(shift);
say $file->sha1;
say $file->md5;
</code></pre>
<p>You can read more about roles in Joel Berger's 2017 Mojolicious Advent Calendar entry <a href="https://mojolicious.io/blog/2017/12/13/day-13-more-about-roles/">Day 13: More About Roles</a>. Curiously that was on Day 13 too, although I don'...
</section>
<small><p><a class="external text" href="https://www.flickr.com/photos/eskimo_jo/27387510917/in/photolist-HJ99Q6-fziGbA-fypQyz-7pCEK2-e6kG1-8NxgJh-9gKfaE-eEhB2w-9wc7yk-fwnRyf-62b1R6-27u47Nh-4ohfrN-9o2vut-2xyVmv-2yas82-ctV3fq-nBYJN4-q6zk...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/roles/">roles</a>,
<a href="/blog/tag/advent/">advent</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/168427dea0a034607ee7850f3de98ea2.jpg">
</div>
<div class="about">
<h5>brian d foy</h5>
<p><a href="http://www252.pair.com/~comdog/">brian d foy</a> is the author of <a href="https://www.masteringperl.org/">Mastering Perl</a> and <a href="https://www.learningperl6.com/">Learning Perl 6</a>, and the co-author of <...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/12/dancer-and-minion/index.html" rel="prev"><strong>Previous Article</strong> Day 12: Using Minion in Dancer Apps</a></li>
<li class="next"><a href="/blog/2018/12/14/a-practical-example-of-mojo-dom/index.html" rel="next"><strong>Next Article</strong> Day 14: A Practical Example of Mojo::DOM </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_13_taking-on-roles_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_14_a-practical-example-of-mojo-dom_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="https://mojolicious.io/blog/2018/12/14/a-practical-example-of-mojo-dom/" property="og:url">
<meta content="Day 14: A Practical Example of Mojo::DOM" property="og:title">
<meta content="Use Mojo::DOM to parse XML" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/14/a-practical-example-of-mojo-dom/banner.png" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 14: A Practical Example of Mojo::DOM - mojolicious.io</title>
<meta content="Chris Seigman" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_14_a-practical-example-of-mojo-dom_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_14_a-practical-example-of-mojo-dom_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_14_a-practical-example-of-mojo-dom_ view on Meta::CPAN
<time class="date" datetime="2018-12-14">Dec 14, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="A typical industrial platform model overlaid with a laser scan" src="/blog/2018/12/14/a-practical-example-of-mojo-dom/banner.png">
</div>
<div class="post-content">
<section id="section-1">
<p>With recent versions of Mojolicious, <a href="https://mojolicious.org/perldoc/Mojo/DOM">Mojo::DOM</a> gained a lot of power that I have been excited to try, but haven't had the time for. Recently, I had a problem at my real ...
</section>
<section id="section-2">
<h2>The task - simple, but tedious.</h2>
devdata/https_mojolicious.io_blog_2018_12_14_a-practical-example-of-mojo-dom_ view on Meta::CPAN
<p>This is just one example of how I have used Mojolicious in my day job. Sometimes, existing software doesn't do what you want, or does it in a format that's not useful - problems that can be solved with the many tools Mojolicious provides....
<p>My next project idea is to rebuild a reporting tool I wrote for Material Take Offs (MTOs) to work with Tekla, which our engineers loved with our old modeling software - and I'm sure I will continue to find good uses for Mojolicious well into t...
</section>
<small><p>Original screenshots by maschine, released under CC-BY-SA 4.0.</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/xml/">xml</a>,
<a href="/blog/tag/non-web/">non-web</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="/static/seigman.png">
</div>
<div class="about">
<h5>Chris Seigman (maschine)</h5>
<p>Chris has been using Perl to develop websites and other tools for more than 20 years, but mostly as a hobby. Since discovering Mojolicious, his Perl skills have improved dramatically, and he has expanded beyond simple CGI ...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/13/taking-on-roles/index.html" rel="prev"><strong>Previous Article</strong> Day 13: Taking on Roles</a></li>
<li class="next"><a href="/blog/2018/12/15/practical-web-content-munging/index.html" rel="next"><strong>Next Article</strong> Day 15: Practical Web Content Munging </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_14_a-practical-example-of-mojo-dom_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@swelljoe" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/15/practical-web-content-munging/" property="og:url">
<meta content="Day 15: Practical Web Content Munging" property="og:title">
<meta content="Working with ugly old websites using Mojo::UserAgent and Mojo::DOM" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/15/practical-web-content-munging/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 15: Practical Web Content Munging - mojolicious.io</title>
<meta content="Joe Cooper" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_ view on Meta::CPAN
<time class="date" datetime="2018-12-15">Dec 15, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="An eyeball of alarming size" src="/blog/2018/12/15/practical-web-content-munging/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Following brian d foy's great <a href="https://mojolicious.io/blog/2018/12/05/compound-selectors/">write-up of using Mojo::DOM selectors from Day 5</a>, I thought it'd be fun to talk about some website migration scripts I...
<h2>From Static Site to Static Site Generator</h2>
<p>The problem I set out to solve was taking an old static website that was once hosted on SourceForge.net and migrating it to an exciting new...um...static website. But, this time, it'll be a modern take on a static website. Instead of editing H...
</section>
<section id="section-2">
<p>Hugo, like most modern static site generators, expects content to be in Markdown format with some metadata at the top of the file. I want to convert our crusty old HTML, as you'll see an example of below, into something that ...
<pre><code>---
title: "Frobnitz 3.141593 released"
date: 2016-10-10
description: "This release includes a fog-flavored bauble of three equal sides, providing the restless..."
categories: []
devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_ view on Meta::CPAN
<p>Then, in the here document, I fill in all the metadata, using values from <code>$e</code>, each of which is just a reference to a hash. Then we write it to a file using the <code>spurt</code> method of <a href="https://mojolicious.org/perldoc/Mojo...
<p>In the interest of clarity and brevity (and because it's basic Perl and not Mojo-related) I've left out the loops and building of the data structure that I used when generating metadata. If you want to see it all in one place, with some ug...
</section>
<small><p>Banner image: <a href="https://flic.kr/p/Rqj9Jj">An eyeball looking at Dallas</a> by <a href="https://www.flickr.com/photos/nerdnomad/">Joe Cooper</a> licensed <a href="https://creativecommons.org/licenses/by-nc-sa/2.0/">CC BY...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/css/">css</a>,
<a href="/blog/tag/html/">html</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://s.gravatar.com/avatar/a8081467b81cb4bf3d22248cbb5b44c5">
</div>
<div class="about">
<h5>Joe Cooper</h5>
<p>Joe works on a lot of cranky old Perl, as well as a little bit of friendly modern Perl. Sometimes, he wrangles robots (but not with Perl...yet).</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/14/a-practical-example-of-mojo-dom/index.html" rel="prev"><strong>Previous Article</strong> Day 14: A Practical Example of Mojo::DOM</a></li>
<li class="next"><a href="/blog/2018/12/16/browser-diet/index.html" rel="next"><strong>Next Article</strong> Day 16: A pre-Christmas Diet for Mojolicious - A Children's Story </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_15_practical-web-content-munging_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="https://mojolicious.io/blog/2018/12/16/browser-diet/" property="og:url">
<meta content="Day 16: A pre-Christmas Diet for Mojolicious - A Children's Story" property="og:title">
<meta content="Setting the HTTP CacheControl header for your static files" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/16/browser-diet/squirrel.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 16: A pre-Christmas Diet for Mojolicious - A Children's Story - mojolicious.io</title>
<meta content="Boyd Duffee" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
<time class="date" datetime="2018-12-16">Dec 16, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Too many nuts. I'm gonna need to slim down" src="/blog/2018/12/16/browser-diet/squirrel.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>You've just read
<a href="https://browserdiet.com">How to lose Weight in the Browser</a>
and you want to know to slim down your Mojo app.
Part of that process is preventing the browser from requesting files
that hardly change.
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
<a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Cookbook#Hypnotoad">reverse proxy</a>,
but a popular setup is sitting Hypnotoad behind
<a href="https://www.mind-it.info/2014/09/27/running-hypnotoad-behind-nginx/">Nginx</a>
or Apache/mod_proxy.
Those servers should let you play with the <code>Expires</code> header.
But the Toad didn't <em>quite</em> have what this particular rodent was looking for.</p>
<p><em>An aside</em> - No, I didn't mention
<a href="https://metacpan.org/pod/Plack">Plack</a>.
Maybe if I'm good this year, Santa will
<a href="http://blogs.perl.org/users/aristotle/2018/11/modern-perl-cgi.html">tell me how</a>
I should be using it. Probably something to do with</p>
<pre><code>Plack::Response->header('Expires' => 'Tue, 25 Dec 2018 07:28:00 GMT');
</code></pre>
<p>but I wouldn't know and neither did our narrator.</p>
<h2>... and <em>then</em> there was a <a href="https://mojolicious.org">Unicorn</a></h2>
<p>Well, that was easy. Just use the standard
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
It sets the <code>Control-Cache</code> header for all static files served by Mojolicious.
With the <strong>nut.js</strong> and <strong>nut.css</strong> files in the <code>public</code> directory
(properly <a href="https://www.minifier.org/">minified</a> of course),
they should only be downloaded once and use the cached version until it expires.
The default <strong>max-age</strong> is 30 days and
if you want you can even cache during development with <code>even_in_dev => 1</code>.</p>
<p><img class="pull-right" src="speedtest_before_StaticCache.png"></p>
<p>The magpies in the forest had cluttered the calendar with 3 JavaScript libraries,
3 CSS files and 4 logos. Sure, the biggest and shiniest was only 66 kB
and the whole collection was a paltry 164 kB, but bandwidth is precious in the wilderness.
Before using the StaticCache plugin, the calendar rated a
<strong>92</strong> on Google's PageSpeed Insights.</p>
<p>With the StaticCache plugin loaded</p>
<pre><code>sub startup {
my $self = shift;
$self->plugin('StaticCache' => { even_in_dev => 1 });
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
didn't get in the way of a new idea or two. <a href="https://github.com/duffee/Mojolicious_session_example">Let me
know</a> if I've missed
something.</p>
</section>
<small><p><a href="https://www.flickr.com/photos/55426027@N03/16915881989">Image</a> by <a href="https://www.flickr.com/photos/55426027@N03">Peter G Trimming</a> <a href="https://creativecommons.org/licenses/by/2.0"> CC BY 2.0 </a></p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/caching/">caching</a>,
<a href="/blog/tag/headers/">headers</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="/static/duffee.jpg">
</div>
<div class="about">
<h5>Boyd Duffee</h5>
<p>Boyd Duffee has been hanging around the <a href="https://metacpan.org/author/DUFFEE">edges</a> of the Perl ecosystem for many moons, picking up new bits of shiny to make SysAdmining more interesting. He's interested in...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/15/practical-web-content-munging/index.html" rel="prev"><strong>Previous Article</strong> Day 15: Practical Web Content Munging</a></li>
<li class="next"><a href="/blog/2018/12/17/a-website-for-yancy/index.html" rel="next"><strong>Next Article</strong> Day 17: A Website For Yancy </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_16_browser-diet_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@preaction" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/17/a-website-for-yancy/" property="og:url">
<meta content="Day 17: A Website For Yancy" property="og:title">
<meta content="Building a markdown-based site with Yancy" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/17/a-website-for-yancy/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 17: A Website For Yancy - mojolicious.io</title>
<meta content="Doug Bell" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_ view on Meta::CPAN
<time class="date" datetime="2018-12-17">Dec 17, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Code on a computer screen" src="/blog/2018/12/17/a-website-for-yancy/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>For this year, I decided that Yancy needed a website. Rather than build
a website with a <a href="http://preaction.me/statocles">static site generator like
Statocles</a>, which is so popular these
days, I decided to do something wild and unpredictable: A dynamic
website! Lucky for me, I have the perfect project to easily build
devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_ view on Meta::CPAN
<p>Now I have a basic website! <a href="myapp.pl">Here's the code so far</a>. This is
a good start, but I'll need more if it's going to be useful...</p>
</section>
<small><p>Banner image CC0 Public Domain</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/yancy/">yancy</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/4bdc4922059d58a0fcbf8f35652dc254.png">
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/16/browser-diet/index.html" rel="prev"><strong>Previous Article</strong> Day 16: A pre-Christmas Diet for Mojolicious - A Children's Story</a></li>
<li class="next"><a href="/blog/2018/12/18/a-view-to-a-pod/index.html" rel="next"><strong>Next Article</strong> Day 18: A View To A POD </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_17_a-website-for-yancy_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_18_a-view-to-a-pod_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@preaction" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/18/a-view-to-a-pod/" property="og:url">
<meta content="Day 18: A View To A POD" property="og:title">
<meta content="A new POD viewer plugin for Mojolicious" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/18/a-view-to-a-pod/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 18: A View To A POD - mojolicious.io</title>
<meta content="Doug Bell" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_18_a-view-to-a-pod_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_18_a-view-to-a-pod_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_18_a-view-to-a-pod_ view on Meta::CPAN
<time class="date" datetime="2018-12-18">Dec 18, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Books on a library shelf" src="/blog/2018/12/18/a-view-to-a-pod/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>In order for Yancy to have a good documentation site, it needs to
actually render the documentation. To render Perl documentation in
<a href="http://mojolicious.org">Mojolicious</a>, I can use the
<a href="http://metacpan.org/pod/Mojolicious::Plugin::PODViewer">PODViewer</a>
plugin (a fork of the now-deprecated
devdata/https_mojolicious.io_blog_2018_12_18_a-view-to-a-pod_ view on Meta::CPAN
<p><a href="myapp.pl">Here's the full source</a>. Now that I have a beautiful
website, I just need to deploy the new site to the Internet...</p>
</section>
<small><p>Banner image CC0 Public Domain</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/documentation/">documentation</a>,
<a href="/blog/tag/yancy/">yancy</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/4bdc4922059d58a0fcbf8f35652dc254.png">
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/17/a-website-for-yancy/index.html" rel="prev"><strong>Previous Article</strong> Day 17: A Website For Yancy</a></li>
<li class="next"><a href="/blog/2018/12/19/you-only-export-twice/index.html" rel="next"><strong>Next Article</strong> Day 19: You Only Export Twice </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_18_a-view-to-a-pod_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_19_you-only-export-twice_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@preaction" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/19/you-only-export-twice/" property="og:url">
<meta content="Day 19: You Only Export Twice" property="og:title">
<meta content="Export content for static rendering" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/19/you-only-export-twice/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 19: You Only Export Twice - mojolicious.io</title>
<meta content="Doug Bell" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_19_you-only-export-twice_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_19_you-only-export-twice_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_19_you-only-export-twice_ view on Meta::CPAN
<time class="date" datetime="2018-12-19">Dec 19, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Container ship leaving port" src="/blog/2018/12/19/you-only-export-twice/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>With my Yancy documentation site built, with <a href="/blog/2018/12/17/a-website-for-yancy">a custom landing
page</a> and <a href="/blog/2018/12/18/a-view-to-a-pod">a POD
viewer</a>, I just need to deploy the site. I
could deploy the site using <a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Cookbook#Hypnotoad">hypnotoad, Mojolicious's preforking server with
hot
deployment</a>,
but that would require me to have a server and keep it online. It'd be a lot
better if I could just deploy a <a href="https://pages.github.com">static website to
Github</a> like all the cool people are doing.</p>
<p>But to do that, I'd need to take my dynamic website and turn it into a static
one, and that's impossible! Or is it? Why am I asking me, when I'm the one who
devdata/https_mojolicious.io_blog_2018_12_19_you-only-export-twice_ view on Meta::CPAN
<p>In the future it'd be nice if this command were made into a plugin so that it
could have hooks for customizing the exported content or additional checks for
broken links. If anyone is interested in helping out with this work, let me
know and I can help get them started!</p>
<p>Now, with <a href="http://preaction.me/yancy">the Yancy CMS</a>, <a href="http://metacpan.org/pod/Mojolicious::Plugin::PODViewer">the PODViewer
plugin</a>, and <a href="http://metacpan.org/pod/Mojolicious::Command::export">the
Mojolicious export
command</a>, I've got a
good-looking documentation website for Yancy! <a href="https://github.com/MojoliciousDotIO/mojolicious.io/blob/master/blog/2018/12/19/you-only-export-twice/myapp.pl">View the full, completed
application</a>.</p>
</section>
<small><p>Banner image CC0 Public Domain</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/command/">command</a>,
<a href="/blog/tag/yancy/">yancy</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/4bdc4922059d58a0fcbf8f35652dc254.png">
</div>
<div class="about">
<h5>Doug Bell</h5>
<p>Doug (<a href="http://preaction.me">preaction</a>) is a long time Perl user.
He is the current maintainer of <a href="http://www.cpantesters.org/">CPAN Testers</a> and the author of many <a href="https://metacpan.org/author/PREACTION">CPAN modules</a> including the <a href="http://preaction.me/statocles/">Statocles</a> blog e...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/18/a-view-to-a-pod/index.html" rel="prev"><strong>Previous Article</strong> Day 18: A View To A POD</a></li>
<li class="next"><a href="/blog/2018/12/20/testing-dancer/index.html" rel="next"><strong>Next Article</strong> Day 20: Testing Dancer </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_19_you-only-export-twice_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@joelaberger" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/20/testing-dancer/" property="og:url">
<meta content="Day 20: Testing Dancer" property="og:title">
<meta content="Test your Dancer2 applications with Test::Mojo" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/20/testing-dancer/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 20: Testing Dancer - mojolicious.io</title>
<meta content="Joel Berger" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
<time class="date" datetime="2018-12-20">Dec 20, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Dancers and judges at a dance competition" src="/blog/2018/12/20/testing-dancer/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Authors of Dancer (and other) PSGI applications are probably accustomed to <a href="https://metacpan.org/pod/distribution/Dancer2/lib/Dancer2/Manual.pod#TESTING">testing</a> with <a href="https://metacpan.org/pod/Plack::Test">Pla...
<p>During advent last year, I wrote about <a href="https://mojolicious.org/perldoc/Test/Mojo">Test::Mojo</a>, showing the many easy and (dare I say) fun ways that you can use it to test your Mojolicious applications.
If you missed it, go <a href="https://mojolicious.io/blog/2017/12/09/day-9-the-best-way-to-test/">check it out</a>.</p>
<p>I expect there are at least a few of you out there who read that and think, "I'd love to use that, but I don't use Mojolicious!"; well, you're in luck!
With just a little role to bridge the gap, you can use Test::Mojo to test your PSGI applications too!</p>
</section>
<section id="section-2">
<h2>Mounting PSGI Applications</h2>
<p>Mojolicious itself doesn't use the <a href="https://metacpan.org/pod/PSGI">PSGI</a> protocol, owing to certain features that it doesn't provide and which are necessary for certain asynchronous operations.
That said, you can serve a Mojolicious application on a PSGI server by using <a href="https://mojolicious.org/perldoc/Mojo/Server/PSGI">Mojo::Server::PSGI</a>.
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
<p>While translating between a Mojo app and a PSGI server is core functionality, doing the opposite, translating between a PSGI app and a Mojolicious server (or app, as you'll see) is available as a third party module.
<a href="https://metacpan.org/pod/Mojolicious::Plugin::MountPSGI">Mojolicious::Plugin::MountPSGI</a>, as it's name implies, can mount a PSGI application into a Mojolicious-based one.
To do so, it builds a new, empty Mojolicious application that translates all requests to PSGI environments before dispatching to it as with any <a href="https://mojolicious.org/perldoc/Mojolicious/Plugin/Mount">mount</a>-ed application.</p>
<h2>Testing using Test::Mojo</h2>
<p>Once you can do that, it is trivial to take a PSGI application, wrap it with MountPSGI, and set it as the application for use with Test::Mojo.
Still, to make it even easier, that has all been done for you in <a href="https://metacpan.org/pod/Test::Mojo::Role::PSGI">Test::Mojo::Role::PSGI</a>.</p>
<p>Like any <a href="https://mojolicious.io/blog/2017/12/13/day-13-more-about-roles/">Mojolicious Role</a>, we can use <code>with_roles</code> to create a (mostly anonymous) subclass with the role applied.
You can use the shortcut <code>+</code> to stand in for <code>Test::Mojo::Role::</code>.</p>
<pre><code>use Test::Mojo;
my $class = Test::Mojo->with_roles('+PSGI');
</code></pre>
<p>Then you instantiate that role with the path to the PSGI application, or else the PSGI application itself.</p>
<p>Since you're using roles, which are all about composition, you can also apply other roles that you might <a href="https://metacpan.org/search?q=%22Test%3A%3AMojo%3A%3ARole%22">find on CPAN</a>.</p>
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
<dd><% name %></dd>
</dl>
</code></pre>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl">dl</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt">dt</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd">dd</a> tags...
The HTML I've built, while nice for display isn't necessarily nice for querying programmatically, this is on purpose for the example.</p>
<h2>The Tests</h2>
<p>Of course we could start the application with <a href="https://metacpan.org/pod/distribution/Plack/script/plackup"><code>plackup</code></a> but that's not what we're trying to do.
I'll break the test script down a bit but if you want to see any of these files look at the <a href="https://github.com/MojoliciousDotIO/mojolicious.io/tree/master/blog/2018/12/20/testing-dancer/ex">blog repo</a> for a full listing.
Instead, let's load this into a test script.</p>
<pre><code>use Mojo::Base -strict;
</code></pre>
<p>Now if you aren't familiar, <code>use Mojo::Base -strict</code> is a quick way to say</p>
<pre><code>use strict;
use warnings;
use utf8;
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
->text_is('dl#data dt#hello + dd', 'world');
$t->post_ok('/html' => form => { name => 'grinch' })
->status_is(200)
->content_type_like(qr[text/html])
->text_is('dl#data dt#hello + dd', 'grinch');
done_testing;
</code></pre>
<p>In this year's Mojolicious advent calendar, we've already seen <a href="https://mojolicious.io/blog/2018/12/05/compound-selectors/">some</a> <a href="https://mojolicious.io/blog/2018/12/14/a-practical-example-of-mojo-dom/">great</a> <a hre...
The point remains however, testing HTML responses with CSS selectors allows you to make your tests targetd in a way that allows you to write more and better tests since you don't have to hack around extracting the bits you want.</p>
<h2>Testing WebSockets</h2>
<p>Ok so that's great and all, but of course now it comes to the point you've all been waiting for: can you test WebSockets?
As Jason Crome mentioned in his <a href="http://advent.perldancer.org/2018/13">Twelve Days of Dancer</a> "State of Dancer", you can now dance with WebSockets via <a href="https://metacpan.org/pod/Dancer2::Plugin::WebSocket">Dancer2::Plugin:...
<p>Well, so far not via the role I showed above.
It might be possible, but it would involve learning deep PSGI magick that I'm not sure I'm smart enough to do; patches welcome obviously :D.</p>
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
<p>Although there are some great testing options in the PSGI space, Test::Mojo has lots of benefits for Dancer and PSGI users.
By using <code>Test::Mojo::Role::PSGI</code> or by running against a locally-bound server, Test::Mojo can be a tool in the toolbox of any PSGI developer.</p>
</section>
<small><p>Banner image adapted from <a href="https://www.flickr.com/photos/louisepalanker/6848788290">Ballroom Dance Competition in Aukland, New Zealand</a> by <a href="https://www.flickr.com/photos/louisepalanker/">Louise Palanker</a>,...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/testing/">testing</a>,
<a href="/blog/tag/psgi/">psgi</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/cc767569f5863a7c261991ee5b23f147">
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/19/you-only-export-twice/index.html" rel="prev"><strong>Previous Article</strong> Day 19: You Only Export Twice</a></li>
<li class="next"><a href="/blog/2018/12/21/a-little-christmas-template-cooking/index.html" rel="next"><strong>Next Article</strong> Day 21: A Little Christmas Template Cooking </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_20_testing-dancer_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@briandfoy_perl" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/21/a-little-christmas-template-cooking/" property="og:url">
<meta content="Day 21: A Little Christmas Template Cooking" property="og:title">
<meta content="Using Mojo::Template for non-web applications." property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/21/a-little-christmas-template-cooking/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 21: A Little Christmas Template Cooking - mojolicious.io</title>
<meta content="brian d foy" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_ view on Meta::CPAN
<time class="date" datetime="2018-12-21">Dec 21, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Peanut Butter Kisses cookies" src="/blog/2018/12/21/a-little-christmas-template-cooking/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>The Advent Calendar has shown you many great ways to use Mojolicious, and since you already have Mojo installed you can use it for things besides web processing. Today's recipe uses The templating rendering engine for somethi...
</section>
<section id="section-2">
<p>First, process some string templates. Here's an example lifted from the <a href="https://mojolicious.org/perldoc/Mojo/Template">Mojo::Template</a>, using the <a href="https://www.effectiveperlprogramming.com/2016/12/strip-lea...
devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_ view on Meta::CPAN
% use Time::Piece;
<div>
% my $now = localtime;
Time: <%= $now->hms %>
</div>
EOF
</code></pre>
<p>The lines with leading percent sings are Perl code. One of those lines loads a module, <a href="https://metacpan.org/pod/Time::Piece">Time::Piece</a>, and the other creates the variable <code>$now</code>. The <code><%= %></code> insert value...
<p>You can invert that so that the source of the values comes from outside of the template. Sometimes this is preferable to having too much logic in the presentation layer:</p>
<pre><code>use v5.26;
use Mojo::Template;
my $mt = Mojo::Template->new;
use Time::Piece;
my $now = localtime;
say $mt->render(<<~'EOF', $now->hms );
devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_ view on Meta::CPAN
</code></pre>
<p>That's about it. Your <code>$wanted</code> subroutine can be more sophisticated to put the cooked files in a different directories, skip directories, and many other things. You don't even need to use <a href="https://perldoc.perl.org/File/...
</section>
<small><p>Banner image: <a href="https://www.flickr.com/photos/39908901@N06/11412118604/in/photolist-ios6gA-5LGoKq-PnBoBQ-ibEPHM-7qUncc-SSGFhT-SCYSD9-7pwexw-2doKrZi-b18y32-acMecE-91MNrB-ogyG6P-LX7iMB-ShNXEj-8ZydMc-qdCE4G-4gn2We-qeqCfM-v...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/templates/">templates</a>,
<a href="/blog/tag/advent/">advent</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/168427dea0a034607ee7850f3de98ea2.jpg">
</div>
<div class="about">
<h5>brian d foy</h5>
<p><a href="http://www252.pair.com/~comdog/">brian d foy</a> is the author of <a href="https://www.masteringperl.org/">Mastering Perl</a> and <a href="https://www.learningperl6.com/">Learning Perl 6</a>, and the co-author of <...
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/20/testing-dancer/index.html" rel="prev"><strong>Previous Article</strong> Day 20: Testing Dancer</a></li>
<li class="next"><a href="/blog/2018/12/22/use-carton-for-your-mojolicious-app-deployment/index.html" rel="next"><strong>Next Article</strong> Day 22: Use Carton for your Mojolicious app deployment </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_21_a-little-christmas-template-cooking_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="https://mojolicious.io/blog/2018/12/22/use-carton-for-your-mojolicious-app-deployment/" property="og:url">
<meta content="Day 22: Use Carton for your Mojolicious app deployment" property="og:title">
<meta content="https://mojolicious.io/blog/2018/12/22/use-carton-for-your-mojolicious-app-deployment/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 22: Use Carton for your Mojolicious app deployment - mojolicious.io</title>
<meta content="Luc Didry" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_ view on Meta::CPAN
<time class="date" datetime="2018-12-22">Dec 22, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Brown cardboard boxes on a white floor" src="/blog/2018/12/22/use-carton-for-your-mojolicious-app-deployment/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>You have a lovely Mojolicious app, itâÂÂs time to deploy it!</p>
<p>But⦠itâÂÂs not working on the production server! What is going on? Oh no, the modules you rely on are not on the same version that on your development server. What can you do?</p>
</section>
devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_ view on Meta::CPAN
Not only it avoids to list all the dependencies needed by your application in the README or the INSTALL file, but it speeds up deployments and make them more safer, since it sure lowers the risks of bugs due to bad versions of dependencies.</p>
<p><small id="footnote-1">1: or INSTALL, or wherever you put your installation documentation <a href="#back-to-1">â©ï¸Â</a><small></small></small></p>
</section>
<small><p><a href="https://unsplash.com/photos/mTkXSSScrzw">Photo</a> by <a href="https://unsplash.com/@fempreneurstyledstock">Leone Venter</a>, <a href="https://unsplash.com/license">Unsplash license</a> (quite similar to public domain...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/deployment/">deployment</a>,
<a href="/blog/tag/carton/">carton</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="/static/ldidry.png">
</div>
<div class="about">
<h5>Luc Didry</h5>
<p>Luc Didry is a sysAdmin and Perl developer, in love with Perl since he discovered it 10 years ago, and a Mojolicious enthusiast.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/21/a-little-christmas-template-cooking/index.html" rel="prev"><strong>Previous Article</strong> Day 21: A Little Christmas Template Cooking</a></li>
<li class="next"><a href="/blog/2018/12/23/mojolicious-and-angular/index.html" rel="next"><strong>Next Article</strong> Day 23: Mojolicious and Angular </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_22_use-carton-for-your-mojolicious-app-deployment_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@sachindangol" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/23/mojolicious-and-angular/" property="og:url">
<meta content="Day 23: Mojolicious and Angular" property="og:title">
<meta content="Learn how to marry Mojolicious and Angular for building awesome web application" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/23/mojolicious-and-angular/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 23: Mojolicious and Angular - mojolicious.io</title>
<meta content="Sachin Dangol" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
<time class="date" datetime="2018-12-23">Dec 23, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Spider in web" src="/blog/2018/12/23/mojolicious-and-angular/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p><a href="https://angular.io/">Angular</a> is one of the most popular front-end web application frameworks, helping you build modern applications for the web, mobile, or desktop.
<a href="https://mojolicious.org/">Mojolicious</a> is a next generation web framework for the Perl programming language.
Mojolicious and Angular together can certainly build a next generation web application.</p>
<p>At work, we have been using these two to build a very responsive, scalable and fantastic web apps.
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
[Sat Dec 15 13:08:52 2018] [info] Worker 38213 started
[Sat Dec 15 13:08:52 2018] [info] Worker 38212 started
</code></pre>
<p>Let's open browser and have a look at our mojo app.</p>
<p><img alt="basic Mojolicious full app" src="mojo_app.png"></p>
<h2>Generate Angular App</h2>
<p>Angular Version 7 is used for this demo, but should work for versions back to 4+. Demos on how to install Angular and CLI will be way too boring for this blog and there are plenty of resources for this in internet.</p>
<p>Angular CLI is a command-line interface tool that you use to initialize, develop, scaffold, and maintain Angular applications.
Let's use the Angular CLI to generate a new app, <code>ng new app-name</code>.</p>
<pre><code>Sachin@01:18 PM[~/workspace/project/mojo_angular]$ ng new NgDemo
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS
CREATE NgDemo/README.md (1023 bytes)
CREATE NgDemo/angular.json (3768 bytes)
CREATE NgDemo/package.json (1306 bytes)
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.08 kB [entry] [rendered]
chunk {styles} styles.js, styles.js.map (styles) 16.3 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 3.67 MB [initial] [rendered]
ï½¢wdmï½£: Compiled successfully.
</code></pre>
<p>Open the browser to check Angular app:</p>
<p><img alt="basic angular app" src="angular_app.png"></p>
<p>Note that this page's content is coming from <code>NgDemo/src/index.html</code> where <code>app-root</code> selector html is content coming from <code>NgDemo/src/app/app.component.html</code>. Later we will be modifying <code>app.component.htm...
<h2>Make Mojolicious app serve an Angular app?</h2>
<p>First we'll compile the Angular app from <a href="https://www.typescriptlang.org/docs/home.html">TypeScript</a> to standard JavaScript.
<code>ng build</code> compiles an Angular app into an output directory named <code>dist</code> at the given output path.
Run <code>ng build</code> with <code>--base-href=./</code> so that base url inside the Angular app is set to the current directory for the application being built. This is very important so that later you do not waste time figuring out why Angular ro...
<pre><code>Sachin@02:06 PM[~/workspace/project/mojo_angular/NgDemo]$ ng build --base-href=./
Date: 2018-12-15T06:06:48.550Z
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
[Sat Dec 15 14:49:03 2018] [info] Worker 40636 started
</code></pre>
<p><img alt="mojolicious serving angular SPA" src="mojo_serving_angular.png"></p>
<p>Congratulations! we have served angular app with Mojolicious. Please note that the URL will be <code>http://localhost:8080/NgDemo/</code>.</p>
<h2>Integrating the Apps Further</h2>
<p>To show how the applications can interact, we'll now build a simple demo to show an api call to a Mojolicious backend routes from the Angular frontend and display the result in Angular.
Since, this is not an Angular blog I will not go too deep explaining Angular; there are plenty of resources in internet for that.</p>
<h3>Create a new route in the Mojo App</h3>
<p>Add a route <code>advent/2018/detail</code> in Mojolicious app class which just responds to http <code>get</code> request.
For some demo data, I'll just use the first articles from the 2018 Mojolicious advent calendar as a detail list.
In a full mojo app it is best to put routes methods in <code>AppName/Controller/SomeModule.pm</code>, but this is just for quick demo so we can use <a href="https://mojolicious.org/perldoc/Mojolicious/Guides/Growing#Simplified-application-class">hybr...
<pre><code>$r->get('advent/2018/detail' => sub {
my $self = shift;
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
<li>For more example code to see more Angular and Mojolicious in action, please have a look at my git repo:
<a href="https://github.com/tryorfry/mojolicious-ng4">https://github.com/tryorfry/mojolicious-ng4</a></li>
</ul>
</section>
<small><p>Banner <a href="https://commons.wikimedia.org/w/index.php?curid=646036">photo</a> by <a href="http://www.videgro.net/">Vincent de Groot</a>, licensed <a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY SA 4.0</a></...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/angular/">Angular</a>,
<a href="/blog/tag/javascript/">JavaScript</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="/static/sachin.jpg">
</div>
<div class="about">
<h5>Sachin Dangol</h5>
<p>Sachin has been using Perl for 10 years plus and loves Perl and Mojolicious. Reading books on programming and technology, traveling, cooking are few of his hobbies.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/22/use-carton-for-your-mojolicious-app-deployment/index.html" rel="prev"><strong>Previous Article</strong> Day 22: Use Carton for your Mojolicious app deployment</a></li>
<li class="next"><a href="/blog/2018/12/24/async-await-the-mojo-way/index.html" rel="next"><strong>Next Article</strong> Day 24: Async/Await the Mojo Way </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@joelaberger" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/24/async-await-the-mojo-way/" property="og:url">
<meta content="Day 24: Async/Await the Mojo Way" property="og:title">
<meta content="Announcing Mojo::AsyncAwait - Better non-blocking workflows for Mojolicious" property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/24/async-await-the-mojo-way/banner.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 24: Async/Await the Mojo Way - mojolicious.io</title>
<meta content="Joel Berger" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
<time class="date" datetime="2018-12-24">Dec 24, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Vancouver Symphony Orchestra with Bramwell Tovey" src="/blog/2018/12/24/async-await-the-mojo-way/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<h2>The Problems with Thinking in Asynchronous Code</h2>
<p>I've thought a lot about asynchronous code.
Learning it, writing it, teaching it.
Async is hard.</p>
<blockquote>
<p>Learning async programming is about being completely confused and overcomplicating everything and eventually having an 'aha' moment and then being utterly frustrated you don't have a way to teach other people without them needing to ...
<cite><a href="https://shadow.cat/blog/matt-s-trout/">Matt S. Trout</a></cite></p>
</blockquote>
<p>While Matt is right, I've thought a lot about that quote and I think I've come up with an underlying problem.
This may sound trite and it may seem obvious, but the problem is that writing asynchronous code is just fundamentally different than writing blocking code.</p>
<p>We've always known how to make one instruction follow another, that's easy, it happens on the next line of code.
Line one executes and then line two.
If line two needs something from line one it will be there.</p>
<p>Say you want to write "get this web resource, then print the title".
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
As a bulwark against future implimentation changes, it comes with a pluggable backend system, not unlike how Mojo::IOLoop's pluggable reactor system works.
The default implementation may change and users may choose to use any available backend if they have a preference (once new ones come along, and others <strong>are</strong> in the works).</p>
<h2>Conclusion</h2>
<p>So now the formula is simple.</p>
<ul>
<li>Use libraries that return promises rather than take callbacks.</li>
<li>Use the <code>async</code> keyword when declaring functions that need to <code>await</code> promises.</li>
<li>Organize your promises using <a href="https://mojolicious.org/perldoc/Mojo/Promise#all">all</a>, <a href="https://mojolicious.org/perldoc/Mojo/Promise#race">race</a> (only wait for the first resolved promise) or some <a href="https://mojolicious....
</ul>
<p>Hopefully with Mojo::AsyncAwait, writing asynchronous code is finally going to be accessible to those users that haven't yet had Matt's "aha" moment.
And for those of us who have, don't worry, you'll love it too.</p>
<p><em>Another excellent resource is <a href="https://www.youtube.com/watch?v=gB-OmN1egV8">The Evolution of Async JavaScript: From Callbacks, to Promises, to Async/Await</a> by Tyler McGinnis.
It is for JavaScript, but nearly everything applies except they syntax.
Highly recommended.</em></p>
</section>
<small><p><a href="https://commons.wikimedia.org/w/index.php?curid=15521095">Banner image</a> by <a href="https://www.flickr.com/people/56355577@N06">Vancouver 125 - The City of Vancouver</a> <a href="https://www.flickr.com/photos/vanco...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/non-blocking/">non-blocking</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/cc767569f5863a7c261991ee5b23f147">
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/23/mojolicious-and-angular/index.html" rel="prev"><strong>Previous Article</strong> Day 23: Mojolicious and Angular</a></li>
<li class="next"><a href="/blog/2018/12/25/special-thanks/index.html" rel="next"><strong>Next Article</strong> Day 25: Special Thanks </a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devdata/https_mojolicious.io_blog_2018_12_25_special-thanks_ view on Meta::CPAN
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<link href="/theme/css/default.css" rel="stylesheet">
<link href="/theme/css/layout.css" rel="stylesheet">
<link href="/theme/css/media-queries.css" rel="stylesheet">
<link href="/theme/css/statocles.css" rel="stylesheet">
<!-- twitter and opengraph -->
<meta content="summary" name="twitter:card">
<meta content="@joelaberger" name="twitter:creator">
<meta content="https://mojolicious.io/blog/2018/12/25/special-thanks/" property="og:url">
<meta content="Day 25: Special Thanks" property="og:title">
<meta content="Wrap up the 2018 Calendar with news and gratitude." property="og:description">
<meta content="https://mojolicious.io/blog/2018/12/25/special-thanks/jude_mojo.jpg" property="og:image">
<meta content="summary_large_image" name="twitter:card">
<script src="/theme/js/modernizr.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/sunburst.min.css" rel="stylesheet">
<title>Day 25: Special Thanks - mojolicious.io</title>
<meta content="Joel Berger" name="author">
<meta content="Statocles 0.093" name="generator">
<link href="/static/favicon.ico" rel="shortcut icon">
devdata/https_mojolicious.io_blog_2018_12_25_special-thanks_ view on Meta::CPAN
</head>
<body>
<header>
<div class="row">
<div class="twelve columns">
<div class="logo">
<a href="/index.html">
<h3 style="color: #fff">mojolicious.io</h3>
</a>
</div>
<nav id="nav-wrap">
<a class="mobile-btn" href="#nav-wrap" title="Show navigation">Show navigation</a>
<a class="mobile-btn" href="#" title="Hide navigation">Hide navigation</a>
<ul class="nav" id="nav">
<!-- li.current is given a different styling -->
<li><a href="/blog">Blog</a></li>
<li><span><a href="/">Advent Calendar</a></span>
<ul>
<li><a href="/">2018</a></li>
<li><a href="/page/advent/2017">2017</a></li>
</ul>
</li>
<li><span><a href="https://mojolicious.org">mojolicious.org</a></span>
<ul>
<li><a href="http://mojolicious.org/perldoc">Documentation</a></li>
<li><a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Tutorial">Tutorial</a></li>
devdata/https_mojolicious.io_blog_2018_12_25_special-thanks_ view on Meta::CPAN
</div>
</header>
<div id="page-title">
<div class="row">
<div class="ten columns centered text-center">
<h1>Mojo Wonk Blog<span>.</span></h1>
<p>A semi-offical blog dedicated to the Mojolicious web framework</p>
</div>
</div>
</div>
<div class="content-outer">
devdata/https_mojolicious.io_blog_2018_12_25_special-thanks_ view on Meta::CPAN
<time class="date" datetime="2018-12-25">Dec 25, 2018</time>
</p>
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Baby Jude Carl Berger in Mojo gear" src="/blog/2018/12/25/special-thanks/jude_mojo.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>This advent calendar, I have special thanks to offer to all the people who helped make it possible.
I'll list them shortly, but before I do, I'd like to introduce you to the newest unofficial member of the Mojolicious Core Team: Jude Carl Berger!
Jude was born on the first day of this calendar, December 1st, at 2:15 am Chicago time.
If you're looking at timestamps, yes, that's about 4 hours after the first blog post went live.</p>
<p>After a one week stay in the NICU for a relatively minor condition, he's now home with myself and his mother, my wonderful wife Carolyn, who I have to thank first.
Not too many partners would put up with someone flitting out to edit a blog post or hit "publish" at the right moment during this time in our lives.
And thanks for Jude.</p>
<p>Armed with that knowledge, you can surely see that even more than usual I couldn't have done this without help!
So, with no further ado, I want to thank all the authors,</p>
<ul>
<li>Boyd Duffee</li>
<li>brian d foy</li>
<li>Chris Seigman</li>
<li>Doug Bell</li>
devdata/https_mojolicious.io_blog_2018_12_25_special-thanks_ view on Meta::CPAN
<p>I especially want to note that Doug Bell went above and beyond with eight (!) articles, brian d foy did more than his fair share with four, and Luc Didry and Boyd Duffee did two each!
I also want to specially mention Jason Crome who, during a tough month of his own, administered the <a href="http://advent.perldancer.org/2018">Twelve Days of Dancer</a> and contributed a cross-over article to ours as well.
The calendar is obviously nothing without the articles and so I'm tremendously thankful that I had authors that I could lean on to help me when I wasn't able to fill extra space as I might have in other years.
Spectacular work, one and all!</p>
<p>We intend to publish more on this site throughout the year, including some pieces from two authors who submitted articles after all the days had been filled.
Articles had been committed to the repo, but were not yet published, which led to a small confusion in which these authors rose to meet a need they thought existed, so thank you Stefan Adams and Yuki Kimoto for stepping up!
We'll get those and other articles out to you in the coming months!</p>
<p>I want to thank Doug again for creating and maintaining <a href="http://preaction.me/statocles/">Statocles</a>, the static blog engine that powers this site.
I want to thank my employer <a href="https://www.servercentral.com/">ServerCentral</a> who not only are great to work for and support open source, but who gave me lots of time to get settled in with the newest member of my family (and a few cute gift...
I want to thank Sebastian Riedel for writing Mojolicious and for the outfit you see on Jude in the picture above (as far as I know, it is a unique piece), and the entire Mojolicious Core Team and community.</p>
<p>I want to thank Jude for being a reasonably happy newborn and sleeping for longer-than-average stretches at night.</p>
<p>Finally, I extend my warmest thanks to the doctors, nurses and staff of Northwest Community Hospital in Arlington Heights, Illinois and especially the NICU nurses who are beyond amazing.</p>
<p>Merry Christmas, Happy Holidays, Happy New Year, and Happy Perling!</p>
</section>
<small><p>Image: "Jude Carl Berger", original work by Joel Berger, licensed <a href="https://creativecommons.org/licenses/by-nc-nd/4.0/">CC BY-NC-ND 4.0</a>.</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>
</p>
<div class="bio cf">
<div class="gravatar">
<img alt="author image" src="https://secure.gravatar.com/avatar/cc767569f5863a7c261991ee5b23f147">
</div>
<div class="about">
<h5>Joel Berger</h5>
<p>Joel has Ph.D. in Physics from the University of Illinois at Chicago.
He an avid Perl user and <a href="https://metacpan.org/author/JBERGER">author</a> and is a member of the Mojolicious Core Team.</p>
</div>
</div>
<ul class="post-nav cf">
<li class="prev"><a href="/blog/2018/12/24/async-await-the-mojo-way/index.html" rel="prev"><strong>Previous Article</strong> Day 24: Async/Await the Mojo Way</a></li>
</ul>
</div>
</article>
</div>
<div class="four columns end" id="secondary">
devdata/https_mojolicious.io_blog_2018_12_25_special-thanks_ view on Meta::CPAN
<div class="widget widget_tag_cloud">
<h5 class="widget-title">Tags</h5>
<div class="tagcloud cf">
<a href="/blog/tag/administration/">administration</a>
<a href="/blog/tag/advent/">advent</a>
<a href="/blog/tag/angular/">Angular</a>
<a href="/blog/tag/api/">api</a>
<a href="/blog/tag/app/">app</a>
<a href="/blog/tag/authentication/">authentication</a>
<a href="/blog/tag/caching/">caching</a>
<a href="/blog/tag/carton/">carton</a>
<a href="/blog/tag/command/">command</a>
<a href="/blog/tag/css/">css</a>
<a href="/blog/tag/dancer/">dancer</a>
<a href="/blog/tag/debugging/">debugging</a>
<a href="/blog/tag/deployment/">deployment</a>
<a href="/blog/tag/development/">development</a>
<a href="/blog/tag/documentation/">documentation</a>
<a href="/blog/tag/example/">example</a>
<a href="/blog/tag/fluent/">fluent</a>
<a href="/blog/tag/full/">full</a>
<a href="/blog/tag/graphql/">graphql</a>
<a href="/blog/tag/growing/">growing</a>
<a href="/blog/tag/headers/">headers</a>
<a href="/blog/tag/hello-world/">hello world</a>
<a href="/blog/tag/html/">html</a>
<a href="/blog/tag/installing/">installing</a>
<a href="/blog/tag/javascript/">JavaScript</a>
<a href="/blog/tag/ldap/">LDAP</a>
<a href="/blog/tag/lite/">lite</a>
<a href="/blog/tag/minion/">minion</a>
<a href="/blog/tag/mocking/">mocking</a>
<a href="/blog/tag/model/">model</a>
<a href="/blog/tag/mojoconf/">mojoconf</a>
<a href="/blog/tag/non-blocking/">non-blocking</a>
<a href="/blog/tag/non-web/">non-web</a>
<a href="/blog/tag/openapi/">openapi</a>
<a href="/blog/tag/promises/">promises</a>
<a href="/blog/tag/psgi/">psgi</a>
<a href="/blog/tag/rendering/">rendering</a>
<a href="/blog/tag/rest/">rest</a>
<a href="/blog/tag/roles/">roles</a>
<a href="/blog/tag/routing/">routing</a>
<a href="/blog/tag/session/">session</a>
<a href="/blog/tag/swagger/">swagger</a>
<a href="/blog/tag/templates/">templates</a>
<a href="/blog/tag/testing/">testing</a>
<a href="/blog/tag/theme/">theme</a>
<a href="/blog/tag/useragent/">useragent</a>
<a href="/blog/tag/wishlist/">wishlist</a>
<a href="/blog/tag/xml/">xml</a>
<a href="/blog/tag/yancy/">yancy</a>
</div>
</div>
</aside>
</div>
</div>
</div>
<footer>
<div class="row">
<div class="twelve columns">
<ul class="footer-nav">
<li><a href="/blog">Blog.</a></li>
<li><a href="/">Advent Calendar.</a></li>
<li><a href="https://mojolicious.org">mojolicious.org.</a></li>
</ul>
<ul class="footer-social">
<li><a href="https://github.com/mojolicious/mojo"><i class="fa fa-github"></i></a></li>
<li><a href="https://twitter.com/search?q=%23mojolicious"><i class="fa fa-twitter"></i></a></li>
<li><a href="/blog/index.rss"><i class="fa fa-rss"></i></a></li>
</ul>
<ul class="copyright">
<li>Copyright é 2017 Joel Berger</li>
<li><a href="https://github.com/MojoliciousDotIO/mojolicious.io">Contribute to this site on Github</a></li>
<li>Design by <a href="http://www.styleshout.com/">Styleshout</a></li>
<li>Made with <a href="http://preaction.me/statocles">Statocles</a></li>
<li>Powered by <a href="http://www.perl.org">Perl</a></li>
</ul>
devscripts/update view on Meta::CPAN
my %add_modules = (
# not linked
#"04" => ["Mojo::DOM"],
);
my %typos = (
#'Perl::PrereqScanner::NotSoLite' => 'Perl::PrereqScanner::NotQuiteLite',
);
my %daily_urls = (
"01" => "https://mojolicious.io/blog/2018/12/01/welcome-mojoconf-recap/",
"02" => "https://mojolicious.io/blog/2018/12/02/automatic-reload-for-rapid-development/",
"03" => "https://mojolicious.io/blog/2018/12/03/higher-order-promises/",
"04" => "https://mojolicious.io/blog/2018/12/04/testing-hooks-and-helpers/",
"05" => "https://mojolicious.io/blog/2018/12/05/compound-selectors/",
"06" => "https://mojolicious.io/blog/2018/12/06/making-a-list-with-yancy/",
"07" => "https://mojolicious.io/blog/2018/12/07/openapi/",
"08" => "https://mojolicious.io/blog/2018/12/08/authenticating-with-ldap/",
"09" => "https://mojolicious.io/blog/2018/12/09/add-a-theme-system-to-your-mojolicious-app/",
"10" => "https://mojolicious.io/blog/2018/12/10/minion-stands-alone/",
"11" => "https://mojolicious.io/blog/2018/12/11/who-watches-the-minions/",
"12" => "https://mojolicious.io/blog/2018/12/12/dancer-and-minion/",
"13" => "https://mojolicious.io/blog/2018/12/13/taking-on-roles/",
"14" => "https://mojolicious.io/blog/2018/12/14/a-practical-example-of-mojo-dom/",
"15" => "https://mojolicious.io/blog/2018/12/15/practical-web-content-munging/",
"16" => "https://mojolicious.io/blog/2018/12/16/browser-diet/",
"17" => "https://mojolicious.io/blog/2018/12/17/a-website-for-yancy/",
"18" => "https://mojolicious.io/blog/2018/12/18/a-view-to-a-pod/",
"19" => "https://mojolicious.io/blog/2018/12/19/you-only-export-twice/",
"20" => "https://mojolicious.io/blog/2018/12/20/testing-dancer/",
"21" => "https://mojolicious.io/blog/2018/12/21/a-little-christmas-template-cooking/",
"22" => "https://mojolicious.io/blog/2018/12/22/use-carton-for-your-mojolicious-app-deployment/",
"23" => "https://mojolicious.io/blog/2018/12/23/mojolicious-and-angular/",
"24" => "https://mojolicious.io/blog/2018/12/24/async-await-the-mojo-way/",
"25" => "https://mojolicious.io/blog/2018/12/25/special-thanks/",
);
gen_curried_sub(
'App::CreateAcmeCPANModulesImportModules::create_acme_cpanmodules_import_modules',
{
modules => [
{
name => '2018',
url => "https://mojolicious.io/",
extract_urls => [map {$daily_urls{$_}} "01".."25"],
devscripts/update view on Meta::CPAN
ignore_empty => 1,
namespace => 'Acme::CPANModules::Import::MojoliciousAdvent',
user_agent => 'Mozilla/5.0',
dist_dir => "$Bin/..",
},
'app',
);
Perinci::CmdLine::Any->new(
url => '/main/app',
log => 1,
)->run;
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_02.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2018_12_02;
our $DATE = '2018-12-30'; # DATE
our $VERSION = '0.001'; # VERSION
our $LIST = {description=>"This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2018/12/02/automatic-reload-for-rapid-development/] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{mod...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2018 (day 02)
__END__
=pod
=encoding UTF-8
=head1 NAME
Acme::CPANModules::Import::MojoliciousAdvent::2018_12_02 - Modules mentioned in Mojolicious Advent Calendar 2018 (day 02)
=head1 VERSION
This document describes version 0.001 of Acme::CPANModules::Import::MojoliciousAdvent::2018_12_02 (from Perl distribution Acme-CPANModulesBundle-Import-MojoliciousAdvent-2018), released on 2018-12-30.
=head1 DESCRIPTION
This module is generated by extracting module names mentioned in L<https://mojolicious.io/blog/2018/12/02/automatic-reload-for-rapid-development/> (retrieved on 2018-12-30). Visit the URL for the full contents.
Modules mentioned in Mojolicious Advent Calendar 2018 (day 02).
This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2018/12/02/automatic-reload-for-rapid-development/] (retrieved on 2018-12-30). Visit the URL for the full contents.
=head1 INCLUDED MODULES
=over
=item * L<Mojolicious::Plugin::AutoReload>
=back
=head1 HOMEPAGE
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_03.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2018_12_03;
our $DATE = '2018-12-30'; # DATE
our $VERSION = '0.001'; # VERSION
our $LIST = {description=>"This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2018/12/03/higher-order-promises/] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"Mojo::Promi...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2018 (day 03)
__END__
=pod
=encoding UTF-8
=head1 NAME
Acme::CPANModules::Import::MojoliciousAdvent::2018_12_03 - Modules mentioned in Mojolicious Advent Calendar 2018 (day 03)
=head1 VERSION
This document describes version 0.001 of Acme::CPANModules::Import::MojoliciousAdvent::2018_12_03 (from Perl distribution Acme-CPANModulesBundle-Import-MojoliciousAdvent-2018), released on 2018-12-30.
=head1 DESCRIPTION
This module is generated by extracting module names mentioned in L<https://mojolicious.io/blog/2018/12/03/higher-order-promises/> (retrieved on 2018-12-30). Visit the URL for the full contents.
Modules mentioned in Mojolicious Advent Calendar 2018 (day 03).
This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2018/12/03/higher-order-promises/] (retrieved on 2018-12-30). Visit the URL for the full contents.
=head1 INCLUDED MODULES
=over
=item * L<Mojo::Promise>
=item * L<Mojo::Promise::Role::HigherOrder>
=back
lib/Acme/CPANModules/Import/MojoliciousAdvent/2018_12_04.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2018_12_04;
our $DATE = '2018-12-30'; # DATE
our $VERSION = '0.001'; # VERSION
our $LIST = {description=>"This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2018/12/04/testing-hooks-and-helpers/] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"Mojo::H...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2018 (day 04)
__END__
=pod
=encoding UTF-8
=head1 NAME
Acme::CPANModules::Import::MojoliciousAdvent::2018_12_04 - Modules mentioned in Mojolicious Advent Calendar 2018 (day 04)
=head1 VERSION
This document describes version 0.001 of Acme::CPANModules::Import::MojoliciousAdvent::2018_12_04 (from Perl distribution Acme-CPANModulesBundle-Import-MojoliciousAdvent-2018), released on 2018-12-30.
=head1 DESCRIPTION
This module is generated by extracting module names mentioned in L<https://mojolicious.io/blog/2018/12/04/testing-hooks-and-helpers/> (retrieved on 2018-12-30). Visit the URL for the full contents.
Modules mentioned in Mojolicious Advent Calendar 2018 (day 04).
This list is generated by extracting module names mentioned in [https://mojolicious.io/blog/2018/12/04/testing-hooks-and-helpers/] (retrieved on 2018-12-30). Visit the URL for the full contents.
=head1 INCLUDED MODULES
=over
=item * L<Mojo::HelloWorld>
=item * L<Mojo::Message::Request>
=item * L<Mojo::Message::Response>