Hi! Please consider following me on twitter: @hanekomu.
2010年07月16日
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.
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.
posted at: 15:56 | path: /cpan_gems | permalink | 2 comments | 0 trackbacks
2010年05月28日
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?
posted at: 10:12 | path: /dev | permalink | 1 comment | 0 trackbacks
2010年05月27日
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.
posted at: 12:02 | path: /dev | permalink | 0 comments | 0 trackbacks
2010年05月25日
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.
posted at: 23:31 | path: /dev | permalink | 1 comment | 0 trackbacks
2010年04月14日
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.
posted at: 10:26 | path: /dev | permalink | 0 comments | 0 trackbacks
2010年04月13日
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.
posted at: 16:54 | path: /conferences | permalink | 0 comments | 0 trackbacks
2010年04月01日
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:
posted at: 15:13 | path: /misc | permalink | 4 comments | 0 trackbacks
2010年03月18日
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;
posted at: 08:22 | path: /dev | permalink | 11 comments | 0 trackbacks
2010年03月17日
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.
posted at: 23:26 | path: /cpan_gems | permalink | 3 comments | 0 trackbacks
