2009-12-31

rt.cpan.org updated - thank you bestpractical

so it seems that we got a nice present for christmas from bestpractical: rt.cpan.org has been updated to last version 3.8

thank you, and keep up the good work!

2009-12-29

helping perl packagers package perl modules (for real this time)

chromatic posted a long rant (who would have guessed? :-) ) about perl modules shipped by linux distributions. however, he doesn't have all the answers... nor the experience needed for this rant. since i'm a perl author and mandriva packager for perl and lots of perl modules, i think i have more enlightened information about this topic.

first, let me state that using system perl is fine, but i really discourage it for your enterprise application. the perl version will change from time to time, ditto for the perl modules you are relying upon. so if you want to be in control your software foundation for your app (and you should) - compile your perl and your modules yourself.

second thing: i also discourage mixing using perl modules installed by your package system and by running cpan as root. you'll end up with a mix of files in /usr/perl5 that either belong or not to a system package, which sucks. installing packages in a local lib of yours is fine, which is made quite easy with local::lib by now.

if you're comfortable with those rules, then you're welcome to using the system perl and the modules shipped by your distribution. after all, we packagers are going through this work in the hope of being useful to others - that is, you!

but back to chromatic post. if you want to install cpan modules as system packages, there's already a tool that does it for you: it's called cpan2dist, and is part of cpanplus. it works as long as a backend for your distribution exists. there's currently one for debian, mandriva (that i wrote), fedora and gentoo. it's not that difficult to write, and allows you to write:
# cpan2dist --format CPANPLUS::Dist::Mdv --install Foo::Bar
this will automatically download foo::bar, check its dependencies (and build & install them if needed recursively), build the module as a mandriva package and install it. what else exactly do you want/need? (as a cpanplus backend writer, i do have some things that i'd like cpan2dist to have, but none as a regular user). and if you're a packager and want to integrate cpan2dist with your linux distribution build system, cpan2pkg can help you (even if it's currently stalled due to sthg missing in cpanplus).

however, if you want to help perl packagers package your modules for a distribution, here's a list of thing that you should not do. this is a list of real, practical things to do as a module author - not some generic hand-waving towards the perl community out there. this comes from my experience as packager for mandriva of more than 400 modules, and makes me curse the module author everytime i'm encountering one of those problems...

  • test your dist before shipping. really, i'm not kidding. lots of dists just fail their tests. and not just on linux, on all the platforms. so if you make an update that "just can't fail" (yeah, right) to your dist just before shipping, please run your test suite nevertheless. just in case, you know, it might fail.
  • if you're shipping pod tests that are skipped depending on the presence of test::pod and test::pod::coverage, make sure you have those modules installed, so you are running those tests, too. even better: skip those tests unless RELEASE_TESTING or AUTHOR_TESTING is set. after all, it's nice for you to know you still have some documentation work to do, but i don't care as a packager... and, you know, it's now the standard & recommended way of shipping those tests.
  • those 2 items lead me to another easy thing for module authors to do to help us: check the cpantester status of your dist. investigate all the fails that you have. if you see a fail that is your fault, fix it and upload a new version. it helps us because this prevents us from having to report a bug against your dist. i generally wait 3 or 4 days before reporting a bug on a dist that has some failure reports, hoping (what a fool) that the author will notice by herself that sthg is going wrong.
  • speaking of bug reports, if we take the time to open a report for your dist (very often with a patch attached)... please read it. and act. or at least answer us. either apply the patch, or explain why you don't want to apply it like that... and ship a new version of your dist, with the fix included.
  • but of course, before reporting a bug, we should find the bug tracker. so, by using rt.cpan.org, you really help us to have a single unified point of contact. i know that rt is kind of slow, not very intuitive, has some problems and could be cleaned out a bit... but it is here, bestpractical is providing & administering it for us for free, and has this nice feature of having a queue for every perl dist on cpan. if you don't want to use it, there are some more polite ways of saying it... and giving the url of your tracker helps, too. oh, and if i took the pain to play by your rules and report a bug to your non-standard bug tracker, i would greatly appreciate that you act on my ticket. or at least, you know, just acknowledge the fact that you received the report.
  • if you want to really piss off a packager, a simple but effective way is to change your versioning scheme every now and then, by (ab-)using your knowledge of perl way of understanding versions. in the same major version, of course. going from version 1.470 to 1.50 is not funny. if you want to change your versioning scheme, you can change the major number to. after all, i'm pretty sure that you're not paying any extra money per major number used in your dist. this is what caused us to mangle the version of perl modules shipped in mandriva.
  • speaking of regular changes, it's irritating to have to follow you through your use of makefile.pl to build.pl to makefile.pl to build.pl to... well, you understand what i mean. even to use this shiny replacement that is module::build, or this oh-so-marvelous module::install, oh no finally module::build way of working fits me better in retrospective... it's ok for you to change from time to time, but changing at every version of your dist - just make up your mind dammit!
  • speaking of it, i hate module::install. and especially its feature that prompts and tries to handle the deps itself coz-it's-so-cool-it-can-do-it-for-real. sorry, but that's not your job in the tool chain. just report that you miss some deps. i know that there's a flag to make this feature go away while launching makefile.pl. but i don't want to bother and would rather expect that the whole stuff has sane defaults...
  • oh, and in case you're wondering - every prompting in the configure phase (makefile.pl or build.pl) sucks and should be banned.
  • having clear and up-to-date dependencies would be fine, too. i know it's not always easy to have them correctly, but you can change your tools and adopt one that extract your prereqs for you.
  • try to avoid dependency on modules that are known to fail. even if it works in your setup, trust cpantesters if they tell you that it fails 95% of its reports: it might not be a good idea to depend on it.
  • trying to support old perl versions and old releases of modules is fine, but update your modules and see if your code work. some functions may become deprecated, or you were relying on a buggy behaviour, or whatever. we update the perl packages as we see new versions, not only your modules. so a linux dist will usually have latest & greatest version of all the modules - you'd better be sure that your code work with them, hmm?
  • finally, if you're developping under macosx, make sure that you don't ship resource files, or textmate temp files. having ._Foo.pm in the dist is not fun: automatic compile tests will fail, unless that's your manicheck or signature check. and even if everything in perl dist is fine, things may bork in the repackaging of the system package due to a file not listed. so, be extra careful when shipping your dist - or change platform and burn your shiny toy that calls itself a computer (careful & clever readers may have guessed from previous sentence that i don't like macosx - but that's not a reason to ditch this post and not to follow the advices i'm reporting).
there, i think that's a pretty good start. i've encountered each and every item of this list at least once (i stopped counting exactly how much a long time ago). don't take it personally if you made some of those mistakes - i have done almost all of them by myself as module author (except of course using module::install and using a mac, but you could have guessed for at least the last part). what's important is to realize that those behaviours are annoying for packagers, and that changing those habits is quite easy to do (except for the burning your mac part, because i agree that it's not very environmental-friendly - see, i'm not that stubborn! ;-) ).

