Hi! Please consider following me on twitter: @hanekomu.

Current git branch in the bash prompt

You can use git branch to see the branch you're currently in, but it's easy to forget and to commit something into the wrong branch.

I wanted to have a constant reminder, so I chose to display the current branch on the bash prompt.

function parse_git_branch {
   ref=$(git symbolic-ref HEAD 2> /dev/null) || return
   printf " (${ref#refs/heads/})"
}

export PS1="\$(parse_git_branch) \$ "

The first backslash in PS1 is important so the function gets evaluated for every new bash prompt. If you're not inside a git repository, nothing will be printed. Let's see this in action.

 $ git init
Initialized empty Git repository in /path/to/repo/.git/
 (master) $ git checkout -b newbranch
Switched to a new branch 'newbranch'
 (newbranch) $ git checkout master
Switched to branch 'master'
 (master) $ cd ~
 $ 

This is just a bare shell prompt and actually I have a rather "baroque" PS1 setting, but that's for another blog post.

Write a comment | Bookmark and Share

posted at: 18:41 | path: /misc | permalink | 1 comment | 0 trackbacks

Modern Perl administration tools

I'm probably preaching to the choir (the phrase we use in German is more like "bringing owls to Athens") and I'm certainly not saying anything new here, but I would like to talk about two modern tools that make working with Perl versions and CPAN distributions very easy: perlbrew and cpanm.

perlbrew

perlbrew (see App::perlbrew) automates building and installing various perl versions in the user's home directory.

curl -LO http://xrl.us/perlbrew
chmod +x perlbrew
./perlbrew install

