<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Jeff Ober</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jeff_ober/" />
    <link rel="self" type="application/atom+xml" href="http://blogs.perl.org/users/jeff_ober/atom.xml" />
    <id>tag:blogs.perl.org,2009-11-03:/users/jeff_ober//1318</id>
    <updated>2012-06-01T12:57:56Z</updated>
    <subtitle>Notes on Perl and software development by Jeff Ober.</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.38</generator>

<entry>
    <title>Simplified error cleanup with Filter::Cleanup</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jeff_ober/2012/06/simplified-error-cleanup-with-filtercleanup.html" />
    <id>tag:blogs.perl.org,2012:/users/jeff_ober//1318.3328</id>

    <published>2012-06-01T12:45:25Z</published>
    <updated>2012-06-01T12:57:56Z</updated>

    <summary>Writing fault-tolerant programs can be a tedious exercise. Often, each step in the program logic depends on the success of the step prior, resulting in deeply nested calls to eval. Tracking the global $@ and ensuring that errors are not...</summary>
    <author>
        <name>Jeff Ober</name>
        <uri>http://www.artfulcode.net</uri>
    </author>
    
        <category term="Filter::Cleanup" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="cpanannouncementssourcefilteringsyntax" label="cpan announcements source-filtering syntax" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jeff_ober/">
        <![CDATA[<p>Writing fault-tolerant programs can be a tedious exercise. Often, each step in the program logic depends on the success of the step prior, resulting in deeply nested calls to eval. Tracking the global $@ and ensuring that errors are not lost can be tricky and result in hard-to-follow logic.</p>

<p>I recently read <u>The D Programming Language</u> by Andrei Alexandrescu (which I highly recommend). D features an interesting (and, to the best of my knowledge, unique) alternative to try/catch-style error handling (although it also supports try/catch/finally). It turns out that very little code actually traps errors and makes decisions based on error conditions. In most cases, the error must be temporarily trapped to allow cleanup before re-throwing the error afterward. In these cases, D programmers can use a <b>scope</b> statement to register clean-up code to be executed should any of the statements following it trigger an error.</p><p>Imagine a function to mix two chemicals to trigger some reaction. You may have a container class that knows its own operating parameters as well as a recipe class that knows the chemical components and mixture rates.<br /></p>

<pre>void mix_dangerous_chemicals(Container c, Recipe r) {
    while (!r.is_complete()) {
        scope(exit) c.set_temp(r.get_temp(r.MIX_FAILURE));
        scope(exit) c.seal();

        // Add ingredients to the container
        c.add(r.ingredients, r.mix_rate);

        // If operating outside tolerances for the
        // container, trigger an error.
        c.validate_operating_parameters();

        // Check that the recipe is producing the
        // expected results, perhaps throwing an error
        // if the recipe sees that a reaction appears to
        // be ready to breach container tolerances.
        r.validate_procedure(c);
    }
}</pre>

<p>This does something interesting. The scope statements each eat up all statements coming after them within their lexical scope and convert them into try/finally blocks. Statements are stack-based, so they are executed in the order opposite of declaration. This is because the first statement is wrapping the second scope statement in a try block, and then placing itself in the finally block. Something like this:</p>

<pre>void mix_dangerous_chemicals(Container c, Recipe r) {
    while (!r.is_complete()) {
        try {
            try {
                // Add ingredients to the container
                c.add(r.ingredients, r.mix_rate);

                // If operating outside tolerances for the
                // container, trigger an error.
                c.validate_operating_parameters();

                // Check that the recipe is producing the
                // expected results, perhaps throwing an error
                // if the recipe sees that a reaction appears to
                // be ready to breach container tolerances.
                r.validate_procedure(c);
            } finally {
                c.seal();
            }
        } finally {
            c.set_temp(r.get_temp(r.MIX_FAILURE));
        }
    }
}</pre>

<p>Which is cool, because the first syntax is much easier to read. You can imagine what this does for <i>really hairy</i> error handling.</p>

<h2>Filter::Cleanup</h2>

<p>Filter::Cleanup makes this syntax possible in Perl using source filtering and <a href="http://search.cpan.org/%7Eadamk/PPI/lib/PPI.pm">PPI</a>. PPI is used to ensure that the rest of a cleanup statement's scope is addressed and correctly rewritten (because let's face, correctly parsing Perl with regexes is <i>hard</i>). Using the cleanup source filter, the above code would be written like this:<br /></p>

<pre>use Filter::Cleanup;

sub mix_dangerous_chemicals {
    my ($c, $r) = @_;

    until ($r.is_complete()) {
        cleanup { $c.set_temp($r.get_temp($r.MIX_FAILURE)) };
        cleanup { $c.seal() };

        $c.add($r.ingredients, $r.mix_rate);
        $c.validate_operating_parameters();
        $r.validate_procedure();
    }
}</pre>

<p>Filter::Cleanup is available on <a href="http://search.cpan.org/%7Ejeffober/Filter-Cleanup/lib/Filter/Cleanup.pm">CPAN</a> and <a href="https://github.com/jsober/Filter-Cleanup">github</a>.</p>]]>
        

    </content>