if you're following all those advices, packagers of your modules will love you. (or at least, not hate you - which is still a win :-) ). i know i will...

2009-12-23

scrapping web pages with embedded javascript in perl

recently i had to download various pdf files from a vendor website, which list them according to different criterias. since i'm lazy, i wanted to write a script that would download all those files for me.

that would be quite easy, but the list was generated by some ajax when i was changing the criterias... so, what to do to pally this problem?

there are some solutions out there for the perl programmer.

although www::mechanize's author stated that he does not want to bother with integrating javascript support, someone wrote a javascript plugin for mechanize. it's still experimental by now, though.

the same author, leveraging his knowledge, also wrote www::scripter that's supposed to achieve the same result.

but before going in those complex beasts, it may be worth trying to understand what the javascript is doing, and if the hidden url that gives the wanted list of files is easy to guess. to do that, you can go the hard way and read the javascript... or the easy way and wiretap the network!

enters http::proxy which is a configurable proxy written in perl by book. among the various examples, it comes with a logger.pl script that displays all the urls accessed by your browser (with cookies). run it as is, configure your browser to use a proxy on localhost port 3128, and check the output of logger.pl while tinkering with your ajaxy application.

chances are that you'll see a url such as http://www.examplecom/path/to/script/list/?crit1=foo&crit2=bar&limit=10

well, that was the case for me, and i could just download the list according to my criterias, parse it with the excellent html::tree and download each of the files separately... \o/

so the title of this blog post is wrong: no javascript webscrapping (although i gave some hints on how to do it), but cheap trick to achieve the same result! :-)

2009-12-16

parrot 1.9.0 available in mandriva

since parrot 1.9.0 is officially out, it landed quite quickly in mandriva cooker. next rakudo version will soon follow.

2009-12-09

rakudo available in mandriva

after some chat with parrot-porters, i finally undertood that what's get installed in /usr/src/parrot (and that i was trimming during installation) is not parrot full source, but intermediate forms of pmc, needed if high-level languages want to subclass them. they are thus now shipped in parrot-src package - and this is enough for rakudo to be compiled.

therefore, rakudo 2009-11 is now (finally) available in mandriva...

2009-12-05

mojomojo now available in mandriva

after struggling quite some time with its dependencies, and then some other prereqs not mentioned deep in the dependency chain, i'm happy to report that mojomojo, the catalyst powered wiki, is now available in mandriva.

2009-12-02

migration to moose - step 3