With this, perlbrew installs itself to ~/perl5/perlbrew. Now you can do (and I'm quoting from the App::perlbrew documentation):

# Initialize
perlbrew init

# Install some Perls
perlbrew install perl-5.12.1
perlbrew install perl-5.8.1
perlbrew install perl-5.11.5

# See what were installed
perlbrew installed

# Switch perl in the $PATH
perlbrew switch perl-5.12.1
perl -v

# Switch to another version
perlbrew switch perl-5.8.1
perl -v

# Switch to a certain perl executable not managed by perlbrew.
perlbrew switch /usr/bin/perl

# Or turn it off completely. Useful when you messed up too deep.
perlbrew off

# Use 'switch' command to turn it back on.
perlbrew switch perl-5.12.1

cpanm

cpanm is a script to get, unpack, build and install modules from CPAN. It does so in pretty much the simplest way possible, without dependencies or configuration.

To install it onto a freshly brewed perl, use this command:

curl -L http://cpanmin.us/ | perl - App::cpanminus

Then you can do (and again, I'm quoting from the App::cpanminus documentation):

cpanm Test::More                                 # install Test::More
cpanm MIYAGAWA/Plack-0.99_05.tar.gz              # full distribution path
cpanm http://example.org/LDS/CGI.pm-3.20.tar.gz  # install from URL
cpanm ~/dists/MyCompany-Enterprise-1.00.tar.gz   # install from a local file
cpanm --interactive Task::Kensho                 # Configure interactively
cpanm .                                          # install from local directory
cpanm --installdeps .                            # install all deps for the current dir
cpanm -L extlib Plack                            # install Plack and its deps to extlib
cpanm --mirror http://cpan.cpantesters.org/ DBI  # use the fast-syncing mirror

The cpanm --installdeps . command will work if you have a Makefile.PL or a Build.PL in the current directory, but if you use Dist::Zilla you're likely to use a plugin that generates the Makefile.PL and the dependencies for you. In that case you can use this:

dzil listdeps | cpanm --skip-installed

Another tool that works well with cpanm is cpan-outdated (see App::cpanoutdated). It will simply list all the outdated modules' distribution names in a format that can be directly passed to cpanm:

cpan-outdated | cpanm

There are some modules that I need for every Perl installation that I'm working with, and I've bundled them into Task::BeLike::hanekomu. So after brewing a new version of perl, I'll do:

cpanm Task::BeLike::hanekomu

and get all the absolute necessities like App::Ack, App::Rgit, Devel::NYTProf and so on.

Write a comment | Bookmark and Share

posted at: 15:56 | path: /cpan_gems | permalink | 2 comments | 0 trackbacks

bash brace expansion

Last time we looked at bash parameter expansion. Now I would like to talk about bash brace expansion. This is mainly a blog about Perl, but Unix tools like shells and editors are part of a Perl programmer's life as well, so from time to time I'll write about those tools too.

Brace expansion in bash is a way of generating strings. The most general form is a list of strings within braces, separated by commas. There can be other strings before and/or after the braces; they will be included in all variations. For example:

$ echo {foo,baz,baz}
foo baz baz

$ echo prefix-{foo,bar,baz}-suffix
prefix-foo-suffix prefix-bar-suffix prefix-baz-suffix

$ for i in {foo,bar,baz}; do echo $i; done
foo
bar
baz

Brace expansion can be turned on and off using bash's B option. +B turns brace expansion off, -B turns it back on.

$ set +B

$ echo {foo,baz,baz}
{foo,baz,baz}

$ set -B

$ echo {foo,baz,baz}
foo baz baz

Here are some easy examples that show what is possible:

$ echo foo{,,,}
foo foo foo foo

$ echo {1..3}{1..3}{1..3}
111 112 113 121 122 123 131 132 133 211 212 213 221 222
223 231 232 233 311 312 313 321 322 323 331 332 333

$ echo {foo,bar,baz}{1..3}
foo1 foo2 foo3 bar1 bar2 bar3 baz1 baz2 baz3

$ echo {foo{1..3},bar{4..6},baz{7..9}}
foo1 foo2 foo3 bar4 bar5 bar6 baz7 baz8 baz9

$ cp /some/very/long/path/to/my.conf{,.bak}
cp /some/very/long/path/to/my.conf /some/very/long/path/to/my.conf.bak

$ mkdir -p /Foo-Bar/{bin,lib,eg,t}
mkdir -p /Foo-Bar/bin /Foo-Bar/lib /Foo-Bar/eg /Foo-Bar/t

$ mv foo{,-}bar
mv foobar foo-bar

You can also specify ranges using the {from..to} syntax, and ranges with steps using the {from..to..step} syntax. These ranges can be numeric or alphabetic.

$ echo {1..5}
1 2 3 4 5

$ echo {5..1}
5 4 3 2 1

$ echo {3..-3}
3 2 1 0 -1 -2 -3

$ echo {1..10..2}
1 3 5 7 9

$ echo {a..e}
a b c d e

$ echo {e..a}
e d c b a

$ echo {a..z..2}
a c e g i k m o q s u w y

One typical use for brace expansion is to tell wget or curl to download several files whose URLs conform to a certain pattern:

$ wget http://example.com/path/to/{014..017}.{html,png}
wget http://example.com/path/to/014.html http://example.com/path/to/014.png
http://example.com/path/to/015.html http://example.com/path/to/015.png
http://example.com/path/to/016.html http://example.com/path/to/016.png
http://example.com/path/to/017.html http://example.com/path/to/017.png

(bash version 4 retains leading zeros; earlier bash versions omitted them.)

I also use brace expansion in my ~/.bashrc to inspect certain directories to find out whether to they contain bin/, sbin/ or man/ subdirectories that should be added to $PATH and $MANPATH:

for d in {/usr,/opt,~}{,/{local,share,local/share,perl,perl/5.*.*}}
do
    test -d "$d/bin" && PATH="$d/bin:$PATH"
    test -d "$d/sbin" && PATH="$d/sbin:$PATH"
    test -d "$d/man" && MANPATH="$d/man:$MANPATH"
done

This effectively iterates over all of these directories:

/usr
/usr/local
/usr/share
/usr/local/share
/usr/perl
/usr/perl/5.*.*
/opt
/opt/local
/opt/share
/opt/local/share
/opt/perl
/opt/perl/5.*.*
~
~/local
~/share
~/local/share
~/perl
~/perl/5.*.*

Do you have interesting examples of using the bash brace expansion mechanism?

Write a comment | Bookmark and Share

posted at: 10:12 | path: /dev | permalink | 1 comment | 0 trackbacks

Aspect-Oriented Programming, Reloaded

Back in 2001, I wrote Aspect.pm, which brought Aspect-Oriented Programming (AOP) to Perl. It was a neat toy, but to be honest, for me that's all it ever was. I never used it even in tests, much less in production.

Now that Adam Kennedy++ has taken over maintenance of the Aspect distribution, he has rewritten its core, introduced new pointcuts and join point types and wrote a blog post in which he details the future plans for AOP in Perl.

Write a comment | Bookmark and Share

posted at: 12:02 | path: /dev | permalink | 0 comments | 0 trackbacks

bash parameter expansion

The bash shell, especially in version 4, has useful parameter expansion features. I've only just started to really use them, so I wanted to make a note of the ones that seem most interesting.

$ foo="hello world goodbye world"
$ echo "${foo/world/perl}"
hello perl goodbye world
$ echo "${foo//world/perl}"
hello perl goodbye perl
$ echo "${foo^}"
Hello world goodbye world
$ echo "${foo^^}"
HELLO WORLD GOODBYE WORLD

bar="HELLO"
$ echo "${bar,}"
hELLO
$ echo "${bar,,}"
hello

$ path="/path/to/the/script"
$ echo "dirname  = ${path%/*}"
dirname  = /path/to/the
$ echo "basename = ${path##*/}"
basename = script

As you can see, ${foo/bar/baz} takes the contents of the variable foo, substitutes the first occurrence of bar with baz and returns the result. The contents of foo are unaltered. If you want to replace all occurrences, not just the first, use ${foo//bar/baz}.

Starting with bash version 4, ${foo^} uppercases the first character, while ${foo^^} uppercases the whole string. Likewise, {$foo,} lowercases the first character and {$foo,,} lowercases the whole string.

${foo#pattern} tries to match the pattern from the start of the string and deletes the matching part of the string. ${foo##pattern} is the greedy version. In the example above, to get the directory path, we greedily delete everything from the start of the string to the final slash: ${path##*/}.

There is also ${foo%pattern}, which also deletes, but starts looking from the end of the string. ${foo%%pattern} is the greedy version. In the example above, to get the filename, we delete everything from the final slash — that is, we start looking from the end until we find a slash: ${path%/*}.

Using the above techniques you might not need to invoke the external dirname and basename programs, as the shell built-in features are powerful enough.

There is a lot more to parameter expansion. See man bash for more details.

Write a comment | Bookmark and Share

posted at: 23:31 | path: /dev | permalink | 1 comment | 0 trackbacks

PAUSE Web Service API and other Perl QA Hackathon results

In this blog post I'd like to talk about what I got done during the Perl QA Hackathon.

On Saturday I wrote a command for Dist::Zilla that uses Devel::Cover to generate code coverage metrics for a distribution: Dist::Zilla::App::Command::cover. Also I added plugin support to App::perlzonji (the more knowledgeable perldoc) so you can provide your own information sources. Ovid got interested in DB::Pluggable and wrote DB::Pluggable::Dumper; I'll try to refactor part of his work back into the main module.

On Sunday I talked with Andreas König about a Web Service API for PAUSE. I want to be able to edit maintainership permissions, add module registration metadata and delete files without having to use the PAUSE web site. Andreas agreed that this would be a good thing to have. In the first phase, to see how this all works out, we'll provide read-only access to the PAUSE data.

Writing a PSGI/Plack application was the obvious choice, and during dinner on Sunday evening miyagawa explained to me how Tatsumaki works. On Monday rafl, whose computer had unfortunately stopped working on Sunday, helped me with using non-blocking features of Tatsumaki.

Basically Tatsumaki is a framework for writing PSGI applications. Of course you can write raw PSGI applications, but Tatsumaki offers non-blocking support, path routing and takes care of the request and response objects for you. Writing a proof-of-concept PAUSE Web Service only took a few dozen lines. The API so far only consists of a few minor GET URLs and is not live yet. Have a look at PAUSE-Web on GitHub.

I also wrote a PAUSE client library to talk to the API, see PAUSE-Client on GitHub. This was really easy thanks to WebService::Simple.

In future posts I will talk more about the PAUSE Web Service API and how it is implemented.

Write a comment | Bookmark and Share

posted at: 10:26 | path: /dev | permalink | 0 comments | 0 trackbacks

This was the Perl QA Hackathon in Vienna

The Perl QA Hackathon 2010 in Vienna is over and has been a great success. It was fun, interesting, inspiring, intensive and tiring. Seeing the Perl friends again felt very good.

We met on Friday early evening and parted on Monday late evening, so the hackathon was about as long as a YAPC would be, but because there were only about thirty people and they were all in the same room, it was much easier to talk to everyone, exchange ideas and work together.

Flights, hotel costs, lunches, dinners, drinks and snacks were all paid for by Vienna.pm with the help of the hackathon sponsors, 123people.at and the Österreichische Bibliothekenverbund (the Austrian Library Network and Services Ltd).

I've uploaded my photos from the weekend to Flickr.

On Sunday and Monday there were a total of three stand-up sessions where each of us talked a bit about what he had achieved so far. brian d foy recorded them:

domm blogged about the first day of the hackathon as well. Ovid wrote about his work at the hackathon.

Write a comment | Bookmark and Share

posted at: 16:54 | path: /conferences | permalink | 0 comments | 0 trackbacks

The CPAN Leaderboard as an arcade game High Score screen

The CPAN Leaderboard shows CPAN authors ranked by the number of modules — but use this with care as it doesn't say anything about the quality of one author's distribution.

If CPAN was an arcade game, its high score screen might look a bit like this:

CPAN Leaderboard as arcade game High Score screen

Write a comment | Bookmark and Share

posted at: 15:13 | path: /misc | permalink | 4 comments | 0 trackbacks

Boolean normalization using the logical negation operator

The perlsyn manpage says the following about truth and falsehood:

The number 0, the strings '0' and '', the empty list "()", and "undef" are all false in a boolean context. All other values are true. Negation of a true value by "!" or "not" returns a special false value. When evaluated as a string it is treated as '', but as a number, it is treated as 0.

Sometimes you want to normalize a value so that it is 1 if it is a true value and 0 if it is a false value. This is sometimes called boolean normalization.

Usually you will see something like this:

my $b = $value ? 1 : 0;

There is an easier way. You could make use of the logical negation operator, !. When it is applied to a true value, it returns a dual value that is the number zero in numerical context and the empty string in string context. When the logical negation operator is applied to a false value, it returns a dual value that is the number 1 in numerical context and the string "1" in string context. Let's see this in detail:

$ perl -MDevel::Peek -le'Dump !42'
SV = PVNV(0x802000) at 0x12fef8
  REFCNT = 2147483647
  FLAGS = (IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x200160 ""\0
  CUR = 0
  LEN = 4

$ perl -MDevel::Peek -le'Dump !0'
SV = PVNV(0x802014) at 0x12ff08
  REFCNT = 2147483646
  FLAGS = (IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x200170 "1"\0
  CUR = 1
  LEN = 4

By using the logical negation operator twice you can therefore simplify the above statement to:

my $b = !!$value;

And if you wanted the opposite boolean normalization, it's even easier:

my $b = $value ? 0 : 1;

becomes:

my $b = !$value;

Write a comment | Bookmark and Share

posted at: 08:22 | path: /dev | permalink | 11 comments | 0 trackbacks

Use parent.pm instead of base.pm

For years, the common way for your class to inherit from one or more superclasses was the base module. For example:

package Game;
sub new { bless {}, shift }

package Baduk;
use base 'Game';

This works, but some people, me included, aren't quite happy with that. Basically, the above could also be expressed as:

package Game;
sub new { bless {}, shift }

package Baduk;
our @ISA = qw(Game);

If the two packages were in different files, the Baduk package would have to load the file where the Game package lives in as well. But that's about it.

However, base.pm goes further than that. It supports deprecated pseudohases, tries to be clever with $VERSION and generally just does too much. A lot of cruft has accumulated over the years. So a new module, parent, was forked from base.pm and cleaned up.

Using parent.pm is pretty much the same as base.pm:

package Game;
sub new { bless {}, shift }

package Baduk;
use parent 'Game';

This will try to load Game.pm as well. If the Game package is in a different file that is already loaded, you can tell parent.pm not to try to load the file:

package Game;
sub new { bless {}, shift }

package Baduk;
use parent -norequire, 'Game';

Compare the source of the two modules and you will find that parent.pm is a lot cleaner and easier to understand.

Write a comment | Bookmark and Share

posted at: 23:26 | path: /cpan_gems | permalink | 3 comments | 0 trackbacks