Sat Feb 23 21:00:00 2013

A Perl of your own

The conversation

If you'll allow me a little hyperbole, I feel like over the past couple of weeks I've had roughly this conversation several dozen times:

Them:

You should change the defaults of perl!

Me:

But then everybody's old code would stop working.

Them:

You should change the defaults of perl!

Me:

But there's no real agreement on what defaults we should have instead.

Them:

You should change the defaults of perl!

Me:

But in 2 or 3 years we'd want different defaults and have the same problem.

Them:

You should change the defaults of perl!

Me:

I don't even want to discuss this, it's out of scope for Pumpkin Perl

Them:

You should change the defaults of perl!

Me:

...

So I thought maybe I should try and figure out why.

A tentative diagnosis

I don't really think most of the people getting annoyed here are actually annoyed because they wish /usr/bin/perl behaved differently.

I mean, you're probably running a perlbrewed perl or one built into /usr/local or something that gives you a newer one than your distro/OS/whatever shipped.

But, on the other hand, I do understand why people hate typing the same half dozen lines at the top of every .pm file they write.

I think, really, this is about "I don't want to have to think about this" which is a reasonable thing to want, but I think the definition of "this" is actually per project.

For a scripty thing I'd likely want IO::All available by default, for example; a large scale app, quite probably not.

More importantly, I think most of the participants are also releasing code to CPAN, so they're better served by a solution that works with perl as it is, rather than as they might like it to be.

So I wrote a thing

So earlier this week I wrote a module called lib::with::preamble that lets you tell perl you have an @INC dir that should be loaded as if it always had a particular set of lines at the front.

There is, by the way, an Acme::use::strict::with::pride module that does this to all of @INC if you want to see just how many things do actually break.

But it was implemented using a source filter, with comments about possible confusions, and ... I wanted to see if I could do it without. Turns out, yes I can.

sub with_preamble {
  my ($preamble, $fh) = @_;
  PerlIO::via::dynamic->new(untranslate => sub {
    $preamble and $_[1] =~ s/\A/$preamble/, undef($preamble);
  })->via($fh);
  return $fh;
}

If I apply that to a $fh I'm about to return from a coderef in @INC (see the perldoc for require for how that part works), then those lines get prepended.

Oh, and it also prepends

# line 1 lib/My/Module.pm

so that your line and file numbers for errors look right.

Then all I needed was something that generated a -M list, so

$ myperl bin/foo

becomes

$ perl -Mv5.14 -Mautodie=:all bin/foo

(except also with a lib::with::preamble invocation to turn them on for lib and t/lib too)

plus a quick wrapper for prove so that

$ myprove t/foo.t

calls prove with --exec=myperl so that your test scripts get the same treatment

and ... presto.

Using myperl

Crack open .myperl/modules and add

v5.14
autodie=:all

and you'll find that when you run

$ myperl bin/foo

then those modules are present for the script, and for anything you load from lib/ (it also adds t/lib to make test libs able to participate, too).

When it's time to ship, all you have to do is arrange for

$ myperl-rewrite My-Dist-Dir-0.001

to be called and it'll add the relevant lines to the front of every .pm and .t file and any scripts in bin/.

Which means that you can pretend that perl has whatever defaults you put into .myperl/modules, and ship your code without needing anybody else to have those defaults.

You can get this now

$ cpanm App::MyPerl

should give you a shiny fresh set of myperl, myprove and myperl-rewrite scripts.

I put the code onto github so you can look, experiment, break it and add features.

Oh, and if you believe that my suspicion that this is better than defaults in perl itself to be unfounded, then please do consider this as a way to get what you want now ... and to experiment with what defaults exactly you'd like.

Quietly. Over there in the corner.

Because tomorrow I'm going to be talking some more about Pumpkin Perl, and changing the defaults of perl is still out of scope for what I'm proposing :)

Have fun!

-- mst, out.

(you should tell me what you think by commenting at blogs.perl.org)