<?xml version="1.0" encoding="utf-8"?>
    <rss version="2.0">
        <channel>
            <title>genehack.org</title>
            <link>http://genehack.org/</link>
            <description></description>
            <language>en</language>
            <copyright>Copyright 2012</copyright>
            <lastBuildDate>Wed, 09 May 2012 08:19:16 -0500</lastBuildDate>
            <generator>http://www.sixapart.com/movabletype/</generator>
            <docs>http://www.rssboard.org/rss-specification</docs>
    
            <item>
                <title>CSA week 1 </title>
                <description><![CDATA[<p>Yesterday was our first <a href="http://sandyspringcsa.com/">Sandy Spring CSA</a> pickup of the year &#8212; we&#8217;ve got 24 more before we&#8217;re done, running through October 22nd. I don&#8217;t know that I&#8217;ll stick with doing this every week (Historical Record Magic 8-Ball sez: &#8220;HAHAHAHAHAHAHA&#8221;), but here&#8217;s what we got and what I&#8217;m planning on doing with it:</p>

<p>First, what was in the box, in no particular order:</p>

<ul>
<li>1 bunch baby scarlet turnips</li>
<li>1 bunch red radishes</li>
<li>2 bunches collard greens</li>
<li>1 bunch scallions</li>
<li>2 heads of lettuce (1 &#8220;butterhead&#8221;, 1 &#8220;green leaf&#8221;)</li>
<li>1 bunch purple <a href="https://en.wikipedia.org/wiki/Mizuna">mizuna</a></li>
<li>2 heads baby bok choy</li>
<li>1 bunch of carrots</li>
</ul>

<p>(There was another big head of bok choy in the box, but I swapped that for a second bunch of collard greens out of the Swap Box.)</p>

<p>Here&#8217;s my menu list for the next week, which manages to use everything except the greens from the carrots, radishes, and turnips (and even those will probably migrate into a salad mix at some point&#8230;)</p>

<ul>
<li>Wednesday: lettuce salad with mushrooms, radishes, cherry tomatoes, grilled chicken, and balsamic vinaigrette </li>
<li>Thursday: collard green stew with chorizo and garlic</li>
<li>Friday: hamburgers, roasted turnip fries with Parmesan</li>
<li>Saturday: carnitas tacos con guacamole y pico de gallo (requested by <a href="https://twitter.com/#!/MrsGenehack">@MrsGenehack</a> for Mother&#8217;s Day&#8230;)</li>
<li>Sunday: bok choy / mizuna / tofu stir fry + cooking down chicken stock (this is where the carrots are headed)</li>
<li>Monday: lettuce salad with mushrooms, radishes, grilled steak, and balsamic vinaigrette (and maybe some additional greens)</li>
<li>Tuesday: mexi-melt chicken surprise</li>
</ul>

<p>(Wikipedia has a nice <a href="https://en.wikipedia.org/wiki/Community-supported_agriculture">CSA</a> article if you&#8217;re all &#8220;WAT.&#8221;)</p>
]]></description>
                <link>http://genehack.org/2012/05/csa_week_1/</link>
                <guid>http://genehack.org/2012/05/csa_week_1/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">CSA</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">cooking</category>
        
                <pubDate>Wed, 09 May 2012 08:19:16 -0500</pubDate>
            </item>
    
            <item>
                <title>Yak Butter Makes The Best Shaving Cream</title>
                <description><![CDATA[<p>This morning, I was finishing off my coffee and reading the morning
email -- as you do -- when I came across a <a href="https://rt.cpan.org/Ticket/Display.html?id=76860">bug report</a> for
<a href="http://genehack.github.com/Git-Wrapper/">Git::Wrapper</a>, a module I maintain. It turned out that a recent
change I'd made to my workflow (archiving older releases in my working tree)
had resulted in the archived releases being included in the version of the
software I'd packaged and put on <a href="http://www.cpan.org/">CPAN</a> for distribution. </p>

<p>Whoops! I needed to fix the problem and get a new release uploaded to CPAN as soon as possible, and
since it was a quiet Saturday morning and I had about an hour free
before I needed to run some errands for <a href="https://twitter.com/#!/mrsgenehack">@MrsGenehack</a>, I didn't expect it
would be a big deal. I use <a href="http://dzil.org/">Dist::Zilla</a> to help me package up
Git::Wrapper for distribution, so I figured it would just be a simple matter of
tweaking the configuration in the <code>dist.ini</code> file in my working copy
and then releasing a new version to CPAN. How long could it take, really? </p>

<p><em>(Enter First Yak, stage right, with bouffant rampant...)</em></p>

<p>I tried a couple of different approaches to changing the configuration
so that it would do what I wanted, and couldn't quite get the syntax
right. Instead of continuing to pound my head into a wall, I
hopped onto the <code>#distzilla</code> channel on <a href="http://irc.perl.org">irc.perl.org</a> and asked
for help. <a href="http://rjbs.manxome.org/">RJBS</a> (author of Dist::Zilla, current Perl pumpking, and
generally nice guy) quickly pointed out where I was going wrong and
got me on the right path.</p>

<p>I was working on the problem in a <a href="http://www.emacswiki.org/emacs/MultiTerm">MultiTerm</a> buffer in my editor,
Emacs. I'm giving a talk on
<a href="http://act.yapcna.org/2012/talk/127">editor tweaks for more effective programming</a> at <a href="http://yapcna.org/">YAPC::NA</a> this
year, and as part of prepping for that, I'm trying to do as much work
as possible inside my editor. This was working great for this
particular problem -- I could make changes to my <code>dist.ini</code> file and
quickly jump over to the terminal window to run <code>dzil</code> commands and
verify the distribution was getting built correctly.</p>

<p>This was working really well, <em>except</em> that I kept getting
distracted by some highlighting irregularities -- and since the talk
was on my mind, I realized I wasn't going to be able to present at
YAPC with those ugly background glitches present. Obviously, taking a
couple of minutes to clean that up would be time well spent...</p>

<p><em>(Enter Second Yak, stage left, somewhat hirsute than previous yak...)</em></p>

<p>Since most of the highlighting problems seemed to be around the color
highlighting in the output of the <code>ls</code> command, I spent a while poking
at the <code><a href="https://github.com/genehack/etc/blob/master/dircolors.ansi-dark">dircolors</a></code> config file I use. I copied this from someplace
on the Internets and I've never really taken the time to understand
it -- it just worked -- so this was mostly poking of the "change
something, see what happens" variety. After a few minutes of failing
with this approach, I started to wonder if I was barking up the wrong
tree. A bit of <a href="http://duckduckgo.com/">DuckDuckGo</a>-ing later, I made a <a href="https://github.com/genehack/emacs/commit/8b8cca7a5b72eb99fd38063bb6ed3a5674d2e636">quick tweak</a>
to my Emacs config, which fixed the highlighting problem. </p>

<p><em>(Exit Second Yak, now smooth and free of hair)</em></p>

<p>That taken care of, I returned to the issue of the Git::Wrapper
distribution problem. Before I got diverted by the Emacs shell issue,
I'd noticed a few other things in the <code>dist.ini</code> file that I could
improve. I <a href="https://github.com/genehack/Git-Wrapper/commit/7bc872e3662690fa1ab33b920cd1518946b50b64">took care of that</a>, built a new release, and uploaded it to
CPAN. I let the bug reporter know, and closed out the ticket. </p>

<p><em>(Exit First Yak, now also denuded.)</em></p>

<p>One of the changes I'd made to the <code>dist.ini</code> was updating the
metadata to point to the new
<a href="http://genehack.github.com/Git-Wrapper/">Git::Wrapper homepage</a> and to the <a href="https://github.com/genehack/Git-Wrapper/issues">issue tracker</a> for Git::Wrapper on
Github. The <a href="http://metacpan.org/">MetaCPAN</a> site uses this information to set up the links
in the sidebar on the <a href="https://metacpan.org/module/Git::Wrapper">Git::Wrapper release page</a>, so I hopped over
there to verify that I'd done everything correctly.</p>

<p>All the links were working correctly, but a Github specific popup was
appearing over my homepage link -- which seemed wrong. I jumped on the
<code>#metacpan</code> channel to see if this had already been reported, and
ended up having a short conversation with <a href="http://shadow.cat/blog/matt-s-trout/">MST</a> that resulted in me
opening <a href="https://github.com/CPAN-API/metacpan-web/issues/561">an issue</a> ... which I ended up assigning to myself. (MST: manipulating
people into open source contributions for fun and profit.)</p>

<p><em>(Enter Bonus Yak, descending from the rafters and bearing a strong
similarity to MST, at least on the hairdo level... )</em></p>

<p>I looked at the issue briefly, but as I'd now used up about 1.5 hours
of my free hour, I had to let it sit briefly while I took care of
those errands. Once I got back, I spent another 30 minutes figuring
out the issue. After I was sure I'd got it taken care of, I sent in a
<a href="https://github.com/CPAN-API/metacpan-web/pull/562">pull request</a>, which has since been <a href="https://github.com/CPAN-API/metacpan-web/commit/ed36ae93d512dbb4aba605ae0de39b78bff23eae">merged</a> -- the bug is no longer visible on the
MetaCPAN site).</p>

<p><em>(Exit Bonus Yak, freed of hair and looking not unlike <a href="http://img.skitch.com/20100519-jy3h8chcxmpcei36bnfkdcp6fm.jpg">MST would have</a>
if he hadn't backed out of the "transparent" option when losing the
Iron Man Perl challenge...)</em></p>

<p>Anyway, that's my Saturday morning - three yaks shaved, 2 patches to
open source projects, 1 editor config tweak, and some good raw
material to fold into my talk. Hope you enjoyed the tale... </p>

<p>(For those of you wondering about the yak thing, "<a href="https://en.wiktionary.org/wiki/yak_shaving">yak shaving</a>" is a
geeky way to describe what happens when you're trying to accomplish
one thing, but get diverted off on solving a chain of seemingly
unrelated problems instead.)</p>

<p>(Hat tip to Josh <a href="http://paperbits.net/">paperbits</a> DiMauro for the title...)</p>]]></description>
                <link>http://genehack.org/2012/04/yak_butter_makes_the_best_shaving_cream/</link>
                <guid>http://genehack.org/2012/04/yak_butter_makes_the_best_shaving_cream/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">emacs</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">git</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">git::wrapper</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">github</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">metacpan</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">perl</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">yaks</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">yapc</category>
        
                <pubDate>Sun, 29 Apr 2012 00:46:28 -0500</pubDate>
            </item>
    
            <item>
                <title>Jacquard: Not dead yet</title>
                <description><![CDATA[<p>I apologize for the lack of recent Jacquard entries &#8212; I had a few posts buffered up with the intent that I would be able to keep regularly posting even if I couldn&#8217;t maintain a regular rate of writing and developing &#8212; but then Skyrim came out, and my buffer got empty, and well, yeah. Here we are. I hope to pick up the project and the writing again now that the end-of-year/beginning-of-year madness has now mostly died down, so watch this space.</p>

<p>(ObSkyrim link: <a href="https://twitter.com/#!/SkyrimMom">@SkyrimMom</a>)</p>
]]></description>
                <link>http://genehack.org/2012/01/jacquard_not_dead_yet/</link>
                <guid>http://genehack.org/2012/01/jacquard_not_dead_yet/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">jacquard</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">perl</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">skyrim</category>
        
                <pubDate>Sun, 15 Jan 2012 14:56:52 -0500</pubDate>
            </item>
    
            <item>
                <title>Cleaning out the buffer </title>
                <description><![CDATA[<ul>
<li>Like Girl Talk? Like dance? Just like cool shit? Go watch all the <a href="http://girlwalkallday.com/watch-the-film/">Girl Walk videos</a>. Right now. </li>
<li>It&#8217;s okay, really. I&#8217;ll wait. Go watch <a href="http://girlwalkallday.com/watch-the-film/">that shit</a>.</li>
<li>This is a <a href="http://www.hertzmann.com/articles/2003/mise/">really good article</a> about the principle of mise en place. Lots of application to stuff beyond cooking. (And if you&#8217;re going &#8220;mise what?&#8221;, then you should certainly read it.)</li>
<li>Excellent, excellent <a href="http://thisismadebyhand.com/">inspiring videos</a> from makers of things. If anybody is interested in giving me a very expensive gift, those knives look to be the shizzle. (Link via <a href="http://www.onemogin.com/">gphat</a>.)</li>
<li><a href="http://mdk.per.ly/2011/05/28/cry-havoc-and-let-slip-the-raptors/">Future tattoo material</a>.</li>
</ul>
]]></description>
                <link>http://genehack.org/2012/01/cleaning_out_the_buffer/</link>
                <guid>http://genehack.org/2012/01/cleaning_out_the_buffer/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">dance</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">development</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">maker</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">tattoo</category>
        
                <pubDate>Sun, 15 Jan 2012 13:56:17 -0500</pubDate>
            </item>
    
            <item>
                <title>Tab dump // 20111107</title>
                <description><![CDATA[<ul>
<li>Thanks to Gabor for the Jacquard shout out in the <a href="http://perlweekly.com/archive/15.html">latest Perl Weekly</a>. If you&#8217;re into Perl, you should subscribe to this newsletter, it&#8217;s a good roundup of Perl-related stuff from around the web.</li>
<li><a href="http://pastebin.com/raw.php?i=FD3xe6Jt">MongoDB sucks</a>. <a href="http://news.ycombinator.com/item?id=3202081">No, it doesn&#8217;t</a>. (Former link from everywhere; latter from the comments over at <a href="http://www.flutterby.com/archives/comments/14836.html">Flutterby</a>.)</li>
<li>Charlie Stross on <a href="http://www.antipope.org/charlie/blog-static/2011/11/evil-social-networks.html">Evil Social Networks</a>. Quoted for Truth: &#8220;If you&#8217;re not paying for the product, you <strong>are</strong> the product.&#8221;</li>
<li><a href="http://www.feld.com/wp/archives/2011/10/be-on-fire.html">Be On Fire</a> - &#8220;YOU. MUST. BURN.&#8221; </li>
</ul>
]]></description>
                <link>http://genehack.org/2011/11/tab_dump_20111107/</link>
                <guid>http://genehack.org/2011/11/tab_dump_20111107/</guid>
        
        
                <pubDate>Mon, 07 Nov 2011 21:23:07 -0500</pubDate>
            </item>
    
            <item>
                <title>Jacquard 04: Extending The Data Model</title>
                <description><![CDATA[<p>Since our previous installment got us
<a href="http://genehack.org/2011/11/setting_up_jacquard_authentication/">users and authentication</a>, we&#8217;re ready to start
adding support for various services. One of the features of Jacquard
&#8212; one of the main <em>points</em> of Jacquard, actually &#8212; is interacting
with multiple services. To make that possible, we&#8217;ve included the
<code>accounts</code> attribute in our User class:</p>

<pre class="brush:perl">
# this attribute is going to contain info about all the services
# this user has configured -- i.e., there will be one for Twitter,
# one for Facebook, etc.
has accounts => (
  isa     => 'KiokuDB::Set',
  is      => 'ro',
  lazy    => 1 ,
  default => sub { set() },
);
</pre>

<p>Before we start actually writing the code for the things that are
going to be inside those <code>accounts</code> attributes, it&#8217;s worth stepping
back and thinking about what the data we want to store looks like,
and how we can best structure our classes to help us manipulate that
data.</p>

<p>Ideally, what we want &#8212; and again, this is a reflection of the
underlying <em>raison d&#8217;etre</em> of Jacquard &#8212; is to be able to interact
with all the different services we support in the same way without
having to worry how each individual service handles fetching new
posts, or writing a new post out. In other words, to be able to do
something like this:</p>

<pre class="brush:perl">
# warning: pseudocode
foreach my $account ( $self->accounts->members ) {
  $account->get_new_posts;
}

# or even
my $new_post = get_new_post_from_user();
foreach my $account ( $self->accounts->members ) {
  $account->post( $new_post )
}
</pre>

<p>Since we&#8217;re using <a href="http://moose.iinteractive.com/">Moose</a>, we&#8217;re going to have a number of
<code>Jacquard::Schema::Account::FOO</code> classes, one for each type of service
we&#8217;re going to interact with. Each of those classes will consume an
API-defining role (called something like
<code>Jacquard::Schema::Role::AccountAPI</code>) that will define the required
methods for the common interface we want all services to have &#8212; that
is, making sure they support a <code>get_new_posts</code> method, and a <code>post</code>
method, and so forth.</p>

<p>We also need to think about how to structure the other data associated
with services. That data will fall into two broad categories: account
information (and similar data, like authentication tokens, etc.) and
posts on that service. Depending on the exact service, the details of
what a &#8216;post&#8217; is will differ &#8212; a tweet is not quite a FaceBook post,
and both are very distinct from a blog post entry in an Atom feed &#8212;
but they share enough commonalities that we can again take a similar
approach: a number of <code>Jacquard::Schema::Post::FOO</code> classes, each
consuming a <code>Jacquard::Schema::Role::PostAPI</code> role that ensures that
they&#8217;re implementing a common API.</p>

<p>The benefit of this approach is that it becomes relatively trivial to
add support for new services &#8212; particularly if there&#8217;s already a
module on <a href="http://metacpan.org">CPAN</a> to handle interacting with that service. As
we&#8217;ll see in a number of upcoming posts, taking an existing library
and wrapping it in a layer of Moose class to implement a particular
API is <em>very</em> little work. </p>

<p>I often find it helpful, when I&#8217;ve gotten to this point in the process
of designing something and I think have a workable solution, to work
out how a small set of data would map across instances of these
classes. Let&#8217;s consider how a single Jacquard user, with a Twitter
account configured within Jacquard, would look once a few tweets were
stored:</p>

<pre class="brush:perl">
# first, the user
my $user = Jacquard::Schema::User->new( name => 'Bob' );

# then we add the account
$user->add_account( 'Twitter' , %account_details );

# and then we get the most recent posts
$user->get_account( 'Twitter' )->get_new_posts();
</pre>

<p>And for this design, this is the point where I realize I haven&#8217;t
really thought at all about how the individual <code>Post</code> objects will be
associated with the <code>Account</code> object. The simplest way to do this
would be for the <code>Account</code> classes to have a <code>posts</code> attribute, much
like the <code>accounts</code> attribute in the <code>User</code> class:</p>

<pre class="brush:perl">
has posts => (
  isa     => 'KiokuDB::Set',
  is      => 'ro',
  lazy    => 1 ,
  default => sub { set() },
);
</pre>

<p>Assuming that is how we go, after that <code>get_new_posts()</code> method above,
we&#8217;d end up with the <code>accounts</code> attribute of <code>$user</code> containing a
<code>KiokuDB::Set</code> object with a single member &#8212; an instance of
<code>Jacquard::Schema::Account::Twitter</code>. Inside that object, there would
be another <code>KiokuDB::Set</code> object with a bunch of members, each one an
instance of <code>Jacquard::Schema::Post::Twitter</code> corresponding to an
individual tweet from this user&#8217;s timeline (and having attributes like
&#8216;author&#8217;, &#8216;content&#8217;, &#8216;datetime&#8217;, &#8216;id&#8217;, and so on).</p>

<p>That all seems to make a reasonable amount of sense &#8212; but there&#8217;s a
looming problem. (If you&#8217;ve already spotted it, give yourself a pat on
the back.) What happens when we add a second <code>User</code>, also with a
Twitter account configured, and that user ends up following some of
the same people on Twitter as our first user? We&#8217;ll end up with <code>Post</code>
objects that are essentially duplicates of each other &#8212; but one copy
will be inside the Twitter <code>Account</code> object of the first user, and the
second will be inside the Twitter <code>Account</code> object of the second. In
the long run, that&#8217;s going to end up being a big waste of storage
space and/or RAM. </p>

<p>How do we solve this problem? We <em>could</em> just maintain a uniform set
of <code>Post</code> objects, and include the same object into different
<code>Account</code> objects as needed. That would solve the issue with the
duplication of information &#8212; but it introduces another issue, in that
we no longer have a place to store per-user metadata about individual
<code>Post</code> objects (e.g., read/unread status). </p>

<p>Instead, we&#8217;ll solve this problem the old fashioned way: we&#8217;ll
introduce another layer of abstraction! Instead of the <code>posts</code>
attribute of <code>Account</code> objects containing <code>Jacquard::Schema::Post</code>
objects directly, we&#8217;ll have a generic <code>Jacquard::Schema::UserPost</code>
object that maps between a <code>User</code> account and a particular
<code>Post</code>. In return for making our data model slightly more complicated,
this approach gives us the best of both worlds, in that we have a place
for per-<code>User</code> metadata to live, but the original <code>Post</code> data is only
present in our system once, regardless of how many of our users have
it present in their <code>Account</code> objects. </p>

<p>This solution also doesn&#8217;t impact any of our previous design
decisions: the <code>Jacquard::Schema::Role::PostAPI</code> can be consumed by
the <code>Jacquard::Schema::UserPost</code> class too, via method delegation to
the <code>Jacquard::Schema::Post::FOO</code> object it refers to. (More about
that later.)</p>

<p>So, now that we&#8217;ve been though a couple of rounds of thinking about
the data structures, we can write some code, yes? Well, no, not
exactly, not quite yet. Instead we&#8217;re going to explore what the
API for using this code might look like, and we&#8217;re going to do <em>that</em>
by writing some test code, or at least outlining some test cases. </p>

<p>First, we&#8217;re going to need to be able to add <code>Account</code> objects to
<code>User</code> objects, and <code>Post</code> objects to <code>Account</code> objects. The code for
that will probably look something like:</p>

<pre class="brush:perl">
## method to associate an Account object with a User
# $model is an instance of Jacquard::Model::KiokuDB, 
# while $user is a Jacquard::Schema::User, 
# and $account->does('Jacquard::Schema::Role::AccountAPI')
$model->add_account_to_user( $account , $user );

## method to add a UserPost object to an Account -- will also save the
## associated Post object if needed 
# $model is an instance of Jacquard::Model::KiokuDB, 
# while $account->does('Jacquard::Schema::Role::AccountAPI')
# and $post->does('Jacquard::Schema::Role::PostAPI')
$model->add_post_to_account( $userpost , $account );
</pre>

<p>(Aside: I spent more time than I am willing to disclose trying to
decide whether the order of arguments in those methods should be &#8216;more
generic object, more specific object&#8217;, or if they should instead be
the same as in the method name &#8212; which is what I finally went with,
reasoning that will serve as a mnemonic.)</p>

<p>We&#8217;ll also need to be able to remove <code>Account</code> objects from <code>User</code>
objects, and modify <code>Post</code> and <code>UserPost</code> objects and save those
changes:</p>

<pre class="brush:perl">
## method to remove an Account object from a user
# $model is an instance of Jacquard::Model::KiokuDB, 
# while $account->does('Jacquard::Schema::Role::AccountAPI')
# doesn't need a user object because $account has an 'owner' attribute
$model->remove_account_from_user( $account );

## method to store a modified Post or UserPost object, e.g. after
## changing some of the metadata, or if the underlying post object is
## updated
# $model is an instance of Jacquard::Model::KiokuDB, 
# while $post->does('Jacquard::Schema::Role::PostAPI')
$model->update_post( $post );
</pre>

<p>Those all look reasonable, at least at first glance. It&#8217;s worth noting
that none of the methods have an explicit return value &#8212; they will
just return true on success (and will likely eventually throw some
sort of exception object on failure). This approach makes the most sense to me,
as it is isolates the model to just marshaling objects to storage. Any
modification or manipulation of the objects will happen elsewhere. </p>

<p>At this point, we&#8217;ve fleshed out the data model more, we have the
beginnings of a plan for implementing the code that will let Jacquard
interact with other services, and we have the outline for how we&#8217;re
going to store and update that data in KiokuDB once we have it. That
seems like a good place to stop. Next time, we&#8217;ll actually implement
the first <code>Account</code> and <code>Post</code> classes! </p>

<p>As always, the code for <a href="https://github.com/genehack/Jacquard">Jacquard</a> is available on
Github. Patches are welcome; share and enjoy.</p>
]]></description>
                <link>http://genehack.org/2011/11/jacquard_04_extending_the_data_model/</link>
                <guid>http://genehack.org/2011/11/jacquard_04_extending_the_data_model/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">catalyst</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">jacquard</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">kioku</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">perl</category>
        
                <pubDate>Mon, 07 Nov 2011 20:27:57 -0500</pubDate>
            </item>
    
            <item>
                <title>Achievement Unlocked: Wear Out A Pair Of Running Shoes</title>
                <description><![CDATA[<p><a href="http://genehack.org/assets_c/2011/11/tired-soldiers-28.html" onclick="window.open('http://genehack.org/assets_c/2011/11/tired-soldiers-28.html','popup','width=2560,height=1920,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://genehack.org/assets_c/2011/11/tired-soldiers-thumb-300x225-28.jpg" width="300" height="225" alt="tired-soldiers.jpg" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /></a></p>

<p>I started running some time in the late summer of 2010, doing the <a href="http://www.c25k.com/">Couch To 5K</a> program. I&#8217;d tried to start running a few other times, and I always had issues with shin splints that would prevent me from establishing any sort of routine. This had been the case for as long as I could remember &#8212; I ran track in my senior year of high school, and I had shin splint problems then too. </p>

<p>The thing that fixed those problems for me was this pair of <a href="http://www.vibramfivefingers.com/index.htm">Vibram Five Fingers KSOs</a>. Running in these hurt at first too &#8212; but it was a different kind of hurt, a more manageable one, and one that got less the more I ran &#8212; the complete opposite of my shin splint problems, in other words. </p>

<p>My last run in these was the Marine Corps Marathon 10K. It was a cold, wet morning, and that hole you can see in the sole of the right shoe didn&#8217;t do me any favors &#8212; but I finished the race. Seemed like a good time to let these tired soldiers get some rest, so today I picked up a new pair of TrekSports. I&#8217;m hoping the slightly thicker sole and treads on the bottom will let me explore some trail running this spring &#8212; and who knows, there&#8217;s a local half marathon in May&#8230; </p>

<p>Those of you that aren&#8217;t familiar with the Vibrams, or the idea of minimalist running, may want to check out <a href="http://www.nytimes.com/2011/11/06/magazine/running-christopher-mcdougall.html?_r=1&amp;pagewanted=all">this NYT article</a> for some background. I can&#8217;t say enough good things about these shoes; they&#8217;ve made it possible for me to run and enjoy it, and that&#8217;s just awesome.</p>
]]></description>
                <link>http://genehack.org/2011/11/achievement_unlocked_wear_out_a_pair_of_running_sh/</link>
                <guid>http://genehack.org/2011/11/achievement_unlocked_wear_out_a_pair_of_running_sh/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">fitness</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">running</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">vibram five fingers</category>
        
                <pubDate>Sun, 06 Nov 2011 22:08:51 -0500</pubDate>
            </item>
    
            <item>
                <title>Jacquard 03: Setting Up Authentication </title>
                <description><![CDATA[<p>In the <a href="http://genehack.org/2011/10/setting_up_jacquard_users">last installment</a>, we created
<code>Jacquard::Schema::User</code> to describe a Jacquard user, and
used <code>Jacquand::Model::KiokuDB</code> (and a helper script) to
persist User objects to storage. This time around, we&#8217;re going to
create our <a href="http://www.catalystframework.org/">Catalyst</a> app and hook up authentication. </p>

<p>So, first step: create the Catalyst application. The
<code>catalyst.pl</code> helper makes this trivial:</p>

<pre class="brush:perl">
$ catalyst.pl Jacquard::Web
created "Jacquard-Web"
created "Jacquard-Web/script"
created "Jacquard-Web/lib"
created "Jacquard-Web/root"
[ couple dozen more lines elided ]
</pre>

<p>Unfortunately, there&#8217;s no easy way to tell it &#8220;I&#8217;m creating this Cat
app as a part of a bigger project&#8221; &#8212; so after creating it, you have
to manually shuffle the files around to get them into the right
place. The Catalyst files also come with quite a bit of templated
stuff in them that we don&#8217;t need (POD skeletons and the like), so
cleaning that up and getting the code into line with your personal
coding style should be done at this point. Once that&#8217;s all done,
checkpointing into revision control is a good idea:</p>

<pre class="brush:plain">
$ git ci -m"Create Catalyst application" 
[03-catalyst 3c20771] Create Catalyst application
 11 files changed, 300 insertions(+), 0 deletions(-)
 create mode 100755 jacquard_web.psgi
 create mode 100644 lib/Jacquard/Web.pm
 create mode 100644 lib/Jacquard/Web/Controller/Root.pm
 create mode 100644 root/favicon.ico
 create mode 100644 root/static/images/btn_88x31_built.png
 create mode 100755 script/jacquard_web_cgi.pl
 create mode 100755 script/jacquard_web_create.pl
 create mode 100755 script/jacquard_web_fastcgi.pl
 create mode 100755 script/jacquard_web_server.pl
 create mode 100755 script/jacquard_web_test.pl
</pre>

<p>Next, we&#8217;re going to use <a href="https://metacpan.org/release/CatalystX-SimpleLogin">CatalystX::SimpleLogin</a> to add
authentication to the application, following the outline in
<a href="https://metacpan.org/module/CatalystX::SimpleLogin::Manual">the manual</a>. First up, add a number of plugins to
the application (in <code>lib/Jacquard/Web.pm</code>):</p>

<pre class="brush:perl">
use Catalyst qw/
    -Debug
    ConfigLoader
    +CatalystX::SimpleLogin
    Authentication
    Session
    Session::Store::File
    Session::State::Cookie
    Static::Simple
/;
</pre>

<p>Create a default View class by running:</p>

<pre class="brush:plain">
./script/jacquard_web_create.pl view TT TT
</pre>

<p>Then create the Catalyst Model class that will wrap
<code>Jacquard::Model::KiokuDB</code>: </p>

<pre class="brush:perl">
package Jacquard::Web::Model::KiokuDB;
use Moose;

use Jacquard::Model::KiokuDB;

BEGIN { extends qw(Catalyst::Model::KiokuDB) }

has '+model_args'  => ( default => sub { { extra_args => { create => 1 }}});
has '+model_class' => ( default => 'Jacquard::Model::KiokuDB' );

__PACKAGE__->meta->make_immutable;
1;
</pre>

<p>We also need to add the configuration for these plugins to the
application config file:</p>

<pre class="brush:plain">
---
name: Jacquard::Web
Model::KiokuDB:
  dsn: dbi:SQLite:dbname=db/jacquard.db
Plugin::Authentication:
  default:
    credential:
      class: Password
      password_type: self_check
    store:
      class: Model::KiokuDB
      model_name: kiokudb
</pre>

<p>Finally, we can add a method requiring authentication to the root
Controller (which is at
<code>lib/Jacquard/Web/Controller/Root.pm</code>):</p>

<pre class="brush:perl">
sub hello_user :Local :Does('NeedsLogin') {
  my( $self , $c ) = @_;

  my $name = $c->user->id;

  $c->response->body( "<h2>Hello, $name!</h2>" );
}
</pre>

<p>(Don&#8217;t forget that you need to change the parent class of the
controller as well:</p>

<pre class="brush:perl">
BEGIN { extends 'Catalyst::Controller::ActionRole' }
</pre>

<p>If things aren&#8217;t working, make sure you didn&#8217;t forget this.)</p>

<p>With all this in place, you should be able to start up the
application, by either running
<code>./script/jacquard_web_server.pl</code> or, if you want to get
all Plack-y and modern, <code>plackup jacquard_web.psgi</code>, and
then browse to the URL the server reports it&#8217;s running on. You should
see the Catalyst welcome page at that point. Add &#8216;/hello_user&#8217; to the
end of the URL, and you should get prompted for a username and
password. Assuming you created an account using the helper script from
the <a href="http://genehack.org/2011/10/setting_up_jacquard_users">last installment</a>, you should be able to give
those same values and see a page that says &#8216;Hello&#8217; and your test
account username. </p>

<p>Now, are we done? Not quite, as we don&#8217;t have any tests of the
authentication code! The following goes in
<code>t/lib/Test/Jacquard/Web/Controller/Root.pm</code>: </p>

<pre class="brush:perl">
package Test::Jacquard::Web::Controller::Root;
use parent 'Test::BASE';

use strict;
use warnings;

use Test::Most;
use Test::WWW::Mechanize::Catalyst;

sub fixtures :Tests(startup) {
  my $test = shift;

  # load test config
  $ENV{CATALYST_CONFIG_LOCAL_SUFFIX} = 'test';

  $test->{mech} = Test::WWW::Mechanize::Catalyst->new( catalyst_app => 'Jacquard::Web' );
}

sub auth_test :Tests() {
  my $test = shift;
  my $mech = $test->{mech};

  $mech->get_ok( '/' , 'basic request works' );
  is( $mech->uri->path , '/' , 'at top page' );

  $mech->get_ok( '/hello_user' , 'request hello_user' );
  is( $mech->uri->path , '/login' , 'redirect to login' );

  $mech->submit_form_ok({
    form_id => 'login_form' ,
    fields  => {
      username => 'test_user' ,
      password => 'test_password' ,
    } ,
    button => 'submit' ,
  } , 'login' );

  is( $mech->uri->path , '/hello_user' , 'redirect to /hello_user' );
  $mech->text_contains( 'Hello, test_user!' , 'see expected greeting' );

  $mech->get_ok( '/' , 'basic request works' );
  is( $mech->uri->path , '/' , 'at home page' );

  $mech->get_ok( '/hello_user' , 'request hello_user' );
  is( $mech->uri->path , '/hello_user' , 'go directly to hello_user' );
  $mech->text_contains( 'Hello, test_user!' , 'still see expected greeting' );

  $mech->get_ok( '/logout' );
  is( $mech->uri->path , '/' , 'back at home page' );

  $mech->get_ok( '/hello_user' , 'request hello_user' );
  is( $mech->uri->path , '/login' , 'redirect to login' );
}


1;
</pre>

<p>If you&#8217;re not familiar with <a href="https://metacpan.org/module/Test::Class">Test::Class-style
testing</a>, you should review the links I gave in <a href="http://genehack.org/2011/10/setting_up_the_jacquard_project_infrastructure/">the
post on the Jacquard project infrastructure</a>. Even if you&#8217;re not that versed in Test::Class, hopefully the sequence above is fairly self-explanatory: we try to access a restricted URL, verify we get bounced to the login URL, then fill out and submit the login form, and verify we get re-directed to the original request. Following that, we logout and verify that we&#8217;re once again unable to get to the restricted resource. Fairly simple. </p>

<p>In order to make this work, we need a distinct application config for
testing, one that defines a test user and password for us. Catalyst, of course, provides a way to do this &#8212; that&#8217;s what that line that sets the <code>CATALYST_CONFIG_LOCAL_SUFFIX</code>
environment variable is about. The testing config goes into
<code>jacquard_test.yaml</code>, and looks like this:</p>

<pre class="brush:plain">
---
Plugin::Authentication:
  default:
    credential:
      class: Password
      password_field: password
      password_type: clear
    store:
      class: Minimal
      users:
        test_user:
          password: 'test_password'
</pre>

<p>With that test file and test config in place, we can run the tests:</p>

<pre class="brush:plain">
$ prove -l -I./t/lib ./t/lib/Test/Jacquard/Web/Controller/Root.pm -v
./t/lib/Test/Jacquard/Web/Controller/Root.pm .. # 
# Test::Jacquard::Web::Controller::Root->auth_test

ok 1 - basic request works
ok 2 - at top page
ok 3 - request hello_user
ok 4 - redirect to login
ok 5 - login
ok 6 - redirect to /hello_user
ok 7 - see expected greeting
ok 8 - basic request works
ok 9 - at home page
ok 10 - request hello_user
ok 11 - go directly to hello_user
ok 12 - still see expected greeting
ok 13 - GET /logout
ok 14 - back at home page
ok 15 - request hello_user
ok 16 - redirect to login
1..16
ok
All tests successful.
Files=1, Tests=16,  4 wallclock secs ( 0.04 usr  0.00 sys +  3.67 cusr  0.20 csys =  3.91 CPU)
Result: PASS
</pre>

<p>and verify they pass. This is also a good point to rerun the whole
test suite: </p>

<pre class="brush:plain">
$ prove -l
t/01-run.t .. ok    
All tests successful.
Files=1, Tests=26,  6 wallclock secs ( 0.03 usr  0.01 sys +  4.16 cusr  0.27 csys =  4.47 CPU)
Result: PASS
</pre>

<p>So, at this point, we have a basic data model (which only models users &#8212;
but that&#8217;s about to change!), a KiokuDB-based persistence framework,
and we&#8217;ve got all that hooked into a Catalyst-based web application
and can use the info in our User object to authenticate to the web
app. Sounds like a good place to take a break! In our next
installment, we&#8217;ll pull back from the coding just a bit and think about the best way to structure the data involved in the services we&#8217;re going to connect to, and the posts we&#8217;re going to read and write to those connections. </p>

<p>As always, the code for <a href="https://github.com/genehack/Jacquard">Jacquard</a> is available on
Github. Patches are welcome; share and enjoy.</p>

<p><strong>Update:</strong> The Jacquard story continues with &#8220;<a href="http://genehack.org/2011/11/jacquard_04_extending_the_data_model/">Extending The Data Model</a>&#8221;.</p>
]]></description>
                <link>http://genehack.org/2011/11/setting_up_jacquard_authentication/</link>
                <guid>http://genehack.org/2011/11/setting_up_jacquard_authentication/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">catalyst</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">jacquard</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">kioku</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">perl</category>
        
                <pubDate>Tue, 01 Nov 2011 19:13:09 -0500</pubDate>
            </item>
    
            <item>
                <title>Jacquard 02: Setting Up Users</title>
                <description><![CDATA[<p>Okay, we&#8217;ve got our <a href="http://genehack.org/2011/10/setting_up_the_jacquard_project_infrastructure/">tooling support built up</a> so we
can easily and quickly run tests &#8212; time to do some Real Work!</p>

<p>Before any coding, it&#8217;s usually helpful to think about what we&#8217;re
trying to do, and how best to break down the data involved in the
problem. Since the point of Jacquard is to aggregate together multiple
social networking sites (and RSS feeds, eventually), we&#8217;re going to
have a few generic object types in the system: we&#8217;ll have User objects
representing our users, Service objects representing the different
types of social networks, Account objects that map between a Service
and a particular User, and Post objects that represent the individual
pieces of content on a particular service.</p>

<p>Given that breakdown of the data structures, one plan of attack is to
first create the User class, get the basics of that working in the
data model layer of the application, then hook it into the web
application layer. Generally speaking, I find that getting to the
point where I can log in to the web application is a good stopping point. </p>

<p><strong>N.b. :</strong> I&#8217;m going to be borrowing <em>very</em> heavily from
<a href="http://blog.woobling.org/2009/05/using-kiokudb-in-catalyst-applications.html">Nothingmuch&#8217;s intro to using KiokuDB in Catalyst applications</a>
post here &#8212; you may want to jump over and read that before
continuing.</p>

<p>So, the first thing to create is our user class in our data
model. Following the conventions discussed in Nothingmuch&#8217;s article,
we&#8217;ll call this class &#8216;Jacquard::Schema::User&#8217;:</p>

<pre class="brush:perl">
package Jacquard::Schema::User;
# ABSTRACT: Jacquard users
use Moose;
with qw/ KiokuX::User /;  # provides 'id' and 'password' attributes

# we're going to use this to map 'username' to the 'id' attr
use MooseX::Aliases;

# and this is an easy way to verify we're getting a valid email
use MooseX::Types::Email qw/ EmailAddress /;
 # these are a couple of helper classes that make Kioku easier to use
use KiokuDB::Set;
use KiokuDB::Util              qw/ set /;

use namespace::autoclean;

# we want to have our username be our unique ID in Kioku
alias username => 'id';

has email => (
  isa      => EmailAddress ,
  is       => 'ro' ,
  required => 1 ,
);

# this attribute is going to contain info about all the services
# this user has configured -- i.e., there will be one for Twitter,
# one for Facebook, etc.
has accounts => (
  isa     => 'KiokuDB::Set',
  is      => 'ro',
  lazy    => 1 ,
  default => sub { set() },
);

__PACKAGE__->meta->make_immutable;    
1;
</pre>

<p>To sanity check the basics that we&#8217;ve done so far, let&#8217;s make a
simple test class for <code>Jacquard::Schema::User</code> &#8212;
something like this:</p>

<pre class="brush:perl">
package Test::Jacquard::Schema::User;
use strict;
use warnings;

use parent 'Test::BASE';

use Test::Most;

use KiokuX::User::Util qw/ crypt_password /;

use Jacquard::Schema::User;

sub test_constructor :Tests(7) {
  my $test = shift;

  my $user = Jacquard::Schema::User->new(
    id       => 'user1' ,
    email    => 'user1@example.com' ,
    password => crypt_password( 'bad_password' ) ,
  );

  isa_ok( $user , 'Jacquard::Schema::User' );

  is( $user->id       , 'user1'             , 'id' );
  is( $user->username , 'user1'             , 'name delegated to id' );
  is( $user->email    , 'user1@example.com' , 'email' );

  ok( $user->check_password( 'bad_password' ) , 'check password' );
  ok( ! $user->check_password( 'wrong password' ), 'check wrong password' );

  is_deeply( [ $user->accounts->members ] , [] , 'no accounts' );

}
</pre>

<p>What happens when we run that?</p>

<pre class="brush: plain">
$ prove -lv
t/01-run.t .. # 
# Test::Jacquard::Schema::User->test_constructor

1..7
ok 1 - The object isa Jacquard::Schema::User
ok 2 - id
ok 3 - name delegated to id
ok 4 - email
ok 5 - check password
ok 6 - check wrong password
ok 7 - no accounts
ok
All tests successful.
Files=1, Tests=7,  1 wallclock secs ( 0.02 usr  0.01 sys +  0.53 cusr  0.03 csys =  0.59 CPU)
Result: PASS
</pre>

<p>It&#8217;s important to note at this point that we don&#8217;t have anything
really KiokuDB-specific going on with that User class. Yes, we used a
few Kioku-related helper classes, but that&#8217;s just because we knew we
were headed towards KiokuDB eventually. Those helpers could easily be
replaced (or even removed, in a few cases), leaving behind a simple
Moose class that describes a User object. In order to really hook this
up to KiokuDB, the next step is make a Model class. This will allow
our data objects to persist (i.e., save them to disk), and also
provides a place to put helper methods to wrap transactions and a way
to define a data storage API that will be used by the Catalyst web
application layer. (Cooler people might call this a data storage
DSL&#8230;) Here&#8217;s an initial version of this Model class: </p>

<pre class="brush:perl">
package Jacquard::Model::KiokuDB;
# ABSTRACT: KiokuX::Model wrapper for Jacquard
use Moose;
extends qw/ KiokuX::Model /;

sub insert_user {
  my( $self , $user ) = @_;

  my $id = $self->txn_do(sub {
      $self->store( $user )
  });

  return $id;
}

__PACKAGE__->meta->make_immutable;
1;
</pre>

<p>And of course, we need a test class too &#8212; this one uses Kioku&#8217;s
ability to &#8220;store&#8221; things to memory, rather than a database, making it
easier to set up the tests.</p>

<pre class="brush:perl">
package Test::Jacquard::Model::KiokuDB;
use parent 'Test::BASE';

use strict;
use warnings;

use Test::Most;

use Jacquard::Model::KiokuDB;
use Jacquard::Schema::User;

use KiokuX::User::Util qw/ crypt_password /;

sub fixtures :Tests(startup) {
  my $test = shift;

  $test->{model} = Jacquard::Model::KiokuDB->new( dsn => 'hash' );
}

sub test_insert_user :Tests(3) {
  my $test = shift;
  my $m    = $test->{model};

  {
    my $s = $m->new_scope;

    my $id = $m->insert_user(
      Jacquard::Schema::User->new(
        id       => 'user1' ,
        email    => 'user1@example.com' ,
        password => crypt_password( 'bad_password' ) ,
      ),
    );

    ok( $id , 'got id' );

    my $user = $m->lookup( $id );

    isa_ok( $user , 'Jacquard::Schema::User' , 'looked up user' );
    is( $user->username , 'user1' , 'expected name' );
  }
}

1;
</pre>

<p>(Note how we&#8217;re using the <code>Tests(startup)</code> method attribute
to set up our test fixtures.)</p>

<p>Running the test suite shows us that everything is working as we expect:</p>

<pre class="brush:plain">
$ prove -lv
t/01-run.t .. # 
# Test::Jacquard::Model::KiokuDB->test_insert_user

ok 1 - got id
ok 2 - looked up user isa Jacquard::Schema::User
ok 3 - expected name
# 
# Test::Jacquard::Schema::User->test_constructor
ok 4 - The object isa Jacquard::Schema::User
ok 5 - id
ok 6 - name delegated to id
ok 7 - email
ok 8 - check password
ok 9 - check wrong password
ok 10 - no accounts
1..10
ok
All tests successful.
Files=1, Tests=10,  2 wallclock secs ( 0.03 usr  0.01 sys +  1.19 cusr  0.06 csys =  1.29 CPU)
Result: PASS
</pre>

<p>We&#8217;re almost ready to create our <a href="http://www.catalystframework.org/">Catalyst</a> application and
hook up the authentication bits to our model/schema code &#8212; but first,
let&#8217;s write a little helper utility to create a user. That will make
our interactive testing of the web application a little bit
easier. We&#8217;ll use SQLite and the KiokuDB/DBIx::Class bridge for the
moment; if and when this gets rolled out to more people, we&#8217;d want to
change that up to something with a bit more power (e.g., by swapping
Postgres in for SQLite, or, if we want to hop the NoSQL train, by
switching over to CouchDB).</p>

<p>First, a configuration file, so we don&#8217;t have to hardcode the database
connection details. This goes in <code>jacquard.yaml</code>:</p>

<pre class="brush:plain">
---
Model::KiokuDB:
  dsn: dbi:SQLite:dbname=db/jacquard.db
</pre>

<p>(Down the road, we&#8217;ll add the Catalyst application configuration to
this file too.)</p>

<p>Next up, the helper script. This just needs to load up the config,
prompt for needed info, create a Jacquard::Schema::User object,
instantiate a KiokuDB connection with
<code>Jacquard::Model::KiokuDB</code>, and use the
<code>insert_user</code> method to store the object in the
database. This will live in <code>script/create_user</code>:</p>

<pre class="brush:perl">
#! /opt/perl/bin/perl

use strict;
use warnings;
use 5.010;

use FindBin;
use lib "$FindBin::Bin/../lib";

use Jacquard::Model::KiokuDB;
use Jacquard::Schema::User;
use KiokuX::User::Util         qw/ crypt_password /;
use YAML                       qw/ LoadFile       /;

my $dsn = parse_config_file();

my( $username , $email , $password ) = prompt_for_info();

my $user = Jacquard::Schema::User->new(
  username => $username ,
  email    => $email ,
  password => crypt_password( $password ),
);

my $m = Jacquard::Model::KiokuDB->connect( $dsn , create => 1 );
{
  my $s = $m->new_scope;

  my $id = $m->insert_user( $user );

  say "STORED USER ID '$id'";
}

# config file parsing and info prompting details elided; if you're
# really interested, the code is on Github... 
</pre>

<p>If we wanted to get really fancy, we could make this take command
line flags for the needed information &#8212; and it should probably not
echo the password back to the screen, and should handle the exception
that&#8217;s going to be thrown if the email address isn&#8217;t properly formed,
or if the username already exists &#8212; but that can all be added down
the road. For the moment, we just need to get a User object saved in
the database so we have something to authenticate against&#8230;</p>

<p>So, we run this to create a test user:</p>

<pre class="brush:plain">
<Jacquard:/> $ ./script/create-user 
USERNAME? test
EMAIL? test@example.com
PASSWORD? bad
STORED USER ID 'user:test'
</pre>

<p>At this point, if you&#8217;re doing this for real, it&#8217;s worth pausing for a
few minutes and using the SQLite tool to poke around inside the
database that&#8217;s been created for you in <code>db/jaquard.db</code>.
Since this is already a super long post and one of the overarching
points of this series is that KiokuDB means you don&#8217;t <em>need</em> to worry
about how your stuff lives on disk, we&#8217;re gonna skip that.</p>

<p>Next time, we&#8217;ll set up our <a href="http://www.catalystframework.org/">Catalyst</a> app and use this user class to hook up authentication. </p>

<p><strong>Update:</strong> See the Catalyst application set up in &#8220;<a href="http://genehack.org/2011/11/setting_up_jacquard_authentication/">Setting Up Authentication</a>&#8221;.</p>
]]></description>
                <link>http://genehack.org/2011/10/setting_up_jacquard_users/</link>
                <guid>http://genehack.org/2011/10/setting_up_jacquard_users/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">catalyst</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">jacquard</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">kioku</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">perl</category>
        
                <pubDate>Thu, 27 Oct 2011 23:00:00 -0500</pubDate>
            </item>
    
            <item>
                <title>Two Completely Unrelated Links Presented Without Commentary</title>
                <description><![CDATA[<ul>
<li>Elf: <a href="http://elfs.livejournal.com/1432775.html">Just start</a></li>
<li>NPR: <a href="http://www.npr.org/2011/10/13/141313080/-re-exposed-naked-mole-rat-genome-sequenced">Naked Mole Rat&#8217;s Genetic Code Laid Bare</a></li>
</ul>
]]></description>
                <link>http://genehack.org/2011/10/tab_dump/</link>
                <guid>http://genehack.org/2011/10/tab_dump/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">bioinformatics</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">buddhism</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">genomics</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">gtd</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">meditation</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">npr</category>
        
                <pubDate>Tue, 18 Oct 2011 10:22:13 -0500</pubDate>
            </item>
    
            <item>
                <title>Jacquard 01: Setting Up Project Infrastructure</title>
                <description><![CDATA[<p>Okay, first step is to get some tooling in place to make it easier to
deal with developing this thing. Since I'm expecting to work on this
for a while, and will probably end releasing the code on <a href="http://www.cpan.org/">CPAN</a>,
it makes sense to invest a little up front effort on making testing
and releasing the code easier.</p>

<p>Item the first: a <a href="http://dzil.org/">Dist::Zilla</a> config. If you're not familiar
with Dist::Zilla, it's a set of tools to make it easier to write Perl
code with an eye towards distributing it on CPAN. There's more info at
the Dist::Zilla site.</p>

<p>Since I've been using dzil for a while, I've taken the step of
uploading my own <a href="https://metacpan.org/module/Dist::Zilla::PluginBundle::GENEHACK">plugin bundle</a> to CPAN -- so my
<code>dist.ini</code> file to configure Dist::Zilla is pretty
straightforward:</p>

<pre class="brush:plain">
name    = Jacquard
author  = John SJ Anderson &lt;genehack@genehack.org>
license = Perl_5
copyright_holder = John SJ Anderson &lt;genehack@genehack.org>
copyright_year   = 2011

[@GENEHACK]
</pre>

<p>The intro boilerplate is pretty self-explanatory, and all that last
line says is "use my standard plugins and settings."</p>

<p>Item the second: <a href="https://metacpan.org/module/Test::Class">Test::Class</a> tooling. I've been using the
OO-ish approach to writing tests for a while now and I find it very
convenient. I'm not going to try to explain how it works, since Ovid
has already written a very nice series of articles over on
<a href="http://www.modernperlbooks.com/mt/">Modern Perl Books</a> about using this module: </p>

<ul>
<li><a href="http://www.modernperlbooks.com/mt/2009/03/organizing-test-suites-with-testclass.html">Organizing Test Suites with Test::Class</a></li>
<li><a href="http://www.modernperlbooks.com/mt/2009/03/reusing-test-code-with-testclass.html">Reusing Test Code with Test::Class</a></li>
<li><a href="http://www.modernperlbooks.com/mt/2009/03/making-your-testing-life-easier.html">Making Your Testing Life Easier</a></li>
<li><a href="http://www.modernperlbooks.com/mt/2009/03/using-test-control-methods-with-testclass.html">Using Test Control Methods with Test::Class</a></li>
<li><a href="http://www.modernperlbooks.com/mt/2009/03/working-with-testclass-test-suites.html">Working with Test::Class Test Suites</a></li>
</ul>

<p>To make it easier to use we're just going to create a test helper to
run all our Test::Class tests -- this will go in a file called
<code>t/01-run.t</code>:</p>

<pre class="brush:perl">
#! perl
use strict;
use warnings;
use Test::Class::Load qw( t/lib );
</pre>

<p>All that does is automatically find all our testing libraries under
<code>t/lib</code> and automatically run each one in turn. We're also
going to create a testing base class at
<code>t/lib/Test/BASE.pm</code> that all our test libraries will
inherit from:</p>

<pre class="brush:perl">
package Test::BASE;
use parent 'Test::Class';

INIT { Test::Class->runtests }

1;
</pre>

<p>This is done so that individual test libraries will do the right thing
when run with the <code>prove</code> tool -- more about that in a
later installment. </p>

<p>Item the third: a top level library file. This isn't strictly needed,
and isn't going to contain any code, but I always like to have a
module file that matches the name of the distribution. So we'll put
this into <code>lib/Jacquard.pm</code>:</p>

<pre class="brush:perl">
package Jacquard;
# ABSTRACT: Jacquard is a social network and RSS feed aggregator.
1;
</pre>

<p>At some point, we'll come back and revise that abstract line, once we have a better idea of what this thing wants to do. </p>

<p>For the moment, let's make sure things are "working" as expected:</p>

<pre class="brush:plain">
&lt;Jacquard:/> $ dzil test
[DZ] building test distribution under .build/EkNRq3jF7V
[DZ] beginning to build Jacquard
[DZ] guessing dist's main_module is lib/Jacquard.pm
[DZ] extracting distribution abstract from lib/Jacquard.pm
[@GENEHACK/@Basic/ExtraTests] rewriting release test xt/release/pod-coverage.t
[@GENEHACK/@Basic/ExtraTests] rewriting release test xt/release/pod-syntax.t
[@GENEHACK/@Basic/ExtraTests] rewriting release test xt/release/eol.t
[@GENEHACK/@Basic/ExtraTests] rewriting release test xt/release/kwalitee.t
[DZ] Override README from [ReadmeFromPod]
[DZ] writing Jacquard in .build/EkNRq3jF7V
Checking if your kit is complete...
Looks good
Writing Makefile for Jacquard
Writing MYMETA.yml and MYMETA.json
cp lib/Jacquard.pm blib/lib/Jacquard.pm
Manifying blib/man3/Jacquard.3
PERL_DL_NONLAZY=1 /opt/perl-5.14.2/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/li    b', 'blib/arch')" t/*.t
t/00-compile.t ............ ok   
t/01-run.t ................ No subtests run 
t/release-eol.t ........... skipped: these tests are for release candidate testing
t/release-kwalitee.t ...... skipped: these tests are for release candidate testing
t/release-pod-coverage.t .. skipped: these tests are for release candidate testing
t/release-pod-syntax.t .... skipped: these tests are for release candidate testing

Test Summary Report
-------------------
t/01-run.t              (Wstat: 0 Tests: 0 Failed: 0)
  Parse errors: No plan found in TAP output
Files=6, Tests=1,  0 wallclock secs ( 0.04 usr  0.02 sys +  0.17 cusr  0.03 csys =  0.26 CPU)
Result: FAIL
Failed 1/6 test programs. 0/1 subtests failed.
make: *** [test_dynamic] Error 255
error running make test
</pre>

<p>And since we haven't actually <em>written</em> any tests yet, that's about
what we should expect. That's a nice place to stop and commit what
we've done so far:</p>

<pre class="brush:plain">
[master]&lt;Jacquard:/> $ git add dist.ini t/01-run.t t/lib/Test/BASE.pm lib/Jacquard.pm

[master 6cd7634] Set up basic dist.init, Test::Class tooling, and lib/Jacquard.pm
 4 files changed, 132 insertions(+), 0 deletions(-)
 create mode 100644 dist.ini
 create mode 100644 lib/Jacquard.pm
 create mode 100755 t/01-run.t
 create mode 100644 t/lib/Test/BASE.pm
</pre>

<p>and a good time to stop for the moment. In the next installment, we'll write some code that actually <em>does</em> something, and start figuring out how this thing is actually going
to work. </p>

<p><strong>Update:</strong> The Jacquard story continues in "<a href="http://genehack.org/2011/10/setting_up_jacquard_users/">Setting Up Users</a>". </p>
]]></description>
                <link>http://genehack.org/2011/10/setting_up_the_jacquard_project_infrastructure/</link>
                <guid>http://genehack.org/2011/10/setting_up_the_jacquard_project_infrastructure/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">catalyst</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">dist::zilla</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">jacquard</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">kioku</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">perl</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">test::class</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">testing</category>
        
                <pubDate>Mon, 17 Oct 2011 09:00:00 -0500</pubDate>
            </item>
    
            <item>
                <title>Introducing Jacquard</title>
                <description><![CDATA[<p>Around the beginning of 2010, I started a project that I eventually
ended up calling <a href="http://github.com/genehack/app-status-skein">App::StatusSkein</a>. The idea was to
provide reading and posting access to a variety of social networks
from a single unified location. As these personal projects will, it
grew to the point where it was tolerable for my primary use for it,
and my desire to develop it further slackened. I had placed some (in
retrospect) odd design constraints on it &#8212; I was trying to not have a
backing database at all, to only run locally, and to only keep a
certain minimal amount of state loaded at any given time. After the
initial page load, all the interaction between the web browser and the
server was AJAX-based, and reloading the page would reset the state to
the initial default. Parts of this worked well; parts of it&#8230; just
worked, but all in all, it was successful at scratching the itch I had
at the time.</p>

<p>Now, I&#8217;ve got a different itch &#8212; same general area, but different
design constraints. Now that I&#8217;ve got an iPad, it would be nice to
have something similar to StatusSkein, but server-based, able to keep
track of where in the timeline I&#8217;d last left off reading, able to save
posts for later, and able to track precisely which posts I&#8217;ve read and
which I haven&#8217;t, regardless of what location I accessed them from &#8212;
something like a mashup of the UI of Google Reader and the current
StatusSkein. Technology-wise, I&#8217;d also like a chance to play around
with a <a href="https://metacpan.org/module/Catalyst">Catalyst</a> app that uses <a href="http://www.iinteractive.com/kiokudb/">KiokuDB</a> instead of
the usual (for me) <a href="https://metacpan.org/module/DBIx::Class">DBIx::Class</a>. It would also be nice if I had
a better way of maintaining my interest in the development of this app
beyond the initial &#8220;hey, this itches!&#8221; stage. The ideal way to do that
is to get users. Failing that, perhaps <em>readers</em> will provide some
motivation&#8230;</p>

<p>So, welcome to what is hopefully the first in a series of posts
outlining bite-sized bits of coding and other noddling around as I
work on developing this new trans-social network app that I&#8217;m
currently calling <a href="https://github.com/genehack/Jacquard">Jacquard</a>&#8230;</p>

<p><strong>Update:</strong> The Jacquard story begins in &#8220;<a href="http://genehack.org/2011/10/setting_up_the_jacquard_project_infrastructure/">Setting Up Project Infrastructure</a>&#8221;. </p>
]]></description>
                <link>http://genehack.org/2011/10/introducing_jacquard/</link>
                <guid>http://genehack.org/2011/10/introducing_jacquard/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">catalyst</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">jacquard</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">kioku</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">perl</category>
        
                <pubDate>Thu, 13 Oct 2011 06:39:48 -0500</pubDate>
            </item>
    
            <item>
                <title>Tab dump - 20110823</title>
                <description><![CDATA[<ul>
<li><a href="http://www.librarian.net/stax/3643/goddard-commencement-speech-text-and-citations/">Jessamyn&#8217;s Goddard Commencement speech</a></li>
<li><a href="http://sociology.ucsc.edu/whorulesamerica/power/investment_manager.html">An Investment Manager&#8217;s View on the top 1%</a></li>
<li><a href="http://www.onemogin.com/blog/2011/8/10/the-setup.html">gphat&#8217;s DIY Setup</a> &#8212; I really like <a href="http://usesthis.com/">The Setup</a> and I should get off my ass and do one of these DIY entries myself&#8230;</li>
<li><a href="http://theoatmeal.com/pl/minor_differences4/kids">The Oatmeal on having kids</a> and <a href="http://theoatmeal.com/comics/online_gaming">The Oatmeal on playing online games as a grownup</a></li>
</ul>
]]></description>
                <link>http://genehack.org/2011/08/tab_dump_-_20110823/</link>
                <guid>http://genehack.org/2011/08/tab_dump_-_20110823/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">finance</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">games</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">jessamyn</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">parenting</category>
        
                <pubDate>Tue, 23 Aug 2011 06:14:16 -0500</pubDate>
            </item>
    
            <item>
                <title>A Non-Exhaustive List Of Things We Brought Home From Vacation That We Did Not Leave Home With, In No Particular Order</title>
                <description><![CDATA[<ul>
<li>1 fifth of Knob Creek Single Barrel Reserve, partially consumed</li>
<li>1 case of Fat Tire Ale</li>
<li>1 twelve pack sampler, Boulevard Brewing Co., Kansas City, Missouri</li>
<li>5 corked beers (various) from the Boulevard Smokestack series, Boulevard Brewing Co., Kansas City, Missouri</li>
<li>8 tomatoes</li>
<li>1 play tea set with wicker carrying case</li>
<li>11 pint jars of various pickles, sauces, and preserves</li>
<li>1 quart jar of cherry bourbon (made with Seagrams 7, dated 26 Jul 2011)</li>
<li>1 fifth of Canadian Club, bearing a 1974 tax stamp, from my deceased maternal grandfather&#8217;s basement</li>
<li>4 fifths of Seagram&#8217;s V.O., bearing tax stamps from the years 1963, 1964, 1965, and 1966, from the same basement</li>
<li>2 bubble wand swords</li>
</ul>
]]></description>
                <link>http://genehack.org/2011/07/a_non-exhaustive_list_of_things_we_brought_home_fr/</link>
                <guid>http://genehack.org/2011/07/a_non-exhaustive_list_of_things_we_brought_home_fr/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">personal</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">random</category>
        
                <pubDate>Sat, 30 Jul 2011 22:24:28 -0500</pubDate>
            </item>
    
            <item>
                <title>2011 CSA Week #4</title>
                <description><![CDATA[<p>And here&#8217;s what I picked up earlier today:</p>

<ul>
<li>1 Head Green Romaine Lettuce</li>
<li>1 Bunch Green Kale</li>
<li>1 Bag Rainbow Chard</li>
<li>1 Bag Baby Scarlet Turnips</li>
<li>1 Bunch Garlic Scapes</li>
<li>1 Bunch Tatsoi (Japanese Spinach)</li>
<li>1 Bunch Collard Greens</li>
<li>1 Bunch Red Scallions</li>
<li>1 Package Shiitake Mushrooms</li>
<li>1 Head Green Leaf Lettuce</li>
</ul>

<p>So, we&#8217;ll have a Caesar salad one night, maybe steak this week. And probably another salad night with the leaf lettuce. The rest of that stuff &#8212; particularly the Tatsoi &#8212; is going to be more challenging.</p>

<p>Any suggestions?</p>
]]></description>
                <link>http://genehack.org/2011/06/2011_csa_week_4/</link>
                <guid>http://genehack.org/2011/06/2011_csa_week_4/</guid>
        
        
                    <category domain="http://www.sixapart.com/ns/types#tag">CSA</category>
        
                    <category domain="http://www.sixapart.com/ns/types#tag">cooking</category>
        
                <pubDate>Wed, 01 Jun 2011 22:12:39 -0500</pubDate>
            </item>
    
        </channel>
    </rss>
 