continuing [0] to port mpd modules to moose - this time it's poe::component::client::mpd turn. in order to do that, i had to fix the tests (using the shiny new test::corpus::audio::mpd) in order to be sure not to introduce regressions.

migration was quite easy, but a bit long. especially since i used a lazy_builder attribute for the connection, leading to commands sent before actual connection took place - and thus the tests failed with a cryptic message from poe::component::client::tcp [1]

the excellent moosex::poe was used too, but not in the connection, since it reuses various components having a more classic way of defining their events.

and now that the base code is moose-ified, i think i'll be able to gain more clarity while leveraging some moose levers.


[0] see this previous post and this one
[1] saying that {server} doesn't have a put method... as opposed as what's documented. but that's because at that time it has not (yet) morphed into a poe::wheel::readwrite. even if i'm at fault for not waiting the connected event, couldn't it provide a better error message?

2009-11-25

announcing git plugin for dist-zilla

pushing lazyness even further, i released a git plugin for dist-zilla. in fact, there are 4 plugins within the distribution. they are kicking in during dzil release, since i've hacked dzil to provide beforerelease and afterrelease roles.

dzp:git:check - this plugin checks that git is in a clean state before releasing. the following checks are performed before releasing:
  • there should be no files in the index (staged copy)
  • there should be no untracked files in the working copy
  • the working copy should be clean. the changelog and dist.ini can be modified locally, though.
if those conditions are not met, the plugin will die, and the release will thus be aborted. this lets you fix the problems before continuing.

dzp:git:commit - once the release is done, this plugin will commit in git if needed changelog and dist.ini (which is a valid target if you happen to set the version manually in it). the commit message will be taken from the changelog for this release.

dzp:git:tag - once the release is done, this plugin will record this fact in git by creating a tag named v$VERSION.

dzp:git:push - once the release is done, this plugin will push current git branch to remote end, with the associated tags.

if you want to use all those neat plugins, you may want to use the git plugin bundle by writing in your dist.ini:
[@Git]
there, one more thing that dzil is doing for me... no more time lost doing those tedious steps - if you're lazy, you should really try it! as usual, comments and feature requests are welcome.

2009-11-18

sweetening tk

after discovering how to sweeten moose with moosex::has::sugar, i thought the concept could be extended for other modules.

as a tk enthusiast, this was a logical target. especially since i was already kind of doing this with some internal modules exporting variables. so i decided to just extract this piece of code, update it and wrap it in a new module, tk::sugar.

so, where previously you were doing:
you can now write:

which is way better imo.

of course, the module supports lots of other often-used helper subs - check the doc for more information. and if you need some more, either request them or clone the repository and send pull requests! in the meantime, enjoy it...

2009-11-14

sweetening moose

even if moose is nice and allows to prune a lot of code, it can still be seen as cryptic. take the following example, and imagine that you have a lot more attributes to declare:

the first thing that can be done is using moose builtin types instead of their name, with moosex::types::moose. this allows to remove the quotes around the types:

but that's still a bit mouthful. enters moosex::has::sugar, for a nicer code:

your code is now more readable - yet some other modules that i'll now use in my dists...

2009-11-09

cpan activity

with mandriva linux 2010.0 out, it's time to have a look at cpan activity once again.

version freeze happened on october 1st for mandriva, at which point it wasn't possible to upload new version - unless to fix a bug preventing usage. since we know that cpan modules don't have such bugs[0], it means that almost no perl package was updated till cooker[1] reopening (which happened on november 6th).

so, how many dists needed an update after ~40 days? around 150. yes, 150. on 1685 distributions shipped by mandriva. and some of those were updated more than once...

that's ~10%. a bit less than what was reported in april for mandriva 2009.1, but:
  • this time it's for whole mandriva, not only the packages i'm responsible for
  • freeze was a bit longer for 2009.1
yet another proof of perl community's health.

[0] :-)
[1] cooker is mandriva's development version

2009-11-03

the state of perl in mandriva 2010

mandriva linux 2010 is out... this is thus a good time to have a look at the state of perl in this release.

adelie (mdv 2010 codename) ships perl 5.10.1 with threads[0], which allowed me to drop half the patches carried within mandriva[1]. and since perl 5 porters hope to make perl 5 releases more often, it means that (hopefully) i'll be able to trim down those patches even more!

on the modules front, mandriva is shipping plenty of them. padre 0.47 (and lots of plugins), moose, poe framework (and lots of components), devel modules, dbi drivers, gui (tk, wx, gtk) and various lib bindings, you name it... using book's pearl of wisdom, this gives us[2]:
12117 installed modules
including 11016 from cpan (15.65% of cpan)
that is 1685 distributions (8.88% of cpan)
that's not half of cpan, but a good deal nevertheless. chances are that you will find the module you need - and if you don't, drop me a mail or open a request and i'll package it for you.

