<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Mark Lawrence</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mark_lawrence/" />
    <link rel="self" type="application/atom+xml" href="http://blogs.perl.org/users/mark_lawrence/atom.xml" />
    <id>tag:blogs.perl.org,2009-11-03:/users/mark_lawrence//715</id>
    <updated>2013-05-19T00:07:24Z</updated>
    <subtitle>A blog about the Perl programming language</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.38</generator>

<entry>
    <title>Shell access to $NOT_MY_ENVIRONMENT for development?</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mark_lawrence/2013/05/shell-access-to-not-my-environment-for-development.html" />
    <id>tag:blogs.perl.org,2013:/users/mark_lawrence//715.4691</id>

    <published>2013-05-18T23:51:15Z</published>
    <updated>2013-05-19T00:07:24Z</updated>

    <summary>I&apos;m a self employed hacker. My development (actually, my total) infrastructure consists of a six-year old laptop running Linux with a full disk and a noisy fan, and a rented virtual server, also Linux. I have a few modules up...</summary>
    <author>
        <name>Mark Lawrence</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/mark_lawrence/">
        <![CDATA[<p>I'm a self employed hacker. My development (actually, my total) infrastructure consists of a six-year old laptop running Linux with a full disk and a noisy fan, and a rented virtual server, also Linux. I have a few modules up on CPAN, which occasionally receive reports from cpantesters or the odd individual user with a build/test failure on a platform I don't have access to. Blinding attempting fixes and waiting for reports is tedious and inefficient.</p>

<p>There are a few no-cost BSD shell providers around, which has allowed me to develop and test directly on that platform. However I haven't found anything similar for Win32. I vaguely remember some offering from Microsoft for CPAN developers, but can no longer find any reference to it. Can someone jog my memory, or give me a pointer to an alternative service?</p>]]>
        
    </content>
</entry>

<entry>
    <title>Bash function for directory-dependent local::lib</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mark_lawrence/2012/07/bash-function-for-directory-dependent-locallib.html" />
    <id>tag:blogs.perl.org,2012:/users/mark_lawrence//715.3577</id>

    <published>2012-07-19T01:06:41Z</published>
    <updated>2012-07-19T01:35:31Z</updated>

    <summary>On my laptop I use perlbrew to keep my system perl separate from my development perl. But I also develop various Perl projects with different dependencies, and would like to keep those dependencies separate if possible. Using a separate perlbrew...</summary>
    <author>
        <name>Mark Lawrence</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/mark_lawrence/">
        <![CDATA[<p>On my laptop I use perlbrew to keep my system perl separate from my development perl. But I also develop various Perl projects with different dependencies, and would like to keep those dependencies separate if possible. Using a separate perlbrew perl for each project as well would be overkill in terms of diskspace, CPU energy and time so I thought local::lib might be useful.</p>

<p>If I install dependencies for a particular project using "cpanm -l extlib $MODULE" in the top level directory, the function below will automatically setup local::lib for that location when I change into that directory, and unset it when I change out. I use a test for the existence of a "extlib" directory and a Makefile.PL file because that is what I consistently have.</p>

<p><br />
<code><pre><br />
# Automatic local::lib setup based on extlib directory<br />
set_local_lib() {<br />
    if [[ $PWD != $MYOLDPWD ]]; then<br />
        MYOLDPWD="$PWD";<br />
        OLDPERL5LIB=$PERL5LIB</p>

<p>        unset PERL5LIB<br />
        unset PERL_MB_OPT<br />
        unset PERL_MM_OPT<br />
        unset PERL_LOCAL_LIB_ROOT</p>

<p>        if [[ -n $VERY_LOCAL_LIB_PATH ]]; then<br />
            export PATH=`echo $PATH | sed -e "s|$VERY_LOCAL_LIB_PATH:||g"`<br />
            unset VERY_LOCAL_LIB_PATH<br />
        fi</p>

<p>        if [[ -e Makefile.PL && -d extlib ]]; then<br />
            eval `perl -Mlocal::lib=extlib`<br />
            VERY_LOCAL_LIB_PATH=$PWD/extlib/bin<br />
            echo "[Using local::lib with $PWD/extlib]";<br />
        fi<br />
        if [[ -n $OLDPERL5LIB ]]; then<br />
            unset OLDPERL5LIB<br />
            echo "[local::lib turned off]";<br />
        fi<br />
    fi<br />
}</p>

<p>export PROMPT_COMMAND=set_local_lib<br />
</pre></code></p>

<p>Can this be improved? Is there are better way of achieving location dependent local::lib without resorting to FindBin/local::lib trickery in test scripts? It has also been <a href="http://stackoverflow.com/questions/5447595/perlbrew-and-locallib-at-the-same-time">mentioned</a> that perlbrew and local::lib don't work together. If "extlib" was a perl-version-dependent location this could also be overcome.</p>]]>
        
    </content>
</entry>

<entry>
    <title>githook-perltidy update</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mark_lawrence/2012/05/githook-perltidy-update.html" />
    <id>tag:blogs.perl.org,2012:/users/mark_lawrence//715.3178</id>

    <published>2012-05-01T03:10:41Z</published>
    <updated>2012-05-01T03:35:04Z</updated>

    <summary>Last year I wrote script to automatically tidy up your Perl code as it is commited by Git. I just ironed out a final issue that had been bugging me: partially indexed files. That change plus a few documentation cleanups...</summary>
    <author>
        <name>Mark Lawrence</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/mark_lawrence/">
        <![CDATA[<p>Last year I <a href="http://blogs.perl.org/users/mark_lawrence/2011/09/running-perltidy-in-a-git-commit-hook-githook-perltidy.html">wrote</a> script to automatically tidy up your Perl code as it is commited by Git. I just ironed out a final issue that had been bugging me: partially indexed files. That change plus a few documentation cleanups are now available as version 0.04 from my Github <a href="https://github.com/mlawren/githook-perltidy">repository</a> or as a <a href="https://github.com/mlawren/githook-perltidy/zipball/0.04">.zip</a> file.</p>

<p>I also uploaded a distribution (App-githook-perltidy) to CPAN however I'm not sure yet if it is installable as it doesn't contain any Perl module files, and cpanm at least doesn't seem to install based on distribution name only. Anyone have thoughts on if it makes sense to have a single-script CPAN distribution?</p>]]>
        
    </content>
</entry>

<entry>
    <title>Running perltidy in a Git commit hook (githook-perltidy)</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mark_lawrence/2011/09/running-perltidy-in-a-git-commit-hook-githook-perltidy.html" />
    <id>tag:blogs.perl.org,2011:/users/mark_lawrence//715.2204</id>

    <published>2011-09-19T06:39:44Z</published>
    <updated>2011-09-19T07:46:50Z</updated>

    <summary>I have found a couple of attempts at integrating perltidy into Git commit hooks, but nothing yet that I considered robust enough. The scripts ignore the state of the index, modify the working tree, and then forget to update the...</summary>
    <author>
        <name>Mark Lawrence</name>
        
    </author>
    
    <category term="git" label="git" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="perltidy" label="perltidy" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/mark_lawrence/">
        <![CDATA[<p>I have found a <a href="http://babyl.dyndns.org/techblog/entry/git%27s-the-nightclub,-perltidy%27s-the-bouncer">couple</a> <a href="http://www.sukria.net/fr/archives/2010/08/27/beyond-the-strictness-youre-used-to/">of</a> <a href="http://blog.darkpan.com/article/1/Tidying-Perl-using-a-pre-commit-hook.html">attempts</a> at integrating <a href="http://perltidy.sourceforge.net/">perltidy</a> into Git commit hooks, but nothing yet that I considered robust enough. The scripts ignore the state of the index, modify the working tree, and then forget to update the index before the commit. They didn't recover from a failed tidy run, leaving both the working tree and index messed up. Critically for me I could not do an interactive or patched "git add" and have the final commit reflect what I wanted.</p>

<p><a href="https://github.com/mlawren/githook-perltidy">githook-perltidy</a> is my answer to this challenge. Robustness is achieved by stashing the working tree and index before  the tidy run, which is re-applied on error. The same stash can be applied on top of the new commit (using a post-commit hook) to merge non-indexed working tree changes afterwards. The POD inside the script hopefully documents the process in sufficient detail to give you confidence in the method. Code has the final say of course...</p>

<p>You can grab a <a href="https://github.com/mlawren/githook-perltidy/tarball/master">tar</a> or <a href="https://github.com/mlawren/githook-perltidy/zipball/master">zip</a> file of the distribution now from the github repository at <a href="https://github.com/mlawren/githook-perltidy">https://github.com/mlawren/githook-perltidy</a>. Feedback (and patches for tests!) is welcome.<br />
</p>]]>
        
    </content>
</entry>

<entry>
    <title>Introducing App::Dispatcher</title>
    <link rel="alternate" type="text/html" href="http://blogs.perl.org/users/mark_lawrence/2011/02/introducing-appdispatcher.html" />
    <id>tag:blogs.perl.org,2011:/users/mark_lawrence//715.1447</id>

    <published>2011-02-09T09:23:38Z</published>
    <updated>2011-02-09T08:25:14Z</updated>

    <summary>I have an issue somewhat related to Steven Haryanto&apos;s concern about bloated apps. I can live with a command taking a second longer to run when performing work, but I absolutely detest waiting that long for the usage message to...</summary>
    <author>
        <name>Mark Lawrence</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://blogs.perl.org/users/mark_lawrence/">
        <![CDATA[<p>I have an issue somewhat related to Steven Haryanto's <a href="http://blogs.perl.org/users/steven_haryanto/2011/02/the-coming-bloated-perl-apps.html">concern</a> about bloated apps. I can live with a command taking a second longer to run when performing work, but I absolutely detest waiting that long for the usage message to be generated. I am constantly running commands without arguments (eg Git) to get an overview of sub-commands and/or their options. A slow Perl command line app (eg dzil) is a pain in comparison. It is sometimes quicker to load the manpage.</p>

<p>But it doesn't necessarily have to be that way. <a href="http://search.cpan.org/perldoc?App::Dispatcher">App::Dispatcher</a> is a tool for constructing command line applications
written in Perl.  It is specifically designed to handle applications
with multiple sub-commands and will generate code to display usage
text, validate options and arguments, and dispatch commands. Its main
strength is that the usage and validation does not load any 
command classes with their possibly heavy startup dependencies.</p>
]]>
        <![CDATA[<p>An application built with App::Dispatcher is composed of three parts:</p>

<ul>
<li><p>Command Classes</p>

<p>These classes are written by the application author to do the actual
work. They have special methods which <a href="http://search.cpan.org/perldoc?App::Dispatcher">App::Dispatcher</a> uses to build
the Dispatcher class.</p></li>
<li><p>Dispatcher Class</p>

<p>The Dispatcher class is generated when the application author runs the
app-dispatcher(1) command. The dispatcher class is called by the
Application Script at runtime.  After performing option and argument
processing the dispatcher class calls the appropriate Command Class.</p>

<p>The only runtime dependency that the Dispatcher Class needs to run is
<a href="http://search.cpan.org/perldoc?Getopt::Long::Descriptive">Getopt::Long::Descriptive</a>(3p), which the application author should
add to their Makefile.PL and/or Build.PL scripts.</p>

<p>Note that <a href="http://search.cpan.org/perldoc?App::Dispatcher">App::Dispatcher</a> is a code generation tool. This means
that option and argument processing will not change when command
classes are modified, until app-dispatcher is re-run.</p></li>
<li><p>Application Script</p>

<p>The application script is what the user runs, and does nothing more
than call the Dispatcher Class:</p>

<pre><code>#!/usr/bin/perl
use Your::Command::Dispatcher;
Your::Command::Dispatcher-&gt;run;
</code></pre>

<p>All the examples below assume the existence of this application script.</p></li>
</ul>

<p>The rest of this tutorial is all about how to write Command Classes.
Let's start with a simple command that has two options, one optional
argument, and no sub-commands:</p>

<pre><code>package Your::Command;

sub opt_spec {(
    [ "dry-run|n",     "print out SQL instead of running it" ],
    [ "drop-tables|D", "DROP TABLEs before deploying" ],
)};

sub arg_spec {(
    [ "database=s",   "which database to deploy to",
        { default =&gt; 'development' } 
    ],
)};

sub run {
    my ($class,$opt) = @_;

    if ( $opt-&gt;dry_run ) {
        print "Not ";
    }
    print "Deploying to ". $opt-&gt;database ."\n";
}

1;
</code></pre>

<p>With the above code in 'lib/Your/Command.pm' we can run
app-dispatcher and then our script:</p>

<pre><code>ex1$ app-dispatcher --add-help Your::Command
Writing lib/Your/Command/Dispatcher.pm

ex1$ ./ex --help
usage: ex [options] [&lt;database&gt;]
    --help             print usage message and exit
    -n --dry-run       print out SQL instead of running it
    -D --drop-tables   DROP TABLEs before deploying

ex1$ ./ex
Deploying to development

ex1$ ./ex -n production
Not Deploying to production
</code></pre>

<p>There are several things to note here. The first is the definition of
the opt_spec() and arg_spec() methods. The values returned from these
methods are passed more or less untouched to
<a href="http://search.cpan.org/perldoc?Getopt::Long::Descriptive">Getopt::Long::Descriptive</a>'s describe_options() routine.</p>

<p>Obvious should be the fact that the '-add-help' option to
app-dispatcher has added a '--help' option to our command.</p>

<p>What is more interesting is that arguments specification has the same
format as the options specification. An argument could actually be
considered the same as an un-named option with a fixed position.  So
<a href="http://search.cpan.org/perldoc?App::Dispatcher">App::Dispatcher</a> actually folds arguments into the option object
passed to the command class. The added benefit is that the parameter
validation of <a href="http://search.cpan.org/perldoc?Getopt::Long">Getopt::Long</a> is now also run against arguments.</p>

<p>Let's make the argument mandatory by adding a "required" key to the
arg_spec definition:</p>

<pre><code>{ default =&gt; 'development', required =&gt; 1 }

ex2$ ./ex
usage: ex [options] &lt;database&gt;
    --help             print usage message and exit
    -n --dry-run       print out SQL instead of running it
    -D --drop-tables   DROP TABLEs before deploying
</code></pre>

<p>You can see that the that the argument is now mandatory, and the usage
message no longer has the '[]' brackets. If the automatically generated
usage message is not to your liking, you can write a usage_desc()
method to specify your own, but that is not really recommended as
you'll have to keep it up to date manually when your code changes:</p>

<pre><code>sub usage_desc {
    return '%c %o &lt;DATABASE&gt;'
}
</code></pre>

<p>Now imagine that the application should have more functions, for
example 'test', and 'undeploy', and that they should be
run as sub-commands. We will rewrite 'Your::Command' as follows:</p>

<pre><code>package Your::Command;


sub opt_spec {(
    [ "dry-run|n",     "print out SQL instead of running it" ],
)};


sub arg_spec {(
    [ "command=s",   "what to do", { required =&gt; 1 } ],
)};
</code></pre>

<p>What we now have is a global option 'dry-run', that applies to all
commands, accessed through the third argument to the run() method (see
below). Because the 'Your::Command' arg_spec defines a mandatory
argument, our usage message is still displayed when we run our command
with no arguments.  If we wanted an action to take place when no
arguments are given, we would make the Your::Command <command> argument
optional, and reinstate the run() method in that package.</p>

<p>Now we write a new command class 'Your::Command::deploy' as follows (
'test' and 'undeploy' are similarly written):</p>

<pre><code>package Your::Command::deploy;


sub arg_spec {(
    [ "database=s",   "production|development",
        { default =&gt; 'development', required =&gt; 1 } 
    ],
)};


sub run {
    my ($self,$opt,$gopt) = @_;


    if ( $gopt-&gt;dry_run ) {
        print "Not ";
    } 
    print "Deploying to ". $opt-&gt;database ."\n";
}

1;
__END__


=head1 NAME


Your::Command::deploy - deploy to a database
</code></pre>

<p>Lets build the dispatcher class again:</p>

<pre><code>ex3$ app-dispatcher --add-help Your::Command
Found lib/Your/Command/test.pm
Found lib/Your/Command/undeploy.pm
Found lib/Your/Command/deploy.pm
Writing lib/Your/Command/Dispatcher.pm
</code></pre>

<p>Notice that the dispatcher has found our new command classes, and the
usage message now shows more information about our subcommands:</p>

<pre><code>ex3$ ./ex
usage: ex [options] &lt;command&gt;
    --help         print usage message and exit
    -n --dry-run   print out SQL instead of running it

Commands:
    test         test a database
    deploy       deploy to a database
    undeploy     undeploy a database
</code></pre>

<p>The informational text for sub-commands has been taken from the POD
documentation in the class file. You can override this by specifying an
'abstract()' method.</p>

<p>Also displayed contextually correctly are usage messages for our sub
commands:</p>

<pre><code>ex3$ ./ex deploy 
usage: ex deploy [options] &lt;database&gt;
    --help    print usage message and exit
</code></pre>

<p>You can write sub-sub-commands as far down as you want to go. There is
however only ever one global option as specified in the Your::Command
class.</p>

<pre><code>ex3$ ./ex -n deploy backup
Not Deploying to backup
</code></pre>

<p>By default, commands are listed in a semi-random order. If you want to
list them in an order that makes more sense (for example in the order
they would typicaly be run) you can add an order() method to each class
which returns an integer.</p>

<pre><code>package Your::Command::deploy;

sub order {1};

package Your::Command::test;

sub order {2};

package Your::Command::undeploy;

sub order {3};
</code></pre>

<p>And now we have:</p>

<pre><code>ex4$ ./ex 
usage: ex [options] &lt;command&gt;
    --help         print usage message and exit
    -n --dry-run   print out SQL instead of running it

Commands:
    deploy       deploy to a database
    test         test a database
    undeploy     undeploy a database
</code></pre>

<p><a href="http://search.cpan.org/perldoc?App::Dispatcher">App::Dispatcher</a> is brand new and has just been uploaded to CPAN. Feedback, bug reports, patches etc are very welcome.</p>

<h2>Alternatives</h2>

<p>It seems the current state of the art for command line applications is
<a href="http://search.cpan.org/perldoc?App::Cmd">App::Cmd</a>. I wrote <a href="http://search.cpan.org/perldoc?App::Dispatcher">App::Dispatcher</a> out of the frustration with the
time that it takes <a href="http://search.cpan.org/perldoc?App::Cmd">App::Cmd</a> to simply generate a usage message,
since <a href="http://search.cpan.org/perldoc?App::Cmd">App::Cmd</a> loads every command class in an app dynamically.</p>
]]>
    </content>
</entry>

</feed>