</entry>

<entry>
    <title>Reddit::API renamed to Reddit::Client</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jeff_ober/2012/06/redditapi-renamed-to-redditclient.html" />
    <id>tag:blogs.perl.org,2012:/users/jeff_ober//1318.3326</id>

    <published>2012-06-01T12:17:53Z</published>
    <updated>2012-06-01T12:57:24Z</updated>

    <summary>To better fit CPAN&apos;s naming conventions, Reddit::API has been renamed to Reddit::Client. As there are no dependencies in the reverse lookup graph, Reddit::API is scheduled for deletion. Reddit::Client begins its life at 0.02 with mostly complete unit tests (thanks for...</summary>
    <author>
        <name>Jeff Ober</name>
        <uri>http://www.artfulcode.net</uri>
    </author>
    
        <category term="Reddit::Client" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="redditcpanannouncements" label="reddit cpan announcements" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jeff_ober/">
        <![CDATA[<p>To better fit CPAN's naming conventions, Reddit::API has been renamed to Reddit::Client. As there are no dependencies in the reverse lookup graph, Reddit::API is scheduled for deletion.</p>

<p>Reddit::Client begins its life at 0.02 with mostly complete unit tests (thanks for the footnote, Gabor), some refactoring, and a few bug fixes. Enjoy!</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Reddit API for Perl</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/jeff_ober/2012/05/reddit-api-for-perl.html" />
    <id>tag:blogs.perl.org,2012:/users/jeff_ober//1318.3217</id>

    <published>2012-05-09T00:43:35Z</published>
    <updated>2012-06-01T15:23:55Z</updated>

    <summary>I have completed the meat of a reasonably complete API wrapper for Reddit. You can grab it at https://github.com/jsober/Reddit-API. It is pretty simple to use, and the docs are complete, but here is the gist: use Reddit::API; my $session_file =...</summary>
    <author>
        <name>Jeff Ober</name>
        <uri>http://www.artfulcode.net</uri>
    </author>
    
    <category term="redditcpanannouncement" label="reddit cpan announcement" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/jeff_ober/">
        <![CDATA[<p>I have completed the meat of a reasonably complete API wrapper for Reddit. You can grab it at <a href="https://github.com/jsober/Reddit-API">https://github.com/jsober/Reddit-API</a>.</p>

<p>It is pretty simple to use, and the docs are complete, but here is the gist:</p>

<pre><code>use Reddit::API;

my $session_file = '~/.reddit';
my $reddit       = Reddit::API-&gt;new(session_file =&gt; $session_file);

unless ($reddit-&gt;is_logged_in) {
    $reddit-&gt;login('someone', 'secret');
    $reddit-&gt;save_session();
}

$reddit-&gt;submit_link(
    subreddit =&gt; 'perl',
    title     =&gt; 'Perl is still alive!',
    url       =&gt; 'http://www.perl.org'
);

my $links = $reddit-&gt;fetch_links(subreddit =&gt; '/r/perl', limit =&gt; 10);
foreach (@{$links-&gt;{items}}) {
    ...
}
</code></pre>
]]>
        

    </content>
</entry>

</feed>