but the biggest change that you will see in mandriva 2010 regarding perl (well, maybe you won't even notice it), is the new standardized version scheme forced upon all perl modules. for example, dist-zilla version 1.092680 is shipped for mandriva 2010 in rpm perl-Dist-Zilla-1.92.680. yes, i know, it means that the mandriva version might differ from upstream version. yes, i am aware that this sucks. yes, i am also aware that there's no real way to get upstream version back from mandriva rpm version. and no, i don't plan to roll back this change - unless you have another miracle solution that deals with rpm not understanding cpan modules changing their versioning scheme without bumping their major (grrr!).

however, note that previous mandriva version (and fedora too) already mangled some modules version, but not all of them - which is even worse imo. since i agree with david that version numbers should be boring, all modules now have their version mangled. no ifs, no buts, we're mangling it. and it makes life easier for us packagers...

of course, the modules' code is not affected by this change. it's only the packaging that changed a bit. to check which version is installed, just check the $VERSION of this package. that's always been, and remains, the only safe way to be sure. eg:
$ perl -E 'for (@ARGV){eval "require $_"; say "$_\t",$_->VERSION if !$@}' Dist::Zilla
Dist::Zilla 1.092680
on the parrot front, we're shipping 1.6.0 (1.7.0 was too late to be included). and rakudo is still not present, since it cannot use an installed parrot.

all in all, that's a quite a good release on the perl front. if you add all the work that went in all other areas, mandriva 2010 will be quite a solid release. i invite you to test it out - who knows, you might even like it so much that you'll switch to it permanently! :-)

[0] no need to complain, rgs - i know your feelings about it.
[1] yup, i took the ownership of the perl package - silly me...
[2] why, yes, i install all perl modules available as rpm on my box :-)

2009-10-28

right trimming for dzil autoprereq plugin

autoprereq plugin for dzil used to trim all modules under the dist namespace from the list of prereqs. eg, for dist-zilla dist, it would trim all dist::zilla::* modules.

although good for a first try, it had two problems:
  • modules outside of your dist can be trimmed. eg, audio::mpd is requiring some audio::mpd::common modules which are outside of audio-mpd dist.
  • if your dist is shipping 2 namespaces, only the modules inside the first namespace are trimmed, and you can end up with a dist with circular deps.
