I need closure

Suppose you wanted to create a list of closures, each of which spits out a new number in sequence. Pretty easy:

my @subs;
foreach my $num( 1 .. 10 ) { 
    push @subs, sub { return $num };
}

print $_->(), "\n" for @subs;

This is a simplified example of something I needed to do in Javascript, but I did it wrong.

Converting a Moose application to a Mouse|Moose hybrid

Hailo has been converted from a Moose application to a hybrid Mouse/Moose application for release 0.20.

This brought its memory usage from 28MB to 20MB. Hailo is around 4.000 lines and the patch required to make it Mouse + Moose compatible (including testing both at make test time) is just under 500 lines.

As well as reduced memory use another big plus is the reduced startup time. hailo(1) starts with Mouse in around 250 ms flat whereas with Moose it hovers around 530 ms. The difference in startup time is clear when running the testsuite with Moose & Mouse:

We had to hack around there not being a MouseX::StrictConstructor analogous to MooseX::StrictConstructor and I fixed a bug in Mouse which caused Mouse's Int type not to support values larger than 2^32 on 32 bit systems.

{Logging, Messaging, Notification, Auditing, ...} frameworks

They're all the same, in many respects.

In my module code, I want to be as flexible as possible. I want to be as detached from implementation details as possible.

I just want to generate a log message (or a notification, or an audit entry). I don't want to care where it ends up, how it is sent, how it is filtered/categorized, who the recipient(s) is/are, what medium(s) is/are used, etc. Let whoever uses the module configure it all.

And I don't want to reinvent the wheel, I want to use an existing framework. A logging framework seems to be a sensible choice. Let's use Log::Any for example. This is a snippet from a module for a file-manager-type web app:

Custom Hacks and Comfort Levels

As I'm working on my Veure project, I've used DBIx::Migration to handle database migrations. If you're familiar with this module, this might seem like a surprising choice since it is, well, awful. However, I know exactly what the limitations are and since I'm so familiar with it, I now have a custom Veure::DBIx::Migration. There are several things I find useful about this.

  • It's not tied into a specific ORM.
  • It's very simple.
  • It's easy to fix and make PostgreSQL-specific hacks I need.

Actually, that's almost a lie.

Cleaning up old code (Part 1)

Way back in 2005 I posted my first CPAN module (Log::WithCallbacks). It had proved useful on several different projects, and I thought it would be nice to share. I struggled a bit with namespace selection and was never able to resolve a nasty permissions problem with the tarball I submitted. I got busy with other things, and my poor module got neglected.

While on humor... best error msg in a while


Warning: something's wrong at /home/sawyer/code/private/KiokuDB-Backend-DBI-0.08/lib//KiokuDB/Backend/DBI.pm line 563.

Really? I could've never figured something was wrong there. I wouldn't assume you feel like... telling me what's wrong, would you?

Oh, and whoever read my last post via RSS and wondered why there's no code, it's because I was using Github Gists and it doesn't pass some RSS readers. Open the entry and you could view it.

The problems with older CPAN clients

Thank God for cpanminus. Now that I'm free from having to use them, allow me to rant, no, bitch about them.

1. Bad defaults. Some default values might make sense 10-15 years ago, but not so much nowadays. For example, I'd argue that "follow" should now be default. See #2.

2. Too developer-oriented. For example, I believe "notest" should be on by default. This is compounded by the fact that installing Perl modules is so damn-slow already. See #3.

3. Too slow. Startup takes around 10-30 seconds or more. Installing Moose usually takes minutes (but with cpanminus, it only takes about 1 minute with --notest on my PC). Autocomplete takes one to a couple of seconds.

4. Too interactive, too verbose. The older clients are getting better but not quiet enough, cpanminus is such a breathe of fresh air.

5. Too bloated (which is the reason why cpanminus was developed in the first place).

The older CPAN clients are an embarassment if we compare it to "apt-get", "yum", "urpmi", which are way faster, way quieter, way less interactive. There's no reason why a CPAN client cannot be like those. And fortunately cpanminus proves it.

