2009-06-29

even more lazyness with dist::zilla::plugin::autoprereq

who never forgot to list a prereq in their makefile.pl / build.pl / whatever? it happens to me on a regular basis.

now that i started using dist::zilla, prereqs are not listed in a build script, but in dist zilla configuration file. but the problem is the same: prereqs are listed manually. and doing stuff manually sucks.

i had to do something. so i used dist-zilla's plugin infrastructure and just uploaded dist::zilla::plugin::autoprereq. just add:
[AutoPrereq]
in your dist.ini, and it will automatically find your prereqs for dist::zilla to use.

the parsing is somehow very rough: it will just find the lines beginning by use or require. for more advanced / hackish stuff, dist::zilla::plugin::prereq is still available. i still think that it should cover 80+% of the cases. i considered using module::info, but it evals the modules to find the prereqs and the result is damn slow... and speed was more important imo.

note that i plan to add the possibility to add modules manually, in order to add missing modules (or maybe we can use both prereq and autoprereq?), and a skip option to trim modules that should not be added to the list of prereqs.

also, i may change the algorithm used to find prereqs: maybe ppi will be fast enough? we'll see.

but in the meantime, just enjoy not writing anymore those prereqs by hand! :-)

2009-06-25

beginning of moose support in padre

so i started using moose like all the cool kids today. it turns out to be quite nice to use. declaring an attribute is as easy as:
has foo => ( is=>'ro', ... );
and since i'm also using poe, i was glad to find the illicit love child of moose and poe - aka moosex::poe. declaring an event without any fuss:
event frobnize => sub { say $_[0]->foo };
but when your module grows to have lots of attributes and poe events, it's difficult to go directly to a given definition in the file.

readers of this blog know that i'm using padre (the perl ide), but neither the sub nor the outline views can help. indeed, if you look the code snippets above, there is no traditional sub definition... syntaxic sugar is nice, but it means the tools need to be aware of them.

this was clearly an itch to scratch... i had a look at padre's outline code, and after some help from alias, here's the result:

the patch is surprisingly small: around 20 lines for attribute detection, and the same for event detection... that's the beauty of having cpan modules at hand - the great ppi in this case.