the first one is easy to solve with a fixed [Prereq] section in your dist.ini (this is what i've done for audio-mpd). and the second is not really common, so i thought that i could leave dzpa as is...

but dams now uses dzil for the excellent curses-toolkit - which ships curses::toolkit::* and poe::component::curses::* modules. so he complained (rightly) and i had to fix autoprereq plugin.

so, dzpa will only trim modules that are part of the dist, instead of blindly removing the modules under the dist namespace. and this only change fixes at once the 2 problems outlined above. where dzpa used to trim too much and not enough, it now trims just what it has to...

2009-10-25

migration to moose - step 2

another module converted to moose (and dist-zilla): audio::mpd. migrating the attributes is quite easy, but this time the constructor migration was a bit trickier to do. fortunately, moose lazy building proved handy.

since the module is quite stable by now, i bumped version to 1.x (1.yyyddn even).

one more module with a simplified code-base... next migration will be pococm, and should prove more difficult, but for even more reward (thanks to moosex::poe).

2009-10-21

test::corpus::* namespace

both audio::mpd and poe::component::client::mpd share the same files for their regression test suite. this includes some boring ogg files - weighing around 150 kb. although not that much, those files are duplicated between those 2 modules.

moreover, it means that everytime i upload a fix for one of those modules, i'm taking some more space on cpan for those exact same files - they never ever change...

something had to be done. i therefore wanted to split this raw test data, and put it in a module of its own. the other 2 modules would then get rid of the test data, and require the new one during the tests.

the question was of course how to name this module. i asked module-authors for advices, and david nicol proposed the test::corpus::* namespace.

since the idea is quite sound, i then released test::corpus::audio::mpd with the data (with some fixes to bring it up to mpd 0.15.x). audio::mpd has already been migrated to use this. i still need to do it for pococm, though.

anyway, this post is merely about the announce of the test::corpus:: namespace, to hold your test data instead of putting them in your dists. let us know what you think of it.

2009-10-14

dist-zilla: compile tests can skip some modules

the compilation test plugin for dist-zilla now accepts a parameter to skip some modules. this can be handy to prevent testing some known-to-fail modules - yes, this can happen if your module does stuff assuming a given environment not currently in place (eg: test modules...).

just use the following in your dist.ini file:
[CompileTests]
skip = Test$

the skip parameter is interpreted as a regex, matched against the module name (not the file name of the module). in this example, all modules with a name ending with Test will not be tested for compilation.

2009-10-11

migration to moose - step 1

as promised, i just migrated audio::mpd::common to use moose. and since i was at it, i also took the opportunity to migrate to dist::zilla!

conclusion: it takes some time to migrate (around half a day?) - and this is a very small dist! maybe i should have not mixed moose and dzil migration... but the resulting code is also easier to read, and better documented now, so it's not a one to one migration.

anyway, i'll continue migrating the mpd related modules to moose, dist-zilla as i find the tuits.

2009-10-05

mandriva 2010 coming - which perl modules do you miss?

mandriva's next version (2010.0) is now in version freeze, for a release date in early november. this means that current packages are not allowed to be upgraded to latest version, unless there's a compelling reason to do so (security update, crash or big regression).

there is still, however, the possibility to ship new packages. so if you miss some perl modules in mandriva and you really want them available as rpm packages in 2010.0 version, now is the time to speak up! just add your request as comment to this post, and i'll do my best to fulfill it.

2009-09-29

about exporter bug

finally exporter with multiple inheritance bug is explained: class::accessor::fast version 0.34 now does some import magic, and in that case export's import sub is not called. so it's neither perl, nor exporter related.

but still, using multiple inheritance cannot be avoided sometimes...

multiple inheritance - why still using it

ovid reacted to the bug i opened against exporter and multiple inheritance, stating that we cpan authors shouldn't use multiple inheritance, since roles exist.

with all due respect to ovid, this is over-simplifying. cpan holds 15000+ distributions, of which maybe 5% is proposing a role-based api (and i think i'm generous). which means that a lot of the modules available needs you to inherit from them[0]. so what to do when you want to use those modules? yup, multiple inheritance. i know it's bad - but i don't have the choice, mmk?[1]

i can already predict ovid's answer: my bug was related to inheriting from both exporter and class::accessor::fast[2], so i should switch to moose to replace the class::accessor bit. right, i plan to do it later on (patches welcome, too).

but in the meantime, i have a module that worked perfectly under 5.10.0, and that breaks under 5.10.1 (i am still not sure if it's perl or exporter or base/parent related). no need to talk of greypan and compatibility accross major perl releases: i'm talking of backward compatibility of minor perl version for regular cpan module with code available here. and even if it's using sub-standard technology - i am entitled to not expect this kind of breakage.


[0] which is not exactly surprizing, since roles are quite new in perl's oo landscape: 2.5 years according to moose's changelog. if you count some time to let the new feature stabilize, get some needed speed boost and gain acceptance, i don't expect to see a lot of non-role based api soon.

[1] i'm not advocating to use multiple inheritance at all costs. ovid is right: if you can, compose classes with roles. really, he is right on this topic. however, the key words here are if you can.

[2] see how both synopsis request you to inherit from them?

2009-09-28

working around exporter bug in perl 5.10.1

exporter seems to have a bug with perl 5.10.1. in case of multiple inheritance, it must be the first parent, otherwise no export magic is done.

the bug is experienced both with base and parent, so i really think it's exporter related - or maybe 5.10.1, since it was not present with 5.10.0.

i reported the bug to p5p - in the meantime, just switch exporter to be the first parent in multiple inheritance...

2009-09-23

external event loops no more part of poe

for those (such as me) that did not spotted it, external event loops for poe are now released as their own distribution. this means they aren't part of the poe distribution anymore, and you should add them to your prereqs...

of course, there's no way that dzil's autoprereq plugin could extract poe::loop::tk from code such as:


so, i had to use the regular prereq plugin to list it as a manual dependency. since dzil is using moose roles, it means more than one plugin can provide the prereqs, so i can continue using autoprereq beside this exception - woohoo!

in conclusion, games::pandemic 1.092660 is on its way, fixing a problem reported by a cpantester (thank you guys - you rock!)

2009-09-21

first external pandemic translation

i'm really happy to release a new pandemic version, namely 1.092640 (that is first release of 264th day of year 2009 for those that skipped previous entry).

beside the introduction of the medic player (which in itself is interesting), it's with great pleasure that i committed a japanese translation that tomita naoki provided me with. thank you tomita for this first external contribution!

so, if you want to contribute, an easy way to start is by providing a translation for your language! of course, any other contribution is also welcome. :-)

2009-09-14

moosex::poe ftw!

in the serie "why using moose and moosex" - today i present moosex::poe.

say you want to create a poe session. traditional way is to create a module handling spawn method that would be called as:


the module itself would be something like this:


now that's moutful. and it has an easy-to-miss error - found it? right, it's should be event3, not evnet3. you can curse poe quite some time trying to understand why your nice handler never gets called for event3.

here's the version using moosex::poe:


of course, it's still possible to mis-spell event3. however, you only have to spell it once, whereas you wrote it 3 times before - which is 2 times too much!

and i'm not talking about the easy accessors that could be added by moose - but i'm concentrating on moosex::poe here.

granted, there's one downside: subs are now anonymous, which can make it a bit harder to debug. but that's a small price to pay, imo.

so, moosex definitely makes your code more readable - i'm definitely not looking back, and i advise you to have a look too.

2009-09-07

full pandemic stikes, woohoo \o/

erm, not this pandemic, but the pandemic game written in perl...

so yes, i'm happy to report that milestone 1.01 has been reached. indeed, here's what warrants the bump:
  • infection rate grows as epidemics strike
  • special event: airlift implemented
  • special event: forecast implemented
  • special event: government grant implemented
  • special event: one quiet night implemented
  • special event: resilient population implemented
  • epidemics now shown in past cards
yup, this means the game is fully playable. i'm not saying fully implemented, since there are still stuff missing such as the medic or dispatcher roles, the possibility to choose the difficulty, number of players, etc. and of course lots of polishing is needed to get rid of all those peksy details that get in the way.

however, all in all, i'm quite happy (and proud) of the release. version 1.0 is definitely not the ultimate one, it only means that you can play with it with comfidence.

of course, i'm always eager to have (constructive) feedback2 on it. and if you want to contribute, well, the source is available on github.

[1] in fact, it's 1.000000 (i know it's ugly) since i'm switching to rjbs' versioning scheme: 1.yydddn3. it'll make versioning boring (even if not beautiful).
[2] fan & love mail is ok too :-)
[3] yes, i'm taking every bad habit rjbs has to offer, as long as it helps my laziness. of course, games-pandemic is using the excellent dist-zilla since the beginning.