The Last Lines of a Particularly Painful Class I Wrote

no warnings 'void';
"if you stare into the void, the void stares back at you";

Belgian Perl Workshop 2010: Call for Papers and Attendees...

Hi,

The 3rd Belgian Perl Workshop will take place on June 26, 2010 nearby the touristic area of Brussels.

The workshop is targeted towards everyone either developing with or interested by Perl.

Obviously, the workshop is only as good as its talks, your talks.

We are interested in all talks about Perl itself or about Perl related topics, and especially talks that would apply to this year's theme.

The theme for this year's workshop is "The Renaissance of Perl", which we hope will inspire submissions on this and related topics. Also it gives any speaker a very good opportunity to practise a talk for YAPC::EU 2010. ;-)

The submission deadline for your 5, 20 or 40 minute talks is June 01, 2010.

Lingua Franca for the talks is English (unless you manage to give the presentation in Dutch, French and English in 1 go ;-) ).

cool experience: Spreadsheet::WriteExcel;

I just want to say, if you need to do some Excel, do it with Perl!

I needed to create some excel sheets based on automatically calculated data. Instead of copying huge amount of data I fired up my IDE, issued

use Spreadsheet::WriteExcel;
use Spreadsheet::WriteExcel::Utility;

$workbook = Spreadsheet::WriteExcel->new($myExcelFile);
$worksheet = $workbook->add_worksheet($sheet);

and was ready to go.
Spreadsheet::WriteExcel has very good documentation (excellent examples included), is very complete and is really a pleasure to use.

Besides: Use Spreadsheet::WriteExcel::Utility to convert between different cell notations. A1 <-> (0, 0) and be aware that one is base 1 ("base A", respectively) and the other base 0.

The shorter path to deployment heaven

Now that there is cpanminus, I've modified the handy little module CPAN::AutoINC to prefer cpanminus over CPAN.

So now when users download and run my programs/scripts for the first time, instead of failing with the dreaded message:

Can't locate Foo/Bar.pm in @INC (@INC contains: [a dozen or more of paths....]).
BEGIN failed--compilation aborted at /some/path line 123

which users or even Perl novices have no clue on how to fix, the program will instead automatically download every necessary CPAN modules into the user's home directory and runs out-of-the-box on the first try!

Writing your own Search::GIN extractor

I stumbled into a tricky situation with Search::GIN that required me to have a reverse indexing with set introspection. This situation isn't so rare, so I thought it would be helpful to share how I did it.

Suppose I have an object. The object has an attribute. The attribute is a set of objects. I need to be able to fetch the objects according to the value of an attribute of the objects in the set in the attribute of the original object. Err.. ya know what? Here's an example!

I have a few music preferences (blues, jazz, etc.), a few simpsons characters (Lisa, Homer, Barney). Each of them likes certain types of music. Lisa likes blues and jazz, while Barney only likes blues and Homer just likes stupid commercial jingles.

First define the objects:

The create them:

The All New Yahoo! eFail Client

So let's say you're looking around for a Web-based email client. Even though the Application Service Provider industry has struggled, many people want Web-based email. So when you evaluate an email client, what are you looking for?

You probably want to be able to send email. You probably want to be able to receive email. In fact, I'll go out on a limb and suggest you might want to read the email you receive. So when you are looking at email clients, what's the one feature you really, really want?

You might think, I dunno, that email is an important feature of email clients. Yahoo! thinks you want to send e-cards.

Yahoo is dropping my emails

It seems that over the last days, around 20% of the mails I have sent from my yahoo.com account did not reached their destinations, didn't I get any notification about the failure.

If you were expecting a reply to some particular mail from me and didn't got anything, you are probably one of the "lucky winners". Just ask for your reply and I will resend it!

Log::Any::App

This is a draft/RFC document.