(note: the feature is in trunk currently. you'll have to wait 0.38 release)

so, try padre. tell us which feature it lacks. or how can we make it the modern perl editor, the one that would be recommended alongside moose and others.

2009-06-22

where are builtin tk icons? (aka tk::toolbar fun)

for everything gui related, my favorite toolkit is tk. it's quite powerful, easy to learn and to use, and feels quite perlish [0]. in a word, it doesn't get in the way.

yeah, of course, current version is not the most up to date [1][2] - but it gets the job done, with the help of some nice tk additional modules available on cpan.

one of those modules is tk::toolbar, from ala qumsieh. and it comes with a set of bundled icons that are loaded. they may not be the prettiest icons out there, but they are available and allow you to do something like [3]:
$mw->Label( -image => 'fileopen16' )->pack;
instead of having to create & load the images yourself.

knowing this, when i needed to add an icon in my new project (yes, yes, i need to present it here), i loaded tk::toolbar in my code, and re-used one of the bundled images.

well, that was my goal anyway - the image never appeared... i tried to tweak my code in every direction, but did not manage to make this icon appear.

having rebuild perl-tk package yesterday to fix a bug in mandriva's package, i thought it might be related... so i tried to run a perl/tk gui provided in one of my other modules using tk::toolbar's icons, but the icons were correctly displayed. so long for this idea...

after having fought 5 minutes, i finally managed to understand what was going on: in this new project, i currently do not have created the toolbar. and since the icons are loaded in the classinit() method, called during the creation of the first widget of this particular class, the icons were not loaded...

so i created a toolbar [4], and miracle! the icon i wanted magically appeared.

tricky one...


[0] contrary to wxwidgets for example - at least imnsho
[1] i'm using plain tk 804.028 and not one of those tk ersatz tcl::tk [5] or tkx [6]
[2] slaven told me he would like to update it when he'll have some tuits...
[3] tk allows you to name the images you load, to do for example:
$mw->Photo( "foo", -file=>"path/to/some/image.jpg" );
[... later on ...]
$mw->Label( -image => "foo" )->pack;

[4] i'll populate the toolbar later on
[5] which is far from complete, and does not seem to be maintained anymore
[6] which doesn't compile easily out of the box, and feels really clumsy after tk goodness. oh well, i guess beauty is in the eye of the beholder...

2009-06-21

prepender distzilla plugin can add boilerplate copyright

following autarch's advice on yesterday's post, i just uploaded dist-zilla-plugin-prepender 0.2.0 that accepts a copyright option to automatically add a boilerplate copyright at the top of the files.

yet another things that ease an author's life.

i'm still unsure with the strict and warnings options. not because of the test argument, but because of the editing argument. indeed, with padre (the perl ide) doing live syntax check, i want the syntax check to be done with all due stricture...

2009-06-20

new distzilla plugin: prepender

when i first heard of dist::zilla, its concepts definitely appealed to me. it took me quite some time (never the good time, plus i needed to create the rpms for mandriva), but i finally managed to try it...

and although i still need to get used to it, i'm already really happy with it. on the new project that i recently started (more on that later on), i'm letting dist::zilla deal with all those pesky copyright, version, pod, etc. stuff.

however, i'm used to add some boilerplate at the top of my files, as the fsf recommends. and i found nothing in dist::zilla to do that... so i just wrote a new plugin for it: dist::zilla::plugin::prepender.

just add the following in your dist.ini file:
[Prepender]
line = #
line = # This file is part of Foo::Bar
line = #
line = # Foo::Bar is copyright...
but it can also be used to enforce some common pragma: since it will be inserted at the top of the file, the pragma will be applied to its lexical scope - the whole file itself in this case:
[Prepender]
line = use strict;
line = use warnings;
since those usages are quite common, i might as well in a future version propose them as options:
[Prepender]
copyright = 1
strict = 1
warnings = 1
but i'm not really sure... wdyt?

2009-06-18

which parrot version to package?

after some lengthy discussions finding the final versioning scheme for parrot, allison finally decided that parrot will use the following version numbers:
  • 1.0 (March, deprecation point)
  • 1.1 (April)
  • 1.2 (May)
  • 1.3 (June)
  • 1.4 (July, deprecation point)
  • 1.5 (August)
  • 1.6 (September)
  • 1.7 (October)
  • 1.8 (November)
  • 1.9 (December)
  • 2.0 (January, deprecation point)
  • 2.1 (February)
  • 2.2 (March)
  • 2.3 (April)
  • 2.4 (May)
  • 2.5 (June)
  • 2.6 (July, deprecation point)
  • 2.7 (August)
  • 2.8 (September)
  • 2.9 (October)
  • 2.10 (November)
  • 2.11 (December)
  • 3.0 (January, deprecation point)
the stable versions will be the deprecation points - that is, 1.0.0, 1.4.0, 2.0.0, 2.6.0 and 3.0.0. this means that those versions may have some bugfix releases during their support lifetime (1 year), but only for very limited stuff (security or other critical problems). everything is described in parrot's support policy.

as parrot packager for mandriva, this is good to know. however, i don't really know what to do: should i package the stable versions? or should i update the package for each new devel version?

since parrot is quite in flux those times, version 1.0.0 (which is 3 monthes old) is really useless... if you add that almost nothing production-ready relies on it currently, i have decided to update the package on a monthly basis. which means that rpm for parrot 1.3.0 is available on cooker right now.

but let's think forward a bit... when rakudo will be able to use an existing parrot, when perl 6 will be in production, i won't continue like that: i'll just stick (of course) with the production releases... but when will this point happen? when will i switch from devel to stable versions? this remains to be seen...

2009-06-11

redefining exported subs in perl

i've explained in a previous post that i changed the way i was logging debug statements within language::befunge. i mentioned that i applied some tricks and promised to explain them - so here are the explanations.

the goal is to minimize time spent for debug statements. previously, i was doing:
$interpreter->debug(@stuff);
and debug was a method defined as:
sub debug {
my ($self, @stuff) = @_;
return unless $self->debug_mode;
warn @stuff;
}

so, to log a debug message, i was doing:
  • a method call on $interpreter
  • a second method call to check an attribute
  • finally the actual logging (skipped if we're not in debug mode)
this is bad, especially since method calls cannot be resolved at compile time by perl, and thus are actually resolved during run-time. but what's worse is that this always happens, even if we're not in debug mode (which is around 99% of the time).

so, one obvious way to improve was to move from a method to a plain sub. this would remove the run-time cost of resolving the method. the debug mode can be stored as a package scalar instead of an attribute.

but we can do even better. knowing that:
  • perl optimizes out calls to empty subs
  • we are not in debug mode most of the time
we can define the debug sub as an empty sub!

here's our code at that point:
package Language::Befunge::Debug;

use 5.010;
use strict;
use warnings;

use base qw{ Exporter };
our @EXPORT = qw{ debug };

sub debug {}
of course, we need to provide a way to activate debugging. a naive approach would be to redefine our debug() sub in our debug package:
sub enable {
*debug = sub { warn @_; };
}
alas, this won't work. well, it will work for calls such as:

Language::Befunge::Debug::debug(@stuff);
but calls using exported debug() will still log nothing. indeed, it's important to understand that exporter installs a copy of exported sub in the package. therefore, changing the definition of the original does not change the exported copies.

so, to redefine exported subs, one is forced to walk the symbol table of all packages and redefine subs on the fly. here's what i ended up doing:

my %redef;
sub enable {
%redef = ( debug => sub { warn @_; } );
_redef();
}

sub disable {
%redef = ( debug => sub {} );
_redef();
}

my %orig; # original subs
sub _redef {
my $parent = shift;
if ( not defined $parent ) {
$parent = '::';
foreach my $sub ( keys %redef ) {
$orig{ $sub } = \&$sub;
}
}
no strict 'refs';
no warnings 'redefine';
foreach my $ns ( grep /^\w+::/, keys %{$parent} ) {
$ns = $parent . $ns;
_redef($ns) unless $ns eq '::main::';
foreach my $sub (keys %redef) {
next # before replacing, check that...
unless exists ${$ns}{$sub} # ... named sub exist...
&& \&{ ${$ns}{$sub} } == $orig{$sub}; # ... and refer to the one we want to replace
*{$ns . $sub} = $redef{$sub};
}
}
}
there, it will redefine my sub in all packages, even the ones that hold an exported copy.

now, do you think this would warrant a sub::redefine module on cpan? after all, i found nothing on cpan that would achieve that. otoh, i'm not sure it's that common to do this kind of things... so tell if you're interested, and i'll turn that in a cpan module for your own use.

2009-06-06

cpan2dist oddity

cpanplus is great - really, i mean it. i don't like its internals, and having to adapt to it for cpanplus::dist::mdv is not my fondest memory. however, it gets the job done, and that's what counts in the end.

but cpanplus has some oddities in the user-space also. cpan2dist, which is a tool allowing you to create a native package for your platform, sometimes makes me cry.

it insists on building prereqs for the module you want. that's fine, except for one thing: it will also build packages for modules that are not up to date... and this is where the fun starts.

you can think that --nobuildprereqs would prevent this, but nope, it's the default and really means: "don't rebuild prereqs if we're at latest version, but rebuild anyway if we're not at latest version". the --buildprereqs indeed means "i really really want to loose my time, please rebuild a package for all the prereqs even if i already have them installed and working". like this option is of any use... erm.

so in app::cpan2pkg, in order not to build the prereqs, i ended up using --ignore flags (flags as in plural form, since using a negative look-ahead regex such as /(?<!$name)$/ do not work). it took me quite some time to come up with this solution, since --ban was not working at that time.

so life was good, i've used cpan2pkg quite some time to create rpms for mandriva, and updated it till v1.0.0. however, since some time, i can see strange things in the packages submitted on upstream buildsystem: the build prereqs were not set. and i had to update the spec file manually, adding all those missing prereqs. i got tired of that, and investigated what happened.

after some experiments, it appears that cpan2dist seems to have somehow changed the way it handles its --ignore flags. ignored modules now are removed from the prereqs completely, and thus the cpanplus::dist backend do not even see them any more. and thus, buildrequires end up empty. of course, --nobuildprereqs still retained its old silly behaviour...

fortunately, it seems that --ban now works correctly (at least on 2 tests that i made). so i've just updated cpan2pkg, and version 1.1.0 should be available soon on cpan, this time really adding the needed buildrequires.

till the next cpan2dist change, of course... :-|

note: i don't want to sound too harsh to jos in this post... i totally understand that cpanplus is still 0.x software - moreover, this is a bug fix in my mind, since --ban was not working.

2009-06-05

some befunge love

i took some time to review my befunge modules. trying to speed up things is always fun, so thanks to devel::nytprof, i saw that i was spending quite some time on my debug statements.

it should be noted that those statements were method calls on the main language::befunge::interpreter object. and the method then was outputing things depending on the value of a debug attribute of the interpreter. the interpreter was not used outside of this.

knowing that method calls are expensive (since perl doesn't know until run-time where to find the method), i therefore created a language::befunge::debug module that exports a debug() sub. 2 other subs are provided (but not exported) to turn on/off the debug. (there's a trick here, that i will explain in another post).

net result? around 20% speedup (a bit more in fact). not bad for one hour spent on the subject. :-)

other than that, language::befunge tests got sanitized (using test::more, test::output and test::exception everywhere instead of crafting stuff by hand). part of this code was not touched since 2002...

finally, language::befunge got some new extensions, still passing all mycology tests. you can now enjoy the following in jqbef98:
  • CPLI - complex numbers extension
  • DIRF - directory operations
  • FILE - file i/o operations
  • FIXP - fixed point operations
  • STRN - string operations
  • SUBR - subroutines extension
  • TIME - date/time operations
some of them were pretty difficult to get right, if you forget some befunge basis (note to self: the storage offset is here for a reason, dammit!).

which leaded me to update language::befunge::debugger to load mycology correctly, with a new option to run without delay till the next breakpoint. using it, things were easier to get right. still not perfect, but already more than usable...

so, enjoy language::befunge 4.11 and language::befunge::debugger 0.3.6, now available on cpan!