2009-09-01

migrating to moose? hell yeah!

dave is asking whether we (cpan authors) would consider migrating to moose.

between moose which brings a lot of nice features, moosex extensions such as attributehelpers (which i'm being said is going core) or moosex::poe (poe integration ftw!), there is so much that moose can bring to developers!

less fuss, less coding, more fun...

of course, moose is a bit slow during startup (but not afterwards). but even if i respect adam's will not to slow down padre too much during startup, i'd be in favor of using it nevertheless for padre. after all, we can expect some speed gains if moose's adoption continues to rise.

so, at least for me, the answer to dave's question is a definitive yes! i am considering switching to moose, and i'll end up doing that when i'll have the tuits to migrate my modules.

note: i should also add that since i'm at it, i'll also switch my modules to dist::zilla, which does a fantastic job to promote lazyness :-) but that's another topic...

2009-08-28

pandemic nearing v1

so games::pandemic 0.8.0 has just been uploaded on cpan. this release saw lots of improvements:
  • diseases can be eradicated
  • performing infection outbreaks
  • detecting game over condition when too many outbreaks
  • allowing player to choose which disease to treat in multi-infected cities
  • return/escape bindings for dialogs
  • tooltips for various game information
  • fix unfair epidemic repartition
  • fix never-ending too many cards / deal more cards when dropping a card but still being beyond max number of cards
  • better dialog for past cards / infections
the game is thus playable, with only 2 things missing to have a full game: augmenting number of infection when epidemic strikes, and special event cards. when those will be done, i'll issue 1.x

of course, this does not mean that game is complete and won't be improved after. for example, the startup dialog to choose the game and player roles, ui improvements, etc. will be post 1.x material.

but in the meantime, enjoy 0.8.0, which is already quite interesting to play.

2009-08-24

perl 5.10.1 has hit cooker