Log::Any is great if you're writing modules . You only need to say:
use Log::Any qw($log);
and then you're off producing logs with:
$log->debug(...);
$log->warn(...);
# etc
But if you're writing scripts/applications (and thus need to "consume" or display the logs as well), it becomes a bit of a hassle. For example, if you want to display logs to the screen with Log::Dispatch , this is the incantation you need:

While I'm on the subject of shell scripting ...

How often have you wanted to cut n paste a module name from some error message onto the command line and just edit the damned file? Isn't it a huge pain in the arse changing all the :: into slashes?

function vi {
VI=/usr/bin/vim
INARGS=("$@")
OUTARGS=()
for i in ${INARGS[@]}; do
if echo $i|grep ::>/dev/null; then
OUTARGS=(${OUTARGS[@]} `echo $i.pm|sed 's/::/\//g'`)
else
OUTARGS=(${OUTARGS[@]} $i)
fi
done
$VI ${OUTARGS[@]}
}

There, I fixed it :-) Now you can do this and it'll Just Work:

$ vi lib/MyApp::Module::That::Is::Broken

One Thing I Love About Git

If you've been using Subversion or (shudder) CVS, you only have the briefest glimmerings of what source control is about. I don't really like having to dig too deeply into tools that I use. I want them to be easy, but I dig when something's hard.

On thing which frustrated me about Subversion is that fact that, as mentioned, I don't think about some things. More than once I've quickly hacked up a change to a module, switched other modules to use that module and do a quick svn rm and svn add.

Oops. I just lost my version history. Damn it.

Not with git. It figures it out for me. My Veure project uses DBIx::Class::Schema::Loader because I don't want to think about building my schema classes. The 0.5003 version is fantastic. It does a better job of naming relationships and the DBIx::Class::Schema::Loader::DBI::Pg support is fantastic.

My first bug report!

Even though I helped on various projects, I never really got a bug report on a project of my own. I've gotten offline requests (usually from people who know me personally), but never an actual RT ticket.

Today I got my first RT ticket (in the mail) and I've very proud of it!

Apparently there was a change in Template::Tiny's API. mst made it more compatible with Template::Toolkit and Adam Kennedy released Template::Tiny 0.11 and took the time to open a ticket with Dancer::Template::Tiny to require 0.11 and up, and update the code. I've updated the code, changed the requirement and done the same with Task::Dancer. Both of them on the way to CPAN as we speak.

Why am I sharing this small tidbit? (isn't tidbit a funny word? I think it is)

Bash perldoc completion tweaks

Remember when I wrote the following?

Completion in bash is hard-wired to understand trailing slashes as “the user might want to do more completion right after this” – we want :: treated that way instead but there is no way to tell bash.

This is still true, but reading the manpage a little less carelessly reveals that passing -o nospace to the complete command tells bash to simply never append a space, which achieves what is desired without hacks.

While I was in there, I found -o default, which means that if the completion generator returned no results, bash should use its default completion generator instead. This is very useful.

Tools to solve perly problems

So, you've got a problem with something perlish. What language do you use to solve it?

My particular problem is that my CPAN-testing machines were all fed off CPAN's RECENT file (eg http://www.cpan.org/RECENT), which would update every few hours. This is apparently no longer being updated, instead there's a much more up-to-date YAML file (http://www.cpan.org/authors/RECENT.recent) that updates within seconds of something hitting the PAUSE. But my ugly lash-up of shell scripts expects the old format, so what's a boy to do?

I *could* write some perl that uses LWP::Simple and YAML to grab the file and parse out the information I need. Alternatively, I could do this:

GET http://www.cpan.org/authors/RECENT.recent \
|grep 'path: id\/.\/..\/' \
|grep '.tar.gz$\|.zip$' \
|sed 's/ *path: id\/.\/..\///g' > RECENT

which fits much better with the rest of the system :-)

About blogs.perl.org

blogs.perl.org is a common blogging platform for the Perl community. Written in Perl with a graphic design donated by Six Apart, Ltd.