view release on metacpan or search on metacpan
"Test::Mojo::Role::TestDeep" : "0",
"Test::Mojo::WithRoles" : "0",
"Test::More" : "0",
"Wishlist" : "0",
"XML::Parser" : "0",
"XMLRPC::Fast" : "0",
"Yancy" : "0",
"Yancy::Backend::Dbic" : "0",
"Yancy::Backend::Mysql" : "0",
"Yancy::Backend::Pg" : "0",
"feature" : "0",
"ojo" : "0",
"ojoBox" : "0",
"strict" : "0",
"utf8" : "0",
"warnings" : "0"
}
}
},
"release_status" : "stable",
"resources" : {
Please visit the project's homepage at
<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousA
dvent-2017>.
SOURCE
Source repository is at
<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-Mojolic
iousAdvent-2017>.
BUGS
Please report any bugs or feature requests on the bugtracker website
<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundl
e-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a patch
to an existing test-file that illustrates the bug or desired feature.
AUTHOR
perlancar <perlancar@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2018 by perlancar@cpan.org.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
devdata/https_mojolicious.io_blog_2017_12_01_day-1-getting-started view on Meta::CPAN
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="hot air ballons" src="/blog/2017/12/01/day-1-getting-started/1280px-Colorado_Springs_Hot_Air_Balloon_Competition.jpg">
</div>
<div class="post-content">
<section id="section-1">
<h2>Start at the Beginning</h2>
<p>In this Advent Calendar series, some posts will be introductory, some will be advanced, some will be on new features.
Who knows what could be next?
But for now let's ensure a level playing field by working out how to get started.</p>
</section>
<section id="section-2">
<h2>What is Mojolicious?</h2>
<p>Well, <a href="http://mojolicious.org">Mojolicious</a> is really two things.
First it is a powerful web-focused toolkit called Mojo.
Second it is a powerful web framework called Mojolicious.
devdata/https_mojolicious.io_blog_2017_12_03_day-3-using-named-routes view on Meta::CPAN
<p>There is one more thing I should mention.
I could have actually made the previous examples with even less code.
If a route doesn't explicitly render something, it will check to see if a template exists for the name of the route.
It is a shortcut that some people like and could have made the routing definitions look like this:</p>
<pre><code>get '/toy/:toy_name' => 'toy';
get '/meet/:name' => 'staff';
get '/' => 'home';
</code></pre>
<p>While some people appreciate that feature, I personally like to be explicit about which template I want.
I also like to separate concerns.
Anyway, you can choose whichever you like best.
After all, there's more than one way to do it!</p>
</section>
<small><p><a href="https://flickr.com/photos/94599716@N06/15283079263">Image</a> by <a href="https://www.flickr.com/people/94599716@N06">Travis Wise</a> licensed under the <a class="extiw" href="https://en.wikipedia.org/wiki/en:Creative...
</small>
<p class="tags">
<span>Tagged in </span>:
devdata/https_mojolicious.io_blog_2017_12_05_day-5-your-apps-built-in-commands view on Meta::CPAN
Certain routes are more complex, and while all these were simple and so no flags are shown, if one were an <code>under</code> route or a <code>websocket</code> it would be noted where the <code>....</code> are.
Finally it includes a pattern that is what is actually matched by the router.
This can be helpful sometimes when debugging why certain requests match (or more likely don't match) a certain route.
Note that the router checks each route in order top to bottom, the first to match is what is used.</p>
<h3>The get Command</h3>
<p>Now we're getting to the fun stuff!</p>
<p>Mojolicious comes with a <a href="http://mojolicious.org/perldoc/Mojo/UserAgent">user agent</a> and lots of post-processing power, including <a href="http://mojolicious.org/perldoc/Mojo/DOM">HTML/XML</a> and <a href="http://mojolicious.org/perldoc...
This command exposes those features together on the command line, like a smart version of cURL or wget.</p>
<p>Output is written to STDOUT so that you can redirect the result to a file if you'd like.
Because of that, headers are omitted from the output unless you pass <code>-v</code>.</p>
<p>Let's see what it can do!
You can find the latest version of <code>IO::Socket::SSL</code> using the <a href="https://github.com/metacpan/metacpan-api/blob/master/docs/API-docs.md">Meta::CPAN JSON API</a>.
The response is parsed as JSON and only the <code>version</code> element is output.</p>
<pre><code>mojo get https://fastapi.metacpan.org/v1/module/IO::Socket::SSL /version
</code></pre>
devdata/https_mojolicious.io_blog_2017_12_05_day-5-your-apps-built-in-commands view on Meta::CPAN
<p>How fun is that?!</p>
<ul>
<li>You can POST or PUT or DELETE data.</li>
<li>It handles HTTP basic authentication using <code>username:password@</code> in the URL.</li>
<li>You can submit forms, even with file uploads using the standard <code>@filename</code> syntax.</li>
<li>You can pipe data to the command if you just want to send the raw contents of a file rather than url-encode it.</li>
<li>See lots more examples in the <a href="http://mojolicious.org/perldoc/Mojolicious/Command/get#SYNOPSIS">documentation</a>.</li>
</ul>
<p>But I haven't even touched on its coolest feature yet.
This command also works on your application when you request a relative url.
This is so handy for debugging requests during rapid development; you don't even need a browser!</p>
<pre><code>perl santa.pl get /meet/rudolph 'p' text
</code></pre>
<h3>The eval Command</h3>
<p>Finally in this whirlwind tour, I'll show you my favorite command.
The <a href="http://mojolicious.org/perldoc/Mojolicious/Command/eval"><code>eval</code></a> command.
devdata/https_mojolicious.io_blog_2017_12_07_day-7-using-template-variants-for-a-beta-landing-page view on Meta::CPAN
<p>For the <a href="http://github.com/cpan-testers/cpantesters-web">CPAN Testers webapp
project</a>, I needed a way to
show off some pre-release tools with some context about what they are and how
they might be made ready for release. I needed a "beta" website with a front
page that introduced the beta projects. But, I also needed the same
<a href="http://mojolicious.org">Mojolicious</a> application to serve (in the future) as a
production website. The front page of the production website would be
completely different from the front page of the beta testing website.</p>
<p>To achieve this, I used <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Rendering#Template-variants">Mojolicious's template variants
feature</a>.</p>
</section>
<section id="section-2">
<p>First, I created a variant of my index.html template for my beta site
and called it <code>index.html+beta.ep</code>.</p>
<pre><code class="hljs"><span class="hljs-keyword"><h1></span>CPAN Testers Beta<span class="hljs-keyword"></h1></span>
<span class="hljs-keyword"><p></span>This site shows off some new features currently being tested.<span class="hljs-keyword"></p></span>
<span class="hljs-keyword"><h2><a</span> href=<span class="hljs-string">"/chart.html"</span><span class="hljs-keyword">></span>Release Dashboard<span class="hljs-keyword"></a></h2></span>
</code></pre>
<p>Next, I told Mojolicious to use the "beta" variant when in "beta" mode
by passing <code>$app->mode</code> to the <code>variant</code> stash variable.</p>
<pre><code class="hljs"><span class="hljs-comment"># myapp.pl</span><span class="hljs-comment">
</span><span class="hljs-keyword">use</span> <span class="hljs-function">Mojolicious::Lite</span>;
get '<span class="hljs-string">/*path</span>', { path => '<span class="hljs-string">index</span>' }, <span class="hljs-keyword">sub </span>{
<span class="hljs-keyword">my</span> ( <span class="hljs-type">$c</span> ) = <span class="hljs-type">@_</span>;
devdata/https_mojolicious.io_blog_2017_12_07_day-7-using-template-variants-for-a-beta-landing-page view on Meta::CPAN
<p>The mode is set by passing the <code>-m beta</code> option to Mojolicious's <code>daemon</code> or
<code>prefork</code> command.</p>
<pre><code>$ perl myapp.pl daemon -m beta
</code></pre>
<p>This gives me the <a href="http://beta.cpantesters.org">new landing page for beta.cpantesters.org</a>.</p>
<pre><code>$ perl myapp.pl get / -m beta
<h1>CPAN Testers Beta</h1>
<p>This site shows off some new features currently being tested.</p>
<h2><a href="/chart.html">Release Dashboard</a></h2>
</code></pre>
<p>But now I also need to replace the original landing page (index.html.ep)
so it can still be seen on the beta website. I do this with a simple
trick: I created a new template called <code>web.html+beta.ep</code> that imports
the original template and unsets the <code>variant</code> stash variable. Now
I can see the <a href="http://beta.cpantesters.org/web">main index page on the beta site at
http://beta.cpantesters.org/web</a>.</p>
<pre><code class="hljs">%= include 'index', variant => undef
</code></pre>
<pre><code>$ perl myapp.pl get /web -m beta
<h1>CPAN Testers</h1>
<p>This is the main CPAN Testers application.</p>
</code></pre>
<p>Template variants are a useful feature in some edge cases, and this isn't the
first time I've found a good use for them. I've also used them to provide a
different layout template in "development" mode to display a banner saying
"You're on the development site". Useful for folks who are undergoing user
acceptance testing. The best part is that if the desired variant for that
specific template is not found, Mojolicious falls back to the main template. I
built a mock JSON API application which made extensive use of this fallback
feature, but that's another blog post for another time.</p>
</section>
<small><p><a href="https://commons.wikimedia.org/w/index.php?curid=2147460">Image</a> by Photo by and (c)2007 <a href="//commons.wikimedia.org/wiki/User:Jina_Lee" title="User:Jina Lee">Jina Lee</a> - <span class="int-own-work" lang="en"...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>,
<a href="/blog/tag/rendering/">rendering</a>,
<a href="/blog/tag/templates/">templates</a>
devdata/https_mojolicious.io_blog_2017_12_09_day-9-the-best-way-to-test view on Meta::CPAN
return Mojo::Pg->new($app->config->{pg});
};
</code></pre>
<p>Then you could override whatever configuration might be present in your system by doing</p>
<pre><code>my $t = Test::Mojo->new('MyApp', {pg => 'postgresql://testuser:testpass@/testdb'});
</code></pre>
<p>If you use <a href="http://mojolicious.org/perldoc/Mojolicious/Plugin/Config">Mojolicious::Plugin::Config</a> or <a href="http://mojolicious.org/perldoc/Mojolicious/Plugin/JSONConfig">Mojolicious::Plugin::JSONConfig</a> or one of several other thi...
If you use some other loader on CPAN (that is Mojolicious aware) and it doesn't support this somewhat newish feature, please point it out to the author, it is easy to add.
Note that this does not work for Lite apps because it has inject the configuration overrides as the application is being built, something which isn't possible for a Lite app.</p>
<p>Finally you might find yourself in a situation where you already have an instantiated application.
If that is the case just pass it to the constructor.</p>
<pre><code>my $app = build_my_app();
my $t = Test::Mojo->new($app);
</code></pre>
<h2>How It Works</h2>
devdata/https_mojolicious.io_blog_2017_12_12_day-12-more-than-a-base-class view on Meta::CPAN
</div>
<div class="post-content">
<section id="section-1">
<p>Through this series, you've seen the module <a href="http://mojolicious.org/perldoc/Mojo/Base">Mojo::Base</a> referenced several times, though briefly and mostly in passing.
It shouldn't be taken lightly however, it packs a lot of punch in one import statement!
Nearly every file in the Mojolicious distribution uses it, either directly or indirectly.
So what is it?</p>
<p>First it imports several handy pragma that make your code safer and some features that are useful.
Second, it can be a base class to the current package, or establish a parent class, or even define a role.
Let's see how it does it.</p>
</section>
<section id="section-2">
<h2>Importing Pragma and Functionality</h2>
<p>Most of the authors in the modern Perl commmunity recommend that all Perl code use the <a href="https://metacpan.org/pod/strict">strict</a> and <a href="https://metacpan.org/pod/warnings">warnings</a> pragmas.
Like many of the major Perl object frameworks, <a href="https://metacpan.org/pod/Moose">Moose</a> and <a href="https://metacpan.org/pod/Moo">Moo</a> included, Mojo::Base feels these are important enough that it imports them for you.
Unlike those others, it goes further.</p>
<p>Since the modern web is trending towards UTF-8 encoding, the <a href="https://metacpan.org/pod/utf8">utf8</a> pragma is loaded; this enables you to use UTF-8 encoded characters right in your script.
Mojolicious does much of your web-facing encoding for you so this <strong>almost</strong> means you don't have to think about character encoding at all!</p>
<p>And because Mojolicious itself requires Perl 5.10, it also enables all of the <a href="https://metacpan.org/pod/feature">features</a> that came with that version.
This includes <a href="https://www.effectiveperlprogramming.com/2009/12/perl-5-10-new-features/">handy functionality</a> like the <code>state</code> and <code>say</code> keywords as well as the defined-or operator <code>//</code>.
Finally it imports IO::Handle so that all of your handles behave as objects (if you don't know what that means or why, don't worry about it).</p>
<p>If this is the only thing you want from Mojo::Base, perhaps in a script or a test file, all you do is pass the <code>-strict</code> flag</p>
<pre><code>use Mojo::Base -strict;
</code></pre>
<p>and you get everything listed above.
Otherwise, if you use the class or roles functionality then these imports come along for free.</p>
<h3>Experimental Signatures</h3>
<p>In the past few years, Perl has added <a href="https://metacpan.org/pod/perlsub#Signatures">signatures</a> to subroutines as an <a href="https://metacpan.org/pod/perlexperiment">experimental</a> feature.
With Mojolicious' emphasis on non-blocking functionality, and the frequent use of callbacks that that entails, the Mojo community has been especially anxious to use them.
However since these are still experimental, and are still subject to change, when Mojo::Base recently added this functionality, it was decided that it should be an additional opt-in flag.
Using it, suddenly</p>
<pre><code>use Mojo::Base -strict;
$ua->get('/url' => sub {
my ($ua, $tx) = @_;
...
});
</code></pre>
devdata/https_mojolicious.io_blog_2017_12_12_day-12-more-than-a-base-class view on Meta::CPAN
<p>becomes</p>
<pre><code>use Mojo::Base -strict, -signatures;
$ua->get('/url' => sub ($ua, $tx) { ... });
</code></pre>
<h2>Establishing a Class</h2>
<p>Now for the functionality that the name implies, setting up a class.
The Mojo stack modules make LOTS of objects in the course of performing their tasks, from making or handling HTTP requests to processing HTML documents, object creation time is key.
Therefore the primary feature of Mojo::Base classes is speed!</p>
<p>The object system is spartan even when compared to Moo.
You get a hash-based object with declarative read/write lazy accessors and a constructor.
When considering Moose vs Moo, you trade lesser-used features for a noticable performance gain.
Likewise when you consider Mojo::Base vs Moo, you strip down futher, this time to the bare essentials, but again get a performance gain.</p>
<p>Now if you need more functionality, you are more than welcome to use Moo or other object systems in your applications (though the Mojo internals will of course continue to use Mojo::Base).
That said, much of the real world usage of Moo is very similar to Mojo::Base: lazy accessor generation; this might be all you need.</p>
<p>To declare a new class with Mojo::Base, one with no other parent classes, you use the <code>-base</code> flag.</p>
<pre><code>package My::Class;
use Mojo::Base -base;
</code></pre>
devdata/https_mojolicious.io_blog_2017_12_12_day-12-more-than-a-base-class view on Meta::CPAN
->text;
</code></pre>
<p>Frequent users of such Javascript libraries as <a href="https://jquery.com/">jQuery</a> or <a href="https://lodash.com/">lodash</a> will find this type of chaining very familiar.
Once you get the hang of this style it is <a href="https://metacpan.org/pod/MooX::ChainedAttributes">hard to let go of it</a>.
In a future post I intent to discuss several of the fluent interfaces that the Mojo stack provides.</p>
<h3>The tap Method</h3>
<p>Speaking of fluent interfaces, Mojo::Base provides an interesting method called <code>tap</code>, which is (in comp-sci terms) a <a href="https://en.wikipedia.org/wiki/SKI_combinator_calculus">K-combinator</a>.
This is a more advanced feature, but it allows you to insert a non-chainable call into a method chain without breaking it.
The first argument is the method or callback to be called, any additional arguments are passed to the tapped subroutine.
Within that subroutine the invocant is available as the first argument (before any passed arguments) or as <code>$_</code>.</p>
<p>If you had a proxy that you needed to setup before running the previous example, you could do</p>
<pre><code>my $title = Mojo::UserAgent->new
->max_redirects(10)
->tap(sub { $_->proxy->detect })
->get('http://mojolicious.org')
->res
devdata/https_mojolicious.io_blog_2017_12_13_day-13-more-about-roles view on Meta::CPAN
Briefly stated, roles enable composing functionality (usually methods) into a class without without implying a change of inheritence.
Said another way, roles let you specify what a class does without changing what it is.
For a better description, check out Toby Inkster's article <a href="http://radar.oreilly.com/2014/01/horizontal-reuse-an-alternative-to-inheritance.html">Horizontal Reuse: An Alternative to Inheritance</a>.</p>
<p>An important utility of roles is that you can easily use more than one role at the same time in the same consuming class.
With inheritance, especially of third-party functionality, you have to choose one set of extensions to utilize.
This is because the author of the subclass establishes the inheritance.
In roles, the user determines which roles to compose into the base class.</p>
<p><a href="/blog/2017/12/12/day-12-more-than-a-base-class">Yesterday</a> I ended the discussion of <a href="http://mojolicious.org/perldoc/Mojo/Base">Mojo::Base</a> before discussing the roles support.
Added in several installments between Mojolicious versions <a href="https://metacpan.org/release/SRI/Mojolicious-7.40">7.40</a> and <a href="https://metacpan.org/release/SRI/Mojolicious-7.55">7.55</a>, this role support is one of the most recently ad...
The role handling comes from <a href="https://metacpan.org/pod/Role::Tiny">Role::Tiny</a> which is an optional dependency in Mojolicious, but is required in order to use the functionality that I will describe.</p>
</section>
<section id="section-2">
<p>This is not to say that roles couldn't be or weren't used in Mojolicious before then, only that Mojo::Base didn't include any special handling to make it user-friendly.
Prior to the functionality being formally available from Mojo::Base, a few roles were available for Mojo stack classes on CPAN.
To my knowledge they all used Role::Tiny, but they had to roll their own composition mechanisms, presenting some barrier to use.</p>
<h2>Creating Roles</h2>
devdata/https_mojolicious.io_blog_2017_12_13_day-13-more-about-roles view on Meta::CPAN
requires 'find';
has custom_selector => 'a';
sub find_custom {
my $self = shift;
return $self->find($self->custom_selector);
}
</code></pre>
<p>This example shows three interesting features.
First is that even though it is not a class, the package still gets Mojo::Base's <a href="http://mojolicious.org/perldoc/Mojo/Base#has">has</a> keyword, used to make accessors for attributes.
Second is that a new keyword, <code>requires</code>, has been added, coming from <a href="https://metacpan.org/pod/Role::Tiny#requires">Role::Tiny</a>.
This keyword tells the role that it can only be composed into a class that provides a <code>find</code> method.
Consider the new <code>find_custom</code> method, since it uses <code>find</code> if the class it is composed into didn't provide that method our new method couldn't behave as expected.</p>
<p>Indeed several keywords are imported from Role::Tiny including <code>with</code> to compose other roles and several method modifiers coming from <a href="https://metacpan.org/pod/Class::Method::Modifiers">Class::Method::Modifiers</a> (which is an ...
While I won't discuss these in depth, if you need to change how a method from a consuming class works by adding behavior before and/or after that method, check out method modifiers.</p>
<p>The third thing you might notice is the name of the package that I chose.
The only thing that limits what classes the role can be consumed by is the <code>requires</code> keyword.
devdata/https_mojolicious.io_blog_2017_12_14_day-14-you-promised-to-call view on Meta::CPAN
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Two hands with interlocked pinkies, a pinky swear" src="/blog/2017/12/14/day-14-you-promised-to-call/pinky_swear.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>A new feature of <a href="http://mojolicious.org/">Mojolicious</a>, as of <a href="https://metacpan.org/release/SRI/Mojolicious-7.49">7.49</a>, is the implementation of the <a href="https://promisesaplus.com/implementations#in-ot...
</section>
<section id="section-2">
<h2>Background</h2>
<p>"Normal" Perl code runs synchronously: it does each step it is told to, one at a time, and only that. This is also known as "blocking", since the program cannot do anything else.</p>
<p>The essence of a non-blocking code framework is that if you are waiting for something, you can register with the framework what to do when that thing happens. It can then do other processing tasks in the meantime. This means you don't have lot...
<p>Originally this was done just using callbacks, but this lead to what is known as "callback hell": each callback contains the next callback, at an increasing level of indentation. Even harder to keep track of is if the functions are kept ...
devdata/https_mojolicious.io_blog_2017_12_15_day-15-start-a-new-yancy-app view on Meta::CPAN
<a href="http://metacpan.org/pod/Yancy::Backend::Dbic">DBIx::Class</a>.</p>
</section>
<section id="section-2">
<h2>Demonstration</h2>
<p>For an demonstration application, letâÂÂs create a simple blog using
<a href="http://mojolicious.org/perldoc/Mojolicious/Lite">Mojolicious::Lite</a>.
First we need to create a database schema for our blog posts. Let's use
<a href="http://metacpan.org/pod/Mojo::Pg">Mojo::Pg</a> and its <a href="http://metacpan.org/pod/Mojo::Pg::Migrations">migrations
feature</a> to create a table
called "blog" with fields for an ID, a title, a date, some markdown, and
some HTML.</p>
<pre><code class="hljs"><span class="hljs-comment"># myapp.pl</span><span class="hljs-comment">
</span><span class="hljs-keyword">use</span> <span class="hljs-function">Mojolicious::Lite</span>;
<span class="hljs-keyword">use</span> <span class="hljs-function">Mojo::Pg</span>;
<span class="hljs-keyword">my</span> <span class="hljs-type">$pg</span> = <span class="hljs-function">Mojo::Pg</span>->new( '<span class="hljs-string">postgres://localhost/blog</span>' );
<span class="hljs-type">$pg</span>-><span class="hljs-type">migrations</span>-><span class="hljs-type">from_data</span>-><span class="hljs-type">migrate</span>;
devdata/https_mojolicious.io_blog_2017_12_16_day-16-the-secret-life-of-sessions view on Meta::CPAN
Any requests with valid sessions will still work.
The reply they receive will contain a new session cookie, as always, but this time it will be issued using the new secret!</p>
<p>Requests issued by the old credentials will slowly be replaced by new ones as clients each make their first requests following the change.
Once you wait long enough that any valid session cookie would have expired, you can remove the old secret from the configuration and restart again.</p>
<h2>Restarting</h2>
<p>This is a good time to mention <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Cookbook#Hypnotoad"><code>hypnotoad</code></a>.
It is Mojolicious' recommended production application server.
It has many of the same characteristics as the <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Cookbook#Pre-forking"><code>prefork</code></a> server but with some tuned settings and one killer feature, <a href="http://mojolicious.org/perld...
<p>Note that on native Windows, <code>hypnotoad</code> will not work.
That said, it works great on the new <a href="https://blogs.msdn.microsoft.com/wsl/">Windows Subsystem for Linux</a>!</p>
<p>A major usage difference is that hypnotoad (for technical reasons) can't use command line parameters.
Instead it takes its parameters via configuration.
It also starts on port <code>8080</code> rather than <code>3000</code> to prevent accidentally exposing your development servers unexpectedly.
For now however, let's set it back, more for an example than any particular reason.</p>
<pre><code class="hljs">{
devdata/https_mojolicious.io_blog_2017_12_17_day-17-the-wishlist-app view on Meta::CPAN
<div class="post-content">
<section id="section-1">
<p>For today's article, I really wanted to demonstrate concepts using a practical example appliation.
It is possible I let the exaxmple get away from me!</p>
<p>In today's article I indend to show how to use template composition techniques to produce a wishlist app.
We will cover <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Rendering#Layouts">layouts</a>, <a href="http://mojolicious.org/perldoc/Mojolicious/Guides/Rendering#Partial-templates">partial templates</a>, <a href="http://mojolicious.org/pe...
<p>The data model is admittedly rough, however I think my plan will be to make that a feature and not a bug.
Today we will example concepts mostly relating to the templates, then in tomorrows post I will migrate the model from using the simplistic persistence of <a href="https://metacpan.org/pod/DBM::Deep">DBM::Deep</a> that it uses now to <a href="https://...
</section>
<section id="section-2">
<p>At that point I hope to put the application into a repository of its own.
In the meantime however, you can see the application in the source for this <a href="https://github.com/MojoliciousDotIO/mojolicious.io/tree/master/blog/2017/12/17/day-17-the-wishlist-app/wishlist">article</a>.
To run it, you will need to install two additional modules, DBM::Deep and <a href="https://metacpan.org/pod/LinkEmbedder">LinkEmbedder</a>.</p>
<pre><code>$ cpanm Mojolicious DBM::Deep LinkEmbedder
</code></pre>
devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model view on Meta::CPAN
</div>
<div class="post-thumb">
<!-- theme suggests 1300x500 -->
<img alt="Still Life: Vase with Pink Roses by Vincent van Gogh" src="/blog/2017/12/18/day-18-the-wishlist-model/van_gogh_still_life.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p><a href="https://mojolicious.io/blog/2017/12/17/day-17-the-wishlist-app/">Yesterday</a> we discussed templates features like layouts, partial templates, and content buffers.
We motivated the discussion by introducing a fully functioning example application that tracked user's Christmas wishlists.
That application did lack sophistication in the area of data storage, using <a href="https://metacpan.org/pod/DBM::Deep">DBM::Deep</a> for quickly getting a basic persistence layer.
While that worked well enough to demonstrate template functionality it was no triumph of the model layer.
Indeed some very hack techniques are used, especially in manipulating wishlist items, since there was no unique record ids.</p>
<p>Well as promised I have created a <a href="https://github.com/jberger/Wishlist">repository</a> for the application on Github.
I have also added several tags.
While development on the application may continue, those tags will remain for future readers.</p>
<p>The initial form of the application (as seen in yesterday's post) is tagged <a href="https://github.com/jberger/Wishlist/tree/blog_post/dbm_deep"><code>blog_post/dbm_deep</code></a>.
devdata/https_mojolicious.io_blog_2017_12_18_day-18-the-wishlist-model view on Meta::CPAN
However some developers like staying a little closer to the SQL.</p>
<h2>Mojo-Flavored DBI</h2>
<p>The Mojolicious community has several modules that live partway between DBI and DBIx::Class.
I lovingly call them "Mojo-Flavored DBI" collectively.
The first of these was <a href="https://metacpan.org/pod/Mojo::Pg">Mojo::Pg</a> for <a href="https://www.postgresql.org/">PostgreSQL</a>.
Quickly, copycat modules were made, <a href="https://metacpan.org/pod/Mojo::mysql">Mojo::mysql</a> for <a href="https://www.mysql.com/">MySQL</a> and <a href="https://metacpan.org/pod/Mojo::SQLite">Mojo::SQLite</a> for the embedded database <a href="...
<p>These are attractive because they are lightweight in comparison to ORMs.
They feature schema migration management and similar <a href="https://mojolicious.io/blog/2017/12/12/day-12-more-than-a-base-class/">fluent interfaces</a> as Mojolicious.
They handle connection pooling and nonblocking access (emulated in the case of SQLite).
In recent versions, they also wrap <a href="https://metacpan.org/pod/SQL::Abstract">SQL::Abstract</a> which can be used to simplify certain common actions.
SQL::Abstract is also used by DBIx::Class, so as you'd expect, these have a feel similar to an ORM.</p>
<p>Going forward with this article, I will use Mojo::SQLite since it doesn't require an external database.</p>
<h2>The Schema</h2>
<p>The first thing we need to establish is the database schema; the collection of tables and their columns.
In Mojo-Flavored DBI these are collected into one file, broken up by comments.
devdata/https_mojolicious.io_blog_2017_12_19_day-19-make-your-app-installable view on Meta::CPAN
Indeed such a transform exists already exists in the Wishlist app but was omitted above for clarity.</p>
<h2>In Conclusion</h2>
<p>I have made some of these changes to the <a href="https://github.com/jberger/Wishlist/compare/blog_post/sqlite_model...blog_post/installable">Wishlist App</a>.
You'll see that it it really isn't much to do.</p>
<p>You also see that I only used as much of these instructions as I needed; you can do the same.
There is no magic in any of what you've seen (other than perhaps File::Share).
If you don't need to think about theming or customizing the environment variable, then don't worry about it.
But if you find yourself in that situation, you'll know you can make such features available to your users.</p>
<p>And hey, if it is a useful application, consider uploading it to CPAN.
Though I warn you, once you start contributing to CPAN it can be addictive!</p>
</section>
<small><p><a href="https://en.wikipedia.org/w/index.php?curid=31630711">Image</a> by Gnovick - Own work, <a href="https://creativecommons.org/licenses/by/3.0/" title="Creative Commons Attribution 3.0">CC BY 3.0</a>.</p>
</small>
<p class="tags">
<span>Tagged in </span>:
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2017;
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/page/advent/2017/] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"App::cpanminus"},{module=>"Mojo:...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2017
__END__
=pod
=encoding UTF-8
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017.pm view on Meta::CPAN
=item * L<XMLRPC::Fast>
=item * L<Moo>
=item * L<MooX::ChainedAttributes>
=item * L<MooX::StrictConstructor>
=item * L<Moose>
=item * L<feature>
=item * L<strict>
=item * L<utf8>
=item * L<warnings>
=item * L<Class::Method::Modifiers>
=item * L<List::UtilsBy>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_01.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_02.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_03.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_04.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_05.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_06.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_09.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_10.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_11.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_12.pm view on Meta::CPAN
package Acme::CPANModules::Import::MojoliciousAdvent::2017_12_12;
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/2017/12/12/day-12-more-than-a-base-class] (retrieved on 2018-12-30). Visit the URL for the full contents.",entries=>[{module=>"Mojo...
1;
# ABSTRACT: Modules mentioned in Mojolicious Advent Calendar 2017 (day 12)
__END__
=pod
=encoding UTF-8
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_12.pm view on Meta::CPAN
=item * L<Mojo::Base>
=item * L<Moo>
=item * L<MooX::ChainedAttributes>
=item * L<MooX::StrictConstructor>
=item * L<Moose>
=item * L<feature>
=item * L<strict>
=item * L<utf8>
=item * L<warnings>
=back
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_13.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_14.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_15.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>
lib/Acme/CPANModules/Import/MojoliciousAdvent/2017_12_16.pm view on Meta::CPAN
=head1 HOMEPAGE
Please visit the project's homepage at L<https://metacpan.org/release/Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 SOURCE
Source repository is at L<https://github.com/perlancar/perl-Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>.
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Acme-CPANModulesBundle-Import-MojoliciousAdvent-2017>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 SEE ALSO
L<Acme::CPANModules> - about the Acme::CPANModules namespace
L<cpanmodules> - CLI tool to let you browse/view the lists
=head1 AUTHOR
perlancar <perlancar@cpan.org>