perl 5.10.1 is out, so i just built it for mandriva cooker - after fighting the build system which seems to be broken very often those days. :-(

it's currently propagating on mirrors, and should hit your machines soon... lots of other packages will need to be rebuilt, so you may want to run urpmi with the --keep flag.

in other news, parrot 1.5.0 is also available on cooker since yesterday.

2009-08-22

new pandemic release

games::pandemic 0.7.0 is now on cpan, with a lot of improvements and a crash fix:
  • wiping all cubes from a city if a cure has been found for the disease
  • reacting to winning conditions
  • reacting to game over condition when no more disease cubes
  • possibility to see cards already played / discarded
  • possibility to see past infections
i'm taking my time, but all in all there is progress... :-)

2009-08-17

more dzil goodness

i'm happy to announce yet another plugin for dist-zilla: critictests.

in your dist.ini, just add:
[CriticTests]
and dist-zilla will automatically create for you an xt/author/critic.t file that will criticize your code during author tests.

of course, since your code will be munged by dist-zilla, code that passes critics in your repo may fail after being rewritten... case in point: stricture use, since dist-zilla-plugin-pkgversion will insert a version just after the package statement - and thus before any use statements. in order to make your code compliant again, just move the use strict / warnings before the package. indeed, use is lexically scoped, and thus the scope of the use statement will be the whole file.

your code will now look like:
use strict;
use warnings;
package Foo::Bar;
and of course, perlcritic this time will now be happy.

2009-08-09

perl 5.10.1-rc1 available on mandriva

perl 5.10.1-rc1 has been released 3 days ago, so i packaged it for mandriva. the good thing is that a lot of patches that we were adding to our perl are now merged upstream.

the new perl (perl-5.10.1-0.rc1.2mdv at the time of writing) rpms are available in mandriva testing media. you can install them with:
# urpmi perl perl-base --media "Main Testing"
please report any problem to either mandriva cooker mailing list, or to perl 5 porters if that's a perl related bug.

2009-08-08

epidemics strike in games::pandemic!

games::pandemic 0.6.0 is now on cpan, with a lot of improvements:
  • introducing epidemic events - fear! :-)
  • closing current game is now supported
  • player cards now displayed in a window of their own
  • detecting game over condition when no more cards
  • sorting cards by type then by disease then by city name
  • introducing a new "action" menu, with shortcuts for actions
  • actions now independant of buttons / menu for easier reuse
of course, there are still a lot of things to do, but it's shaping up nicely...

2009-08-07

shipping compile tests with dist-zilla

perl community places some emphasis on testing. which is great, since it enhances the overall quality of perl ecosystem.

the first, easiest test that one should provide is basic: making sure the modules compile. we have 2 options here:
  • either create a test and add some use_ok('Foo::Bar'). but we then need to update it whenever we add more modules to our distribution - without forgetting to update test count.
  • or, to get rid of this burden, ship a test that automatically finds the module and tries to compile them.
but shipping the exact same generic test is boring, and could be automated. which is now the case for dist::zilla with the new module dist::zilla::plugin::compiletests. just add the following in your dist.ini file:
[CompileTests]
and you will get a brand new t/00-compile.t that will test your modules and your scripts one by one. this my take some time if your dist ships a lot of modules having lots of prereqs, especially if they are a bit slow to compile such as Moose. but this will potentially find more compile errors in your modules.

2009-08-06

more moose support in dzp:autoprereq

dist::zilla::plugin::autoprereq just gained more moose support: it can now extract the base module declared with:
extends 'Foo::Bar';
it's not perfect since it only extracts the first base class, but i think it will cover 90+% of the cases out there.

2009-08-04

bash completion for dzil command

lazyness strikes once again: i've created a (rough) bash completion file for dzil command that rjbs just merged. it will be available in next dist::zilla release.

2009-08-01

converting & rebuilding mandriva perl modules rpm

as time went by, the %perl_convert_version[0] macro in rpm has proven useful to convert perl version number to something that rpm will (should) always be able to parse. i also patched mandriva's perl.prov and perl.req (that automatically extracts requires & provides for perl in rpm packages) to use %perl_convert_version also.

the last step happened this week, when guillomovitch has converted youri checks to also compare newer cpan version with %perl_convert_version. therefore i'm currently migrating the not-yet converted mandriva perl rpm package to use %perl_convert_version also[1]...

expect some problems during installation till all modules are converted. this should be solved soon.


[0] so that eg 1.54 is understood as 1.540.0, and thus greater than 1.470 - as on cpan.
[1] when the build system works! :-)

2009-07-24

autoprereq plugin for dist-zilla gets smarter

i just released dist::zilla::plugin::autoprereq 0.2.0 which now extracts prereqs from moose roles declared with the with keyword [0]. also new in this release is the support for skip list, allowing to trim unwanted prereqs.


[0] why, yes, i got some failures for games::pandemic 0.5.0 due to a missing prereq... defined in a role, you guessed it. :-)

2009-07-22

parrot 1.4.0 landed on mandriva

latest stable parrot version (1.4.0) is now available on mandriva - enjoy.

2009-07-18

pandemic turns implemented

so games::pandemic 0.5.0 is now released[0].

the basic game play is now done: besides the player actions, the cards are now dealt and infections propagated. card limit is also implemented, so player can discard them if needed. add to that a bit of ui polishing, and we now have a solid basis on which to build upon...

next releases will see (in no special order):
  • the special cards (including the epidemics)
  • end of game conditions (both game-over and win cases)
  • more ui polishing (i think the players cards will have their own toplevel)
  • easier game play (drag-n-drop on the canvas)
  • missing player features (dispatcher, medic)
  • missing rule implementation (disease eradication, ...)
  • start game dialog
  • etc.
yup, that's still a lot to do, so expect other 0.x versions! ;-)

[0] and without any more warnings, since i spotted a bug in moosex::semiaffordanceaccessor which has been swiftly fixed!

2009-07-10

prettyfying tk apps

one of the main griefs people have against tk is the fact that it looks ugly. however, it's possible to tremendously enhance tk with only one line. indeed, tk by default uses a 2 pixels wide border, which does look fugly.

here's a snapshot of config::model (used as an example):


now, try to insert the following line in your code:
$mw->optionAdd('*BorderWidth' => 1);



here's the result, still using config-model as guinea pig:


look at how the buttons are crisper... now that's better, uh? :-)

thanks to ala qumsieh who first reported this tip on perltk.org - but the site seems to be down nowadays.

note: i'm told that tk 8.5 can be themed and looks native. but i'm still using perl/tk which is build against tk 8.4

2009-07-02

perl helps save world pandemic

ok, maybe the title was a bit too much dramatic - especially in those days. :-)

i like playing board games, and my wife and i discovered recently pandemic, from z-man games. it is a tremendous cooperative game, where players allies to eradicate 4 diseases. but the infections spread out, and if you aren't fast enough, you end up with a global pandemic - and loose...

it is really addictive, so i decided to write a perl module games::pandemic implementing a clone of this board game, with all its rules. it was also a good occasion to learn moose, dist::zilla and other modern perl stuff. at least, this goal is already fulfilled! :-)

i'm also using poe and tk (i know, i know). i just published the first public release, version 0.4.0. it already implements all the player actions, and here's a snapshot of a game:

of course it isn't finished, but i'm pretty happy of the result (even if the gui might change in the future). i aim for a v1.0.0 playable alone, and then allow networked game...

the code is available on github if you want to help - even "only" translating strings is welcome!

so, expect to hear more about pandemic on this blog. and while waiting for this perl version to be complete, i recommend you to buy a pandemic board game: you won't regret it...

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!

2009-05-29

image resizing in perl

perl is really versatile, and can do a lot of things. moreover, you can do it in a lot of different ways. the difficult part being sometimes to choose the way you want to do it...

so i need to resize an image within perl. this is for games::risk, a perl implementation of the famous board game (btw, try it and tell me if you like it!). i want the background image to fit the window size on resize events. of course, i want it to be fast - but i also want something maintainable.

looking on cpan, i found 3 modules: gd, image::magick and image::imlib2. using gd to resize a picture is a nightmare, therefore i ditched it for image::resize which is a convenient wrapper around gd.

here are the needed incantations to resize:
  • with imlib2

  • my $old = Image::Imlib2->load($src);
    my $new = $old->create_scaled_image($w, $h);

  • with image::magick - note that the operation is done inplace, so one needs to clone the image first to compare the same things.

  • my $old = Image::Magick->new;
    $old->Read($src);
    my $new = $old->Clone;
    $new->Scale(width=>$w, height=>$h);

  • with image::resize

  • my $old = Image::Resize->new($src);
    my $new = $old->resize($w, $h);

so i benchmarked them and found that on average, image::imlib2 is a few times faster than image::magick, which is itself around the same speed or a bit faster than image::resize.

however, image::imlib2 has a drawback: the only way to get back the new image is to save it to a file, where one can get the new image as a scalar directly:
  • image::resize with $img->jpeg
  • image::magick with $img->ImageToBlob


therefore, one must also take this into account in the benchmarking! so here's the latest version of the bench:

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;

use Benchmark qw{ :all };
use Image::Size;

use Image::Resize;
use Image::Imlib2;
use Image::Magick;

my $src = "src.jpg";
my $dst = "dst.jpg";

my ($w, $h) = imgsize($src);
my @sizes = (
[10,10], [100,100], [1000,1000],
[640,400], [840,600], [1024,768],
[$w,$h], [$w/2,$h/2], [$w/4,$h/4],
[$h,$w], [$h/2,$w/2], [$h/4,$w/4],
);

my $imlib2 = Image::Imlib2->load($src);
my $resize = Image::Resize->new($src);
my $magick = Image::Magick->new; $magick->Read($src);

foreach my $s ( @sizes ) {
my ($width, $height) = @$s;
say "-> ${width}x${height}";
local $/;

cmpthese( -3, {
imlib2 => sub {
my $img = $imlib2->create_scaled_image($width, $height);
$img->save($dst);
open my $fh, '<', $dst;
return <$fh>;
},
magick => sub {
my $img = $magick->Clone;
$img->Scale(width=>$width,height=>$height);
return $img->ImageToBlob;
},
resize => sub {
my $img = $resize->resize($width,$height);
return $img->jpeg; # $img->png
},
} );
say '';
}


and i was quite astonished to see that image::imlib2 is still 2 or 3 times faster that image::magick or image::resize!

so, imlib2 may not the best api around, but sure it's fast...