<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9112560338291574360</id><updated>2012-02-16T17:11:46.893Z</updated><category term='Config::XPath'/><category term='Net::Async::HTTP'/><category term='Socket::GetAddrInfo'/><category term='Encode'/><category term='Module::PluginFinder'/><category term='POE::Wheel::TermKey'/><category term='AnyEvent'/><category term='C'/><category term='IO::Async::Loop::AnyEvent'/><category term='perl'/><category term='overload::substr'/><category term='IO::Socket'/><category term='Test::Identity'/><category term='IO::Async'/><category term='events'/><category term='POE'/><category term='Carp'/><category term='List::UtilsBy'/><category term='IO::Socket::IP'/><category term='BPF'/><category term='LPW2010'/><category term='module naming'/><category term='Term::TermKey'/><category term='Parser::MGC'/><category term='ironman'/><category term='Error'/><category term='ECMA-48'/><category term='unibilium'/><category term='rant'/><category term='libtermkey'/><category term='Term::Terminfo'/><category term='IPv6'/><category term='Net::LibAsyncNS'/><category term='terminals'/><category term='sockets'/><category term='cpan'/><category term='Test::Fatal'/><category term='tiny'/><category term='Tickit'/><category term='XML'/><category term='struct'/><category term='terminfo'/><category term='YAML'/><category term='ExtUtils::H2PM'/><category term='Text::CharWidth'/><category term='IO::KQueue'/><category term='Sentinel'/><category term='Term::TermKey::Async'/><category term='Linux'/><category term='Socket'/><category term='AnyEvent::TermKey'/><category term='Glib'/><category term='CPS'/><category term='IO::Async::SSL'/><category term='testing'/><category term='XS'/><category term='LPW2011'/><category term='libvterm'/><category term='Circle'/><category term='Module::Build'/><title type='text'>LeoNerd's programming thoughts</title><subtitle type='html'>My thoughts, ideas, and sometimes rants, on Perl, C, Linux, terminals,...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>42</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-5503280589281629539</id><published>2012-01-29T17:16:00.000Z</published><updated>2012-01-29T17:16:48.280Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Term::TermKey'/><category scheme='http://www.blogger.com/atom/ns#' term='libtermkey'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>libtermkey 0.12 + Term::TermKey 0.11</title><content type='html'>Last week I updated &lt;tt&gt;&lt;a href="http://www.leonerd.org.uk/code/libtermkey/"&gt;libtermkey&lt;/a&gt;&lt;/tt&gt; to version 0.12, and associated with it, the Perl module wrapper &lt;tt&gt;&lt;a href="http://search.cpan.org/dist/Term-TermKey/"&gt;Term::TermKey&lt;/a&gt;&lt;/tt&gt; to &lt;a href="http://search.cpan.org/%7Epevans/Term-TermKey-0.11/"&gt;version 0.11&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Primary changes are the fact it will now support an abstract mode, where an instance can be constructed not associated with a TTY filehandle. Instead of being read from the filehandle, bytes provided to the library directly by the application.&lt;br /&gt;&lt;br /&gt;While I originally wrote this to support someone using the library where the application is already reading in bytes from the TTY by some other mechanism, I did lately find a new use for it. By applying a small string parser to a &lt;tt&gt;readline&lt;/tt&gt; &lt;tt&gt;inputrc&lt;/tt&gt; file, its raw byte sequences can be turned into &lt;tt&gt;libtermkey&lt;/tt&gt; representations instead. I don't quite have an example of this robust enough yet to demonstrate, but hopefully by the next version of &lt;tt&gt;Term::TermKey&lt;/tt&gt; I'll get around to writing one. I have a plan to write a &lt;tt&gt;Tickit::Widget::ReadlineAlike&lt;/tt&gt;, which would go as far as parsing the user's &lt;tt&gt;inputrc&lt;/tt&gt; file to discover all the keybindings to apply.&lt;br /&gt;&lt;br /&gt;Also included in 0.12 are plenty of manpage updates, including also an online copy of them rendered into HTML on my website &lt;a href="http://www.leonerd.org.uk/code/libtermkey/doc/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-5503280589281629539?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/5503280589281629539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2012/01/libtermkey-012-termtermkey-011.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5503280589281629539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5503280589281629539'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2012/01/libtermkey-012-termtermkey-011.html' title='libtermkey 0.12 + Term::TermKey 0.11'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-360218939371056686</id><published>2011-12-13T16:22:00.001Z</published><updated>2011-12-13T18:19:03.821Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Socket'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - more Socket</title><content type='html'>&lt;p&gt;Some of you may have noticed that I'm now maintaining Socket dual-life on CPAN. Recently uploaded is &lt;a href="http://search.cpan.org/~pevans/Socket-1.96/"&gt;version 1.96&lt;/a&gt;, which is an extraction of what was in bleadperl, updated to support building out-of-core on versions of perl back to at least 5.10.0, and some nicely rewritten documentation.&lt;p&gt;&lt;p&gt;My plans for 1.97 are to neaten up the build system a bit more. Currently it's a rather hastily-written set of support code to handle the dual-life nature of it, so it can build on CPAN outside of core. Once that is in place, it will be much easier to add support for new features.&lt;/p&gt;&lt;p&gt;At this point I'll be starting to take more ideas from around CPAN. What constants or structure handling functions need adding. What socket options are being used in practice? And new protocol families it doesn't yet support - e.g. &lt;tt&gt;PF_RFCOMM&lt;/tt&gt; (Bluetooth)? If anyone has any feature requests, now would be an excellent time to get them to me. :)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-360218939371056686?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/360218939371056686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/12/perl-more-socket.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/360218939371056686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/360218939371056686'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/12/perl-more-socket.html' title='Perl - more Socket'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-1832111712167899352</id><published>2011-11-24T20:11:00.000Z</published><updated>2011-11-24T20:11:50.785Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>No longer thinking about Perl 5.8</title><content type='html'>This week I got around to rebuilding all my local Perl module packages for the Perl 5.14.1 now in debian testing. Because that replaced the 5.12.4 that was previously running, I've rebuilt that into my homedir with &lt;tt&gt;perlbrew&lt;/tt&gt;.&lt;br/&gt;&lt;br/&gt;Added to the 5.10.1 I previously had, that's still one system and two custom installed perls I have. I try to remember to test everything before releasing it to CPAN on all these three.&lt;br/&gt;&lt;br/&gt;At this point, I can't really be bothered to look after 5.8 as well, so effectively I'm no longer testing anything on 5.8. I'll still keep an eye on smoke-test results and see if they're passing or failing, and if I see a failure that looks easy to fix I might have a go at it. But no promises now.&lt;br/&gt;&lt;br/&gt;If I manage to break anything on 5.8 in a module of mine and anyone actually cares about it, feel free to raise me a bug on rt.cpan.org. But apart from that, I hope I don't have to think too much about 5.8 any more.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-1832111712167899352?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/1832111712167899352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/11/no-longer-thinking-about-perl-58.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1832111712167899352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1832111712167899352'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/11/no-longer-thinking-about-perl-58.html' title='No longer thinking about Perl 5.8'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-4856171145809918555</id><published>2011-11-15T19:00:00.001Z</published><updated>2011-11-15T19:04:38.136Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='LPW2011'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>LPW2011 Talk Slides</title><content type='html'>If anyone wants to see the slides of the talks I co-presented with Tom this year at LPW, they're at&lt;br/&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://docs.google.com/present/edit?id=0ARPsKlp7RKTpZGZuNzYycGhfN2hrdnB3OWN6"&gt;A Protocol for Protocols&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://docs.google.com/present/edit?id=0Abtck6K7NL6AZGd6bjhwbmhfNnhxcDJ3d21q"&gt;Tickit&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Though, at least the latter talk was mostly a series of code demos, so the slides alone won't make much sense.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-4856171145809918555?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/4856171145809918555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/11/lpw2011-talk-slides.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4856171145809918555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4856171145809918555'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/11/lpw2011-talk-slides.html' title='LPW2011 Talk Slides'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-8586916542511312433</id><published>2011-11-03T19:11:00.000Z</published><updated>2011-11-03T19:11:03.413Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='tiny'/><category scheme='http://www.blogger.com/atom/ns#' term='struct'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - Tiny lightweight structures module</title><content type='html'>&lt;pre&gt;$ cat struct.pm &lt;br /&gt;package struct;&lt;br /&gt;&lt;br /&gt;use strict;&lt;br /&gt;use warnings;&lt;br /&gt;&lt;br /&gt;sub import&lt;br /&gt;{&lt;br /&gt;   shift;&lt;br /&gt;   my ( $name, $fields ) = @_;&lt;br /&gt;   my $caller = caller;&lt;br /&gt;&lt;br /&gt;   my %subs;&lt;br /&gt;   foreach ( 0 .. $#$fields ) {&lt;br /&gt;      my $idx = $_;&lt;br /&gt;      $subs{$fields-&gt;[$idx]} = sub :lvalue { shift-&gt;[$idx] };&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   my $pkg = "struct::impl::$name";&lt;br /&gt;&lt;br /&gt;   no strict 'refs';&lt;br /&gt;   *{$pkg."::$_"} = $subs{$_} for keys %subs;&lt;br /&gt;   *{$caller."::$name"} = sub { bless [ @_ ], $pkg };&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;1;&lt;br /&gt;&lt;br /&gt;$ perl&lt;br /&gt;use struct Point =&gt; [qw( x y )];&lt;br /&gt;my $p = Point(10,20);&lt;br /&gt;printf "Point is at (%d,%d)\n", $p-&gt;x, $p-&gt;y;&lt;br /&gt;$p-&gt;x = 30;&lt;br /&gt;printf "Point is now at (%d,%d)\n", $p-&gt;x, $p-&gt;y;&lt;br /&gt;$p-&gt;z = 40;&lt;br /&gt;&lt;br /&gt;__END__&lt;br /&gt;Point is at (10,20)&lt;br /&gt;Point is now at (30,20)&lt;br /&gt;Can't locate object method "z" via package "struct::impl::Point" at - line 6.&lt;/pre&gt;&lt;br/&gt;It's specifically and intentionally not an object class. You cannot subclass it. You cannot provide methods. You cannot apply roles or mixins or metaclasses or traits or antlers or whatever else is in fashion this week.&lt;br/&gt;&lt;br/&gt;On the other hand, it is tiny, single-file, creates cheap lightweight array-backed structures, uses nothing outside of core. And I defy anyone to even measure its startup overhead with a repeatable benchmark.&lt;br/&gt;&lt;br/&gt;It's intended simply to be a slightly nicer way to store internal data structures, where otherwise you might be tempted to abuse a hash, complete with the risk of typoing key names.&lt;br/&gt;&lt;br/&gt;Would anyone use this, if it were available?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-8586916542511312433?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/8586916542511312433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/11/perl-tiny-lightweight-structures-module.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/8586916542511312433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/8586916542511312433'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/11/perl-tiny-lightweight-structures-module.html' title='Perl - Tiny lightweight structures module'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-849110630673966681</id><published>2011-10-26T14:51:00.000+01:00</published><updated>2011-10-26T14:51:07.549+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Socket'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='IPv6'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - Dual-life Socket</title><content type='html'>I've been working on how to dual-life the &lt;a href="http://search.cpan.org/~flora/perl-5.14.2/ext/Socket/Socket.pm"&gt;&lt;tt&gt;Socket&lt;/tt&gt;&lt;/a&gt; module, so it can go on CPAN and give older Perl versions the benefits of recent additions; namely &lt;tt&gt;getaddrinfo(3)&lt;/tt&gt;/&lt;tt&gt;getnameinfo(3)&lt;/tt&gt; wrappings and other IPv6 support.&lt;br /&gt;&lt;br /&gt;I have what's currently marked as an unauthorized release now on CPAN, though I'm hoping to get co-maint on it to release officially. In the meantime, it'd be useful to get some smoketest reports on what works and what doesn't. I've tested on Linux at perl 5.10.1, 5.12.4 and 5.14.1. Other OSes, especially MSWin32, would be most appreciated.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://search.cpan.org/~pevans/Socket-1.94_03/"&gt;http://search.cpan.org/~pevans/Socket-1.94_03/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-849110630673966681?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/849110630673966681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/10/perl-dual-life-socket.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/849110630673966681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/849110630673966681'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/10/perl-dual-life-socket.html' title='Perl - Dual-life Socket'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-1444956491196326420</id><published>2011-09-30T15:18:00.011+01:00</published><updated>2011-09-30T18:12:28.256+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tickit'/><category scheme='http://www.blogger.com/atom/ns#' term='libvterm'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='terminals'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>libvterm/pangoterm and Tickit</title><content type='html'>Lately I've written a bit about my terminal emulator library, &lt;a href="https://launchpad.net/libvterm"&gt;&lt;tt&gt;libvterm&lt;/tt&gt;&lt;/a&gt;, and briefly mentioned &lt;a href="http://search.cpan.org/dist/Tickit/"&gt;&lt;tt&gt;Tickit&lt;/tt&gt;&lt;/a&gt;, my terminal UI module for Perl. I'll write about each in more detail soon, but I thought since I hit an important milestone recently, I'd write a little something more about &lt;tt&gt;libvterm&lt;/tt&gt; and &lt;tt&gt;pangoterm&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;libvterm&lt;/tt&gt; is a purely abstract C99 library that implements the bulk of the logic of being a terminal emulator. Bytes from the PTY master are fed into it by the containing program, and it maintains the abstract state of the terminal; the position of the cursor, the state of the pen, what charcters are where with what attributes, and so on. It calls callback functions registered by the containing program, to inform it of damaged screen regions that need repainting. Two of the main selling points of the library are&lt;ul&gt;&lt;li&gt;It is purely abstract C99, doesn't rely on POSIX or any particular rendering/UI system&lt;/li&gt;&lt;br /&gt;&lt;li&gt;During normal operation of just feeding it bytes and processing events, it does not use the &lt;tt&gt;malloc&lt;/tt&gt; system.&lt;/li&gt;&lt;/ul&gt;These properties make it ideal for a number of situations, ranging from desktop applications, to small embedded systems or operating system kernels.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;pangoterm&lt;/tt&gt; is a GTK/Pango-driven embedding of this libary, in a simple single-&lt;tt&gt;.c&lt;/tt&gt;-file application, mostly for me to develop and test it. It is currently maintained in the &lt;tt&gt;libvterm&lt;/tt&gt; source tree.&lt;br /&gt;&lt;br /&gt;For a while now this combination has been complete enough to drive &lt;tt&gt;vim&lt;/tt&gt; sufficient to edit its own source code - &lt;tt&gt;pangoterm&lt;/tt&gt; and &lt;tt&gt;libvterm&lt;/tt&gt; are now self-hosting. A couple of weeks ago I finally managed to fix the last of a number of small issues making it not quite perfect. Last week I also managed to get &lt;tt&gt;pangoterm&lt;/tt&gt; to completely correctly render a &lt;tt&gt;Tickit&lt;/tt&gt;-based program; the final missing piece being some of the mouse tracking modes.&lt;br /&gt;&lt;br /&gt;I now have a bit of extra configuration in my &lt;tt&gt;.vimrc&lt;/tt&gt; to take advantage of a few of &lt;tt&gt;pangoterm&lt;/tt&gt;'s abilities, such as support for italics.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-IC2uIyjDE9M/ToXyAVUZs3I/AAAAAAAAAEw/RzMBy7hwgLY/s1600/vterm-vim-comments.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 226px;" src="http://2.bp.blogspot.com/-IC2uIyjDE9M/ToXyAVUZs3I/AAAAAAAAAEw/RzMBy7hwgLY/s320/vterm-vim-comments.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5658194594397533042" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As well as italics, it also supports strikethrough and alternative fonts, although so far I've only managed to find one alternative font that actually looks at all decent alongside DejaVu Sans Mono. These are all shown off quite well by &lt;tt&gt;Tickit&lt;/tt&gt;'s &lt;tt&gt;demo-pen.pl&lt;/tt&gt; example script here.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-yxqiz0XK0oo/ToXyAcL9JlI/AAAAAAAAAE4/GYI77RrAShU/s1600/vterm-tickit-pen.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 226px;" src="http://2.bp.blogspot.com/-yxqiz0XK0oo/ToXyAcL9JlI/AAAAAAAAAE4/GYI77RrAShU/s320/vterm-tickit-pen.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5658194596241155666" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And finally here, a demo of the &lt;tt&gt;xterm&lt;/tt&gt;-like 256 colour handling.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-bHVdypdRWoA/ToXyArkQUvI/AAAAAAAAAFA/kkWhulhmKYA/s1600/vterm-tickit-xterm256.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 226px;" src="http://2.bp.blogspot.com/-bHVdypdRWoA/ToXyArkQUvI/AAAAAAAAAFA/kkWhulhmKYA/s320/vterm-tickit-xterm256.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5658194600369607410" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;These screenshots briefly show &lt;tt&gt;Tickit&lt;/tt&gt; working nicely with &lt;tt&gt;pangoterm&lt;/tt&gt;.  Sometime soon I shall get around to writing about &lt;tt&gt;Tickit&lt;/tt&gt; in more detail, and also explaining some of my further plans for the whole &lt;tt&gt;Tickit&lt;/tt&gt;+&lt;tt&gt;libtermkey&lt;/tt&gt; vs &lt;tt&gt;libvterm&lt;/tt&gt; combination.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-1444956491196326420?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/1444956491196326420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/09/libvtermpangoterm-and-tickit.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1444956491196326420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1444956491196326420'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/09/libvtermpangoterm-and-tickit.html' title='libvterm/pangoterm and Tickit'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-IC2uIyjDE9M/ToXyAVUZs3I/AAAAAAAAAEw/RzMBy7hwgLY/s72-c/vterm-vim-comments.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-3336858034816913653</id><published>2011-09-28T15:16:00.008+01:00</published><updated>2011-09-29T13:49:54.983+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sentinel'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - Sentinel - version 0.02</title><content type='html'>I have just uploaded the first (non-development) release of &lt;a href="http://search.cpan.org/perldoc?Sentinel"&gt;&lt;tt&gt;Sentinel&lt;/tt&gt;&lt;/a&gt;; version &lt;a href="http://search.cpan.org/~pevans/Sentinel-0.02/"&gt;0.02&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It provides a little helper function that creates lvalues, suitable for lvalue typed accessors that want to run real code on assignment (such as for type checking or coercion, or update triggers), rather than just update a scalar.&lt;pre&gt;use Sentinel;&lt;br /&gt; &lt;br /&gt;sub foo :lvalue&lt;br /&gt;{&lt;br /&gt;   my $self = shift;&lt;br /&gt;   sentinel get =&gt; sub { return $self-&gt;get_foo },&lt;br /&gt;            set =&gt; sub { $self-&gt;set_foo( $_[0] ) };&lt;br /&gt;}&lt;/pre&gt;It makes the following two lines equivalent&lt;pre&gt;my $obj = Some::Object-&gt;new;&lt;br /&gt;&lt;br /&gt;$obj-&gt;set_foo( 100 );&lt;br /&gt;$obj-&gt;foo = 100;&lt;/pre&gt;This is rare among my modules, more or less the first thing I've written mostly as a result of ranting about it on &lt;tt&gt;#perl&lt;/tt&gt;, rather than because I actually wanted it. My argument kept being that if anyone does want an lvalue accessor, it's trivially easy to write one given some function &lt;tt&gt;sentinel&lt;/tt&gt; as in this example, and that actually implementing the &lt;tt&gt;sentinel&lt;/tt&gt; function itself isn't hard; it's a small piece of obvious XS magic.&lt;br /&gt;&lt;br /&gt;So here it is.&lt;br /&gt;&lt;br /&gt;It has to cheat somewhat on versions of Perl before 5.14, because of the way lvalue context isn't properly as powerful as it now is. Long story short - there may be unit-test failures on some older versions of Perl; but I can't tell yet because the CPAN Testers web frontend is still down, so I can't see the smokers. If anyone sees any version-related failures, please do let me know.&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;Edit 2011/11/29: By the power of crowdsourced smoke testing, it appears this does work stably across many Perl versions - thanks all who've informed me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-3336858034816913653?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/3336858034816913653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/09/perl-sentinel-version-002.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/3336858034816913653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/3336858034816913653'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/09/perl-sentinel-version-002.html' title='Perl - Sentinel - version 0.02'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-6403223373497381815</id><published>2011-08-30T19:27:00.005+01:00</published><updated>2011-08-30T19:46:46.581+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tickit'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Term::TermKey'/><category scheme='http://www.blogger.com/atom/ns#' term='libtermkey'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - Term::TermKey - version 0.09</title><content type='html'>Last week saw a new version of &lt;a href="http://search.cpan.org/perldoc?Term::TermKey"&gt;&lt;tt&gt;Term::TermKey&lt;/tt&gt;&lt;/a&gt; (0.09), and also the underlying &lt;a href="http://www.leonerd.org.uk/code/libtermkey/"&gt;&lt;tt&gt;libtermkey&lt;/tt&gt;&lt;/a&gt; (0.9). This contains a fairly small new feature, giving control of the way that &lt;tt&gt;EINTR&lt;/tt&gt; is handled.&lt;br /&gt;&lt;br /&gt;Version 0.8 added graceful handling of &lt;tt&gt;EINTR&lt;/tt&gt; to restart IO operations rather than fail with an error. This had unfortunate knock-on effects for the Perl-level wrapping of it, because of the deferred nature of Perl's safe signals. On a signal (such as the not-so-unlikely &lt;tt&gt;SIGWINCH&lt;/tt&gt;) a flag would be set, but the &lt;tt&gt;termkey_waitkey(3)&lt;/tt&gt; operation would be restarted, not returning back to Perl's control until a keypress event was actually received. This upset programs that wish to respond to &lt;tt&gt;SIGWINCH&lt;/tt&gt; and redraw the terminal to the new size.&lt;br /&gt;&lt;br /&gt;Version 0.9 of &lt;tt&gt;libtermkey&lt;/tt&gt; now therefore has a new flag, &lt;tt&gt;TERMKEY_FLAG_EINTR&lt;/tt&gt; whose presence makes the blocking IO operations (&lt;tt&gt;termkey_waitkey(3)&lt;/tt&gt; and &lt;tt&gt;termkey_advisereadable(3)&lt;/tt&gt;) to return a new result code, &lt;tt&gt;TERMKEY_RES_ERROR&lt;/tt&gt; after which the caller can inspect the value of &lt;tt&gt;errno&lt;/tt&gt;, to observe an &lt;tt&gt;EINTR&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Again because of Perl's safe signal handling, the Perl wrapping of &lt;tt&gt;libtermkey&lt;/tt&gt; has to always enable this flag, so it can invoke the &lt;tt&gt;$SIG{WINCH}&lt;/tt&gt; signal handler, for example. The &lt;tt&gt;Term::TermKey&lt;/tt&gt; module therefore now always sets &lt;tt&gt;TERMKEY_FLAG_EINTR&lt;/tt&gt; on the underlying &lt;tt&gt;TermKey&lt;/tt&gt; instance, and emulates the presence or absence of this flag at the Perl level, by optionally restarting its IO operation, or itself returning &lt;tt&gt;TERMKEY_RES_ERROR&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;An unfortunate bug here in the emulation and hiding of this flag from the Perl level means that &lt;tt&gt;Term::TermKey&lt;/tt&gt; 0.09 fails to correctly read the &lt;tt&gt;TermKey&lt;/tt&gt; flags back out of the underlying object. In particular it fails to be able to check on the presence of &lt;tt&gt;TERMKEY_FLAG_UTF8&lt;/tt&gt; that &lt;tt&gt;libtermkey&lt;/tt&gt; itself may have enabled, after detecting a &lt;tt&gt;UTF-8&lt;/tt&gt; locale. This causes &lt;a href="http://search.cpan.org/perldoc?Tickit"&gt;&lt;tt&gt;Tickit&lt;/tt&gt;&lt;/a&gt;'s unit tests to break with the familiar &lt;tt&gt;"Wide character in syswrite at ..."&lt;/tt&gt; error.&lt;br /&gt;&lt;br /&gt;This bug has now been fixed in the source code repository, and will be present in the next version, 0.10. &lt;tt&gt;Tickit&lt;/tt&gt; 0.10 also has an independent fix for the same bug, by using Perl's &lt;tt&gt;${^UTF8LOCALE}&lt;/tt&gt; instead of reading the &lt;tt&gt;TermKey&lt;/tt&gt; flags back out again.&lt;br /&gt;&lt;br /&gt;Also upcoming in &lt;tt&gt;libtermkey&lt;/tt&gt; 0.10, will be some Solaris portability fixes, and a new canonicalisation flag, which turns a &lt;tt&gt;TERMKEY_SYM_DEL&lt;/tt&gt; key into &lt;tt&gt;TERMKEY_SYM_BACKSPACE&lt;/tt&gt;, for those terminals that send &lt;tt&gt;DEL&lt;/tt&gt; on Backspace.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-6403223373497381815?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/6403223373497381815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/08/perl-termtermkey-version-009.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/6403223373497381815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/6403223373497381815'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/08/perl-termtermkey-version-009.html' title='Perl - Term::TermKey - version 0.09'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-7484448906085697598</id><published>2011-08-27T14:31:00.007+01:00</published><updated>2011-08-27T14:52:11.540+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async::Loop::AnyEvent'/><category scheme='http://www.blogger.com/atom/ns#' term='AnyEvent'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>IO::Async and AnyEvent</title><content type='html'>I've recently been working on a new &lt;a href="http://search.cpan.org/dist/IO-Async/"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt; loop implementation, &lt;a href="http://search.cpan.org/dist/IO-Async-Loop-AnyEvent/"&gt;&lt;tt&gt;IO::Async::Loop::AnyEvent&lt;/tt&gt;&lt;/a&gt;. Like the &lt;tt&gt;Glib&lt;/tt&gt; and &lt;tt&gt;POE&lt;/tt&gt; loops, this one uses another event system as its underlying implementation; &lt;a href="http://search.cpan.org/dist/AnyEvent/"&gt;&lt;tt&gt;AnyEvent&lt;/tt&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;What makes this one a little different and noteworthy, is that &lt;tt&gt;AnyEvent&lt;/tt&gt; claims not to be an event system as such, but rather a compatibility layer on top of event systems. I have so far resisted writing this particular loop implementation on the grounds that, since &lt;tt&gt;AnyEvent&lt;/tt&gt; just applies a cross-compatibility layer on top of some other existing event system anyway, &lt;tt&gt;IO::Async&lt;/tt&gt; might as well use that underlying event system directly. In practice however this doesn't quite seem to work out all the time; existing code exists and is already written. Sometimes that existing code already works using &lt;tt&gt;AnyEvent&lt;/tt&gt; directly, making it harder to drop a small section of &lt;tt&gt;IO::Async&lt;/tt&gt;-based code inside it.&lt;br /&gt;&lt;br /&gt;In that situation, an individual module/function/etc.. can construct itself an &lt;tt&gt;IO::Async::Loop::AnyEvent&lt;/tt&gt;, to allow that component to use &lt;tt&gt;IO::Async&lt;/tt&gt;-based functionallity, while still interacting correctly with the rest of the &lt;tt&gt;AnyEvent&lt;/tt&gt;-based program.&lt;br /&gt;&lt;br /&gt;It is not primarily intended that this module be used as the basis of an entire program; mostly because a neater solution for mixed &lt;tt&gt;IO::Async&lt;/tt&gt;+&lt;tt&gt;AnyEvent&lt;/tt&gt; exists in the form of &lt;tt&gt;AnyEvent::Impl::IOAsync&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;There are still some minor issues to deal with currently; most notably that because each of &lt;tt&gt;IO::Async&lt;/tt&gt; and &lt;tt&gt;AnyEvent&lt;/tt&gt; could use the other as an event source, there are some circularity problems when &lt;tt&gt;AnyEvent&lt;/tt&gt; picks &lt;tt&gt;AnyEvent::Impl::IOAsync&lt;/tt&gt; to use, when &lt;tt&gt;IO::Async::Loop::AnyEvent&lt;/tt&gt; loads it.&lt;pre&gt;Deep recursion on subroutine "AnyEvent::Impl::IOAsync::io" at /home/leo/src/perl/IO-Async-Loop-AnyEvent/blib/lib/IO/Async/Loop/AnyEvent.pm line 103.&lt;/pre&gt;Hmmmmm.... A little work there still needed :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-7484448906085697598?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/7484448906085697598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/08/ioasync-and-anyevent.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/7484448906085697598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/7484448906085697598'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/08/ioasync-and-anyevent.html' title='IO::Async and AnyEvent'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-1558409377573180944</id><published>2011-07-31T16:25:00.001+01:00</published><updated>2011-07-31T16:36:24.319+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='terminfo'/><category scheme='http://www.blogger.com/atom/ns#' term='Term::Terminfo'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='unibilium'/><category scheme='http://www.blogger.com/atom/ns#' term='terminals'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - Term::Terminfo - version 0.06</title><content type='html'>I've just uploaded a new version of &lt;a href="http://search.cpan.org/perldoc?Term::Terminfo"&gt;&lt;tt&gt;Term::Terminfo&lt;/tt&gt;&lt;/a&gt;. In brief; this is a small wrapper around the &lt;tt&gt;terminfo&lt;/tt&gt; database, and can be used to enquire about properties of a given terminal. For annoying historic reasons, each of these properties is known by at least two names; its short "capname", a two or three letter code often found in the actual file on disk, and a longer "varname", the name of a variable in the &lt;tt&gt;curses&lt;/tt&gt; C library, which stores its value for the current terminal.&lt;br /&gt;&lt;br /&gt;This latest version, 0.06, adds a whole duplicate set of methods - varname accessors. Prior to 0.06, the properties were only accessible using their short capnames.&lt;br /&gt;&lt;br /&gt;It's probably best to use the longer varnames anyway. They are more self-documenting, and a little more future-proof against the admittedly-remote possibility of new variables being added in the future.&lt;br /&gt;&lt;br /&gt;I'm also planning to support &lt;a href="https://github.com/mauke/unibilium"&gt;&lt;tt&gt;unibilium&lt;/tt&gt;&lt;/a&gt; in a later version. This is a standalone &lt;tt&gt;terminfo&lt;/tt&gt;-parsing library, which is useful for reading &lt;tt&gt;terminfo&lt;/tt&gt; data without linking against the full &lt;tt&gt;curses&lt;/tt&gt; library. This is especially useful when trying to build a replacement for &lt;tt&gt;curses&lt;/tt&gt;...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-1558409377573180944?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/1558409377573180944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/07/perl-termterminfo-version-006.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1558409377573180944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1558409377573180944'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/07/perl-termterminfo-version-006.html' title='Perl - Term::Terminfo - version 0.06'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-8568449790649030446</id><published>2011-07-15T13:47:00.004+01:00</published><updated>2011-07-15T13:55:00.283+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tickit'/><category scheme='http://www.blogger.com/atom/ns#' term='Text::CharWidth'/><category scheme='http://www.blogger.com/atom/ns#' term='XS'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>XS beats Pure Perl</title><content type='html'>Someone reported some test failures trying to install &lt;a href="http://search.cpan.org/dist/Tickit/"&gt;&lt;tt&gt;Tickit&lt;/tt&gt;&lt;/a&gt;, which seemed to be related to shortcomings in &lt;a href="http://search.cpan.org/perldoc?Text::CharWidth"&gt;&lt;tt&gt;Text::CharWidth&lt;/tt&gt;&lt;/a&gt;. The latter seems to have very poor unit test coverage on itself, so the failures didn't appear during its installation, only when &lt;a href="http://search.cpan.org/perldoc?Tickit::Utils"&gt;&lt;tt&gt;Tickit::Utils&lt;/tt&gt;&lt;/a&gt; was tested against it. On initial inspection I wondered if &lt;tt&gt;Text::CharWidth&lt;/tt&gt; simply wasn't using &lt;tt&gt;wcswidth(3)&lt;/tt&gt; correctly, and whether I should get around to my plan of rewriting bits of &lt;tt&gt;Tickit::Utils&lt;/tt&gt; in XS instead for performance, as well as work around this bug.&lt;br /&gt;&lt;br /&gt;This turned out to be quite a good idea. Implementing &lt;tt&gt;cols2chars()&lt;/tt&gt; and &lt;tt&gt;chars2cols()&lt;/tt&gt; in XS instead of Perl makes them at least 10 times faster. I tested it on four strings; two ASCII and two Unicode; a long and a short of each:&lt;br /&gt;&lt;br /&gt;&lt;table border=0 cellpadding=0 cellspacing=8&gt;&lt;tr&gt;&lt;td&gt;Calls/sec&lt;td&gt;&lt;td&gt;PP&lt;td&gt;XS&lt;td&gt;Ratio&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;chars2cols&lt;td&gt;along&lt;td&gt;48685&lt;td&gt;406504&lt;td&gt;834.97%&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;chars2cols&lt;td&gt;ashort&lt;td&gt;72674&lt;td&gt;704225&lt;td&gt;969.02%&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;chars2cols&lt;td&gt;ulong&lt;td&gt;37341&lt;td&gt;387596&lt;td&gt;1037.99%&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;chars2cols&lt;td&gt;ushort&lt;td&gt;52966&lt;td&gt;714285&lt;td&gt;1348.57%&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;cols2chars&lt;td&gt;along&lt;td&gt;16350&lt;td&gt;403255&lt;td&gt;2466.39%&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;cols2chars&lt;td&gt;ashort&lt;td&gt;58685&lt;td&gt;649350&lt;td&gt;1106.50%&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;cols2chars&lt;td&gt;ulong&lt;td&gt;13561&lt;td&gt;362318&lt;td&gt;2671.76%&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;cols2chars&lt;td&gt;ushort&lt;td&gt;50556&lt;td&gt;632911&lt;td&gt;1251.90%&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;In fact, some cases it turns out to be 24 times faster.&lt;br /&gt;&lt;br /&gt;I haven't looked into too much detail on why, but I suspect a large amount of the reason is to do with the way the XS functions primarily walk along the internal UTF-8 representation of the strings, counting bytes, characters, and columns as they go, and returning the appropriate count(s) when the required. The pureperl implementation doesn't have direct access to the byte offsets, so only has character numbers to work to. The frequent character-to-byte or byte-to-character conversions at all the boundaries between the functions result in multiple UTF-8 byte skip counting steps along the string each time a function is entered or left, generally slowing it down.&lt;br /&gt;&lt;br /&gt;As to the original test failure, it turned out to be entirely unrelated lack of locale support in the platform's libc. The XS implementations fail there in the same way. But having implemented the above improvements, I decided to leave them in anyway.&lt;br /&gt;&lt;br /&gt;XS faster than Pure Perl; who'd have thought it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-8568449790649030446?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/8568449790649030446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/07/xs-beats-pure-perl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/8568449790649030446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/8568449790649030446'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/07/xs-beats-pure-perl.html' title='XS beats Pure Perl'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-8829871518747608511</id><published>2011-06-20T00:07:00.000+01:00</published><updated>2011-06-20T00:07:15.793+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Socket'/><category scheme='http://www.blogger.com/atom/ns#' term='Socket::GetAddrInfo'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async::SSL'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='IPv6'/><category scheme='http://www.blogger.com/atom/ns#' term='Test::Fatal'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>Perl - IO::Async - version 0.41</title><content type='html'>Wow; seems I haven't been writing these posts as much as I should be. I last wrote about version 0.34, and just now I've uploaded &lt;a href="http://search.cpan.org/%7Epevans/IO-Async-0.41/"&gt;version 0.41&lt;/a&gt; to CPAN. Quite a bit changed between then and now, here's a rundown of the most important bits:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Added &lt;a href="http://search.cpan.org/perldoc?IO::Async::FileStream"&gt;&lt;tt&gt;IO::Async::FileStream&lt;/tt&gt;&lt;/a&gt;. This behaves like a read-only &lt;a href="http://search.cpan.org/perldoc?IO::Async::Stream"&gt;&lt;tt&gt;IO::Async::Stream&lt;/tt&gt;&lt;/a&gt;, but reads its data from a regular file on the filesystem. Like &lt;tt&gt;tail -f&lt;/tt&gt;, or &lt;a href="http://search.cpan.org/perldoc?File::Tail"&gt;&lt;tt&gt;File::Tail&lt;/tt&gt;&lt;/a&gt;, it watches the file for changes in size, and follows appended data.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Added &lt;a href="http://search.cpan.org/perldoc?IO::Async::Function"&gt;&lt;tt&gt;IO::Async::Function&lt;/tt&gt;&lt;/a&gt;. This is a true &lt;a href="http://search.cpan.org/perldoc?IO::Async::Notifier"&gt;&lt;tt&gt;IO::Async::Notifier&lt;/tt&gt;&lt;/a&gt; subclass to represent an asynchronous block of code; which was previously handled by &lt;tt&gt;DetachedCode&lt;/tt&gt;. Being a true &lt;tt&gt;Notifier&lt;/tt&gt; subclass gives it many advantages, and should provide a better base to build other things on. &lt;a href="http://search.cpan.org/perldoc?IO::Async::Resolver"&gt;&lt;tt&gt;IO::Async::Resolver&lt;/tt&gt;&lt;/a&gt; is now a subclass of &lt;tt&gt;Function&lt;/tt&gt;, not &lt;tt&gt;DetachedCode&lt;/tt&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Added &lt;a href="http://search.cpan.org/perldoc?IO::Async::Process"&gt;&lt;tt&gt;IO::Async::Process&lt;/tt&gt;&lt;/a&gt;. This is another &lt;tt&gt;IO::Async::Notifier&lt;/tt&gt; subclass, this time to represent an external process.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Support &lt;tt&gt;encoding&lt;/tt&gt; parameter in &lt;tt&gt;IO::Async::Stream&lt;/tt&gt;. This allows the &lt;tt&gt;Stream&lt;/tt&gt; to handle text in some encoding, rather than simply raw bytes.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Support &lt;tt&gt;first_interval&lt;/tt&gt; parameter to &lt;a href="http://search.cpan.org/perldoc?IO::Async::Timer::Periodic"&gt;&lt;tt&gt;IO::Async::Timer::Periodic&lt;/tt&gt;&lt;/a&gt;. If supplied, this will be the first wait time when the timer is started. In particular, if it is zero the timer's first invocation will happen immediately.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Allow &lt;tt&gt;Loop-&amp;gt;listen&lt;/tt&gt; to be extended via extensions, similar to &lt;tt&gt;-&amp;gt;connect&lt;/tt&gt;. Such extensions as &lt;a href="http://search.cpan.org/perldoc?IO::Async::SSL"&gt;&lt;tt&gt;IO::Async::SSL&lt;/tt&gt;&lt;/a&gt; are already set up to make use of this.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Distribution now uses &lt;a href="http://search.cpan.org/perldoc?Test::Fatal"&gt;&lt;tt&gt;Test::Fatal&lt;/tt&gt;&lt;/a&gt; rather than &lt;tt&gt;Test::Exception&lt;/tt&gt;. The former is smaller and simpler, whereas the latter relies on clever tricks to hack on &lt;tt&gt;caller()&lt;/tt&gt;, which sometimes breaks some setups.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Added convenient method in &lt;tt&gt;IO::Async::Loop&lt;/tt&gt; for handling socket addresses; &lt;tt&gt;extract_addrinfo&lt;/tt&gt;. This recognises strings for common networking constants; &lt;tt&gt;'inet'&lt;/tt&gt;, &lt;tt&gt;'inet6'&lt;/tt&gt; and &lt;tt&gt;'unix'&lt;/tt&gt; as socket families, &lt;tt&gt;'stream'&lt;/tt&gt;, &lt;tt&gt;'dgram'&lt;/tt&gt; and &lt;tt&gt;'raw'&lt;/tt&gt; as socket types. These convenient forms are also recognised by the &lt;tt&gt;-&amp;gt;connect&lt;/tt&gt; and &lt;tt&gt;-&amp;gt;listen&lt;/tt&gt; methods.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Now prefers to use the IPv6 support functions found in Perl 5.14's &lt;a href="http://search.cpan.org/perldoc?Socket"&gt;&lt;tt&gt;Socket&lt;/tt&gt;&lt;/a&gt; module; only falling back to using &lt;a href="http://search.cpan.org/perldoc?Socket::GetAddrInfo"&gt;&lt;tt&gt;Socket::GetAddrInfo&lt;/tt&gt;&lt;/a&gt; in earlier perls.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-8829871518747608511?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/8829871518747608511/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/06/perl-ioasync-version-041.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/8829871518747608511'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/8829871518747608511'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/06/perl-ioasync-version-041.html' title='Perl - IO::Async - version 0.41'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-4594243524120153566</id><published>2011-06-10T11:53:00.004+01:00</published><updated>2011-06-10T12:16:32.223+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='CPS'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>Sleep Sorting with IO::Async and CPS</title><content type='html'>There's a bit of a silly meme going around lately; an implementation of a sorting algorithm that works by many parallel sleeps. So I thought I'd have a go at it from an &lt;a href="http://search.cpan.org/perldoc?IO::Async"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt; perspective.&lt;pre&gt;use CPS qw( kpareach );&lt;br /&gt;use IO::Async::Loop;&lt;br /&gt;&lt;br /&gt;my $loop = IO::Async::Loop-&gt;new;&lt;br /&gt;&lt;br /&gt;kpareach( \@ARGV,&lt;br /&gt;   sub {&lt;br /&gt;      my ( $val, $k ) = @_;&lt;br /&gt;      $loop-&gt;enqueue_timer(&lt;br /&gt;         delay =&gt; $val,&lt;br /&gt;         code  =&gt; sub { print "$val\n"; goto $k },&lt;br /&gt;      );&lt;br /&gt;   },&lt;br /&gt;   sub { $loop-&gt;loop_stop },&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;$loop-&gt;loop_forever;&lt;/pre&gt;This produces such output as:&lt;pre&gt;$ perl sleepsort.pl 3 8 4 2 6 5 7 1&lt;br /&gt;1&lt;br /&gt;2&lt;br /&gt;3&lt;br /&gt;4&lt;br /&gt;5&lt;br /&gt;6&lt;br /&gt;7&lt;br /&gt;8&lt;/pre&gt;It's a little more verbose than I'd like it though. I have been pondering creating a &lt;tt&gt;CPS::Async&lt;/tt&gt; module, which would provide some more simple &lt;a href="http://search.cpan.org/perldoc?CPS"&gt;&lt;tt&gt;CPS&lt;/tt&gt;&lt;/a&gt;-like versions of the usual blocking primatives we're used to, like &lt;tt&gt;sleep&lt;/tt&gt; and &lt;tt&gt;sysread&lt;/tt&gt;. Using this new hypothetical module would lead to something looking like:&lt;pre&gt;use CPS qw( kpareach );&lt;br /&gt;use CPS::Async qw( ksleep );&lt;br /&gt;&lt;br /&gt;kpareach( \@ARGV,&lt;br /&gt;   sub {&lt;br /&gt;      my ( $val, $k ) = @_;&lt;br /&gt;      ksleep( $val, sub {&lt;br /&gt;         print "$val\n";&lt;br /&gt;         goto $k;&lt;br /&gt;      } );&lt;br /&gt;   },&lt;br /&gt;   sub { CPS::Async::stop },&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;CPS::Async::run;&lt;/pre&gt;This would be a small wrapper around &lt;tt&gt;IO::Async&lt;/tt&gt;, providing &lt;tt&gt;CPS&lt;/tt&gt;-style functions that turn into method calls on some implied &lt;tt&gt;IO::Async::Loop&lt;/tt&gt; object; similar to for example, the &lt;tt&gt;AnyEvent::Impl::IOAsync&lt;/tt&gt;, which exposes an AnyEvent API using &lt;tt&gt;IO::Async&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;I have plenty of other projects to keep me amused currently, but I'll sit it on the back burner in case something interesting happens that way...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-4594243524120153566?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/4594243524120153566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/06/sleep-sorting-with-ioasync-and-cps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4594243524120153566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4594243524120153566'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/06/sleep-sorting-with-ioasync-and-cps.html' title='Sleep Sorting with IO::Async and CPS'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-903186365960133039</id><published>2011-05-24T22:04:00.000+01:00</published><updated>2011-05-24T22:04:40.052+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Term::TermKey'/><category scheme='http://www.blogger.com/atom/ns#' term='libtermkey'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>libtermkey - read keypresses from terminals</title><content type='html'>I have just released version 0.8 of &lt;a href="http://www.leonerd.org.uk/code/libtermkey/"&gt;&lt;tt&gt;libtermkey&lt;/tt&gt;&lt;/a&gt;. It contains a small set of bugfixes on the previous version (0.7), relating to handling the signal-raising keys (&lt;tt&gt;Ctrl-C&lt;/tt&gt;, &lt;tt&gt;Ctrl-\&lt;/tt&gt;, &lt;tt&gt;Ctrl-Z&lt;/tt&gt;), gracefully handles &lt;tt&gt;EINTR&lt;/tt&gt; from &lt;tt&gt;read(2)&lt;/tt&gt; calls, and actually gets around to implementing the &lt;tt&gt;CSI u&lt;/tt&gt; modified Unicode encoding scheme &lt;a href="http://www.leonerd.org.uk/hacks/fixterms/"&gt;I documented&lt;/a&gt; a long time ago.&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;libtermkey&lt;/tt&gt; is a library for reading keypress events (and in fact mouse events too) from a terminal, in a terminal-based application. I won't list all its points and features, but as a brief overview:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It presents events to the application in a structure, containing basic key information and a bitfield of modifiers in effect, rather than a single flat enumeration integer, as &lt;tt&gt;curses&lt;/tt&gt; tries to do. In this way, it can easily represent the various modifier-combinations on cursor keys, like arrows or &lt;tt&gt;PageUp&lt;/tt&gt;/&lt;tt&gt;PageDown&lt;/tt&gt;, and can easily represent any Unicode character vs. any special key.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It supplies a pair of functions (&lt;tt&gt;termkey_strfkey&lt;/tt&gt; and &lt;tt&gt;termkey_strpkey&lt;/tt&gt;) for converting between these structural notations and plain-text human-readable strings, such as &lt;tt&gt;"Ctrl-PageUp"&lt;/tt&gt;. These assist with easy reporting of keypresses in applications, or for config file parsing.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Perl bindings exist, primarily in the form of &lt;a href="http://search.cpan.org/dist/Term-TermKey/"&gt;&lt;tt&gt;Term::TermKey&lt;/tt&gt;&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-903186365960133039?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/903186365960133039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/05/libtermkey-read-keypresses-from.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/903186365960133039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/903186365960133039'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/05/libtermkey-read-keypresses-from.html' title='libtermkey - read keypresses from terminals'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-5650515982447549025</id><published>2011-05-19T17:15:00.000+01:00</published><updated>2011-05-19T17:16:05.529+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Term::TermKey'/><category scheme='http://www.blogger.com/atom/ns#' term='libtermkey'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='Term::TermKey::Async'/><category scheme='http://www.blogger.com/atom/ns#' term='POE::Wheel::TermKey'/><category scheme='http://www.blogger.com/atom/ns#' term='AnyEvent::TermKey'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Wearing Two Hats</title><content type='html'>A while ago, I wrote &lt;a href="http://www.leonerd.org.uk/code/libtermkey/"&gt;&lt;tt&gt;libtermkey&lt;/tt&gt;&lt;/a&gt;, a C library for reading keypress events from a terminal. I wrote a Perl binding for it, &lt;a href="http://search.cpan.org/perldoc?Term::TermKey"&gt;&lt;tt&gt;Term::TermKey&lt;/tt&gt;&lt;/a&gt;. On a separate note, I also maintain &lt;a href="http://search.cpan.org/perldoc?IO::Async"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt;, an event framework for Perl. Naturally, the combination of these two lead me to write an &lt;tt&gt;IO::Async&lt;/tt&gt; module to handle &lt;tt&gt;libtermkey&lt;/tt&gt;, &lt;a href="http://search.cpan.org/perldoc?Term::TermKey::Async"&gt;&lt;tt&gt;Term::TermKey::Async&lt;/tt&gt;&lt;/a&gt;. These all work together quite well.&lt;br /&gt;&lt;br /&gt;However, these two things are separate considerations. There's nothing specific to Perl, in &lt;tt&gt;libtermkey&lt;/tt&gt;, nor anything specific to &lt;tt&gt;IO::Async&lt;/tt&gt; in &lt;tt&gt;Term::TermKey&lt;/tt&gt;. After some thought, and discussions on &lt;tt&gt;#perl&lt;/tt&gt;, I decided in the end, that I had to realise these were two separate concerns, two different problem domains, that neither should be allowed to influence the other. In short, I had to wear two hats.&lt;br /&gt;&lt;br /&gt;With my &lt;tt&gt;libtermkey&lt;/tt&gt; hat on, I went to join &lt;tt&gt;#poe&lt;/tt&gt; and &lt;tt&gt;#anyevent&lt;/tt&gt; on &lt;tt&gt;irc.perl.org&lt;/tt&gt;, and talked my way around designing two new modules, which are now happily sitting on CPAN as well: &lt;a href="http://search.cpan.org/perldoc?POE::Wheel::TermKey"&gt;&lt;tt&gt;POE::Wheel::TermKey&lt;/tt&gt;&lt;/a&gt; and &lt;a href="http://search.cpan.org/perldoc?AnyEvent::TermKey"&gt;&lt;tt&gt;AnyEvent::TermKey&lt;/tt&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;With so many CPAN modules effectively being glue between two others (such as in the case of &lt;tt&gt;Term::TermKey::Async&lt;/tt&gt; being the glue between &lt;tt&gt;Term::TermKey&lt;/tt&gt; and &lt;tt&gt;IO::Async&lt;/tt&gt;), it's often the case that at least one if not both sides of the module are written by the same author. It is important to recognise these cases, and to consider whether the community as a whole would be better served by taking a look around to see if other modules and other use cases need attention as well.&lt;br /&gt;&lt;br /&gt;When wearing hats, it is important to remember which hat you are wearing, and only try to wear one hat at once.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-5650515982447549025?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/5650515982447549025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/05/wearing-two-hats.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5650515982447549025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5650515982447549025'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/05/wearing-two-hats.html' title='Wearing Two Hats'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-3076220363867435412</id><published>2011-04-26T21:21:00.000+01:00</published><updated>2011-04-26T21:21:58.105+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='module naming'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Deterministic Random Testing</title><content type='html'>I've just written an implementation of a weighted random shuffle. Because the function is random, it won't return the same results every time. This makes it hard to unit-test; I can't just run it on some given input and assert it returns some given output. Indeed, by its nature, any ordering of the results is potentially valid. One way to solve this is to run it a large number of times, counting the frequency of various output results, and asserting that roughly the right proportion of results are returned. Of course, exactly how close "roughly right" is, is hard to determine.&lt;br /&gt;&lt;br /&gt;This isn't a very satisfactory testing method, however. Get the tolerance too tight, and spurious random differences cause tests to fail unnecessarily. Too loose, and you might miss a subtle logic bug that skews the probabilities of some case.&lt;br /&gt;&lt;br /&gt;The weighted random shuffle algorithm calls &lt;tt&gt;int rand $limit&lt;/tt&gt; a number of times, each time passing in a small integer. This effectively uses the RNG like a dice roll, randomly selecting some integer &lt;tt&gt;0 .. $limit - 1&lt;/tt&gt;. Because each call takes a small integer, and because the algorithm is entirely deterministic for any given set of random results, this suggests a better testing method. If we could instead enumerate all possible returns of random numbers, each one exactly once, we can generate all possible results from the shuffle algorithm in their ideal proportions. Because this will be an exact deterministic count, free from randomness, we can assert exact values for the results.&lt;br /&gt;&lt;br /&gt;So this is what I did. I've created a module, for now simply called &lt;tt&gt;Unrandom&lt;/tt&gt;, which exports one function, &lt;tt&gt;unrandomly&lt;/tt&gt;. It is used like the following:&lt;pre&gt;use Unrandom 'unrandomly';&lt;br /&gt;&lt;br /&gt;unrandomly {&lt;br /&gt;  my $da = 1 + int rand 6;&lt;br /&gt;  my $db = 1 + int rand 6;&lt;br /&gt;  say "Roll 2d6: $da + $db = " . ($da+$db);&lt;br /&gt;};&lt;/pre&gt;The &lt;tt&gt;unrandomly&lt;/tt&gt; function has the effect of replacing the &lt;tt&gt;rand&lt;/tt&gt; function with one under its control while it runs the block of code. It runs the block of code a number of times, enumerating the entire tree of possible return values, in a given deterministic order:&lt;pre&gt;Roll 2d6: 1 + 1 = 2&lt;br /&gt;Roll 2d6: 1 + 2 = 3&lt;br /&gt;Roll 2d6: 1 + 3 = 4&lt;br /&gt;Roll 2d6: 1 + 4 = 5&lt;br /&gt;Roll 2d6: 1 + 5 = 6&lt;br /&gt;Roll 2d6: 1 + 6 = 7&lt;br /&gt;Roll 2d6: 2 + 1 = 3&lt;br /&gt;Roll 2d6: 2 + 2 = 4&lt;br /&gt;...&lt;br /&gt;Roll 2d6: 6 + 5 = 11&lt;br /&gt;Roll 2d6: 6 + 6 = 12&lt;/pre&gt;Because each possible combination is returned exactly once, we can unit test that this dice-rolling algorithm does in fact give us the right distribution of results; there will be exactly one 2, two 3s, etc... We don't have to run it a few million times, and check that we got "roughly" the right number; we can be exact.&lt;br /&gt;&lt;br /&gt;While I'm using this code in a unit-test, there's nothing directly test-related in the code. It could be useful anywhere that statistical modelling is used, or other problems involving random integer generation.&lt;br /&gt;&lt;br /&gt;I'm now just looking for a good name to call it, so I can extract it from the unit tests and give it a life of its own on CPAN.&lt;br /&gt;&lt;br /&gt;Suggestions anyone?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-3076220363867435412?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/3076220363867435412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/04/deterministic-random-testing.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/3076220363867435412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/3076220363867435412'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/04/deterministic-random-testing.html' title='Deterministic Random Testing'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-2163114898418013282</id><published>2011-04-09T12:30:00.006+01:00</published><updated>2011-04-09T12:53:08.862+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='ECMA-48'/><category scheme='http://www.blogger.com/atom/ns#' term='terminals'/><title type='text'>Extended colour support, terminals, and ECMA-48</title><content type='html'>&lt;i&gt;tl;dr summary&lt;/i&gt;: Terminal authors - please accept &lt;code&gt;CSI 38:5:123 m&lt;/code&gt; as well as anything else, to set extended colours. NOTE THE COLON.&lt;br /&gt;&lt;br /&gt;Many terminals these days are starting to support extended colour modes; specifically things like 256 colours. They're all doing it wrong.&lt;pre&gt;CSI 38;5;123 m&lt;/pre&gt;No no no no no.&lt;br /&gt;&lt;br /&gt;That is &lt;b&gt;NOT&lt;/b&gt; what you think. It does not select colour 123 from palette 5. CSI arguments are separated by semicolons. This sets three unrelated SGRs; 38, 5, and 123. 38 sets a foreground colour to .. er.. nothing in particular. 5 is blinking mode, 123 has no defined meaning to my knowledge. All the other following are exactly identical:&lt;pre&gt;CSI 5;38;123 m&lt;br /&gt;CSI 38 m CSI 5 m CSI 123 m&lt;/pre&gt;&lt;a href="http://www.ecma-international.org/publications/standards/Ecma-048.htm"&gt;ECMA-48&lt;/a&gt; already defines a perfectly good way for parameters to take sub-parameters. It's the colon. The &lt;i&gt;correct&lt;/i&gt; way to encode this concept is&lt;br /&gt;&lt;pre&gt;CSI 38:5:123 m&lt;/pre&gt;Why does this matter? It matters for parsers not to have to &lt;i&gt;understand&lt;/i&gt; what is going on. Consider&lt;pre&gt;CSI 3;38:9:5:4:3:2:1;11;1&lt;/pre&gt;This is equivalent to&lt;pre&gt;CSI 3 CSI 38:9:5:4:3:2:1 CSI 11; CSI 1&lt;/pre&gt;I.e. I have no idea what palette 9 is, but I can definitely parse out the contents of this SGR from the others, knowing exactly where it ends. I don't have to "just know" that palette 9 happens to take 5 parameters. The CSI encodes this.&lt;br /&gt;&lt;br /&gt;My own terminal emulator library, &lt;a href="https://launchpad.net/libvterm"&gt;libvterm&lt;/a&gt;, already understands these colon-based arguments. It parses them correctly. This is important for other palettes that don't take just one value. For example, the RGB, RGBA, CMY, and CMYK palettes. It's vital to be able to parse out these sub-arguments from the single SGR 38 or 48.&lt;br /&gt;&lt;br /&gt;Standards exist for a reason, people. Please use them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-2163114898418013282?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/2163114898418013282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/04/extended-colour-support-terminals-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/2163114898418013282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/2163114898418013282'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/04/extended-colour-support-terminals-and.html' title='Extended colour support, terminals, and ECMA-48'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-6045641467230871702</id><published>2011-03-29T23:54:00.001+01:00</published><updated>2011-03-30T00:10:56.720+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Encode'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='Parser::MGC'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>When failure isn't failure</title><content type='html'>Lately I have been looking at two different problems, with a common theme.&lt;br /&gt;&lt;br /&gt;My first problem concerns &lt;a href="http://search.cpan.org/perldoc?Parser::MGC"&gt;&lt;tt&gt;Parser::MGC&lt;/tt&gt;&lt;/a&gt;, and its ability to read input lazily as needed, rather than needing to slurp an entire file all at once. This ability is provided by the &lt;tt&gt;from_reader&lt;/tt&gt; method, which takes a &lt;tt&gt;CODE&lt;/tt&gt; reference to a reader function.&lt;br /&gt;&lt;br /&gt;As the documentation points out, this is only supported for reading input that's broken across skippable whitespace. This is because it's implemented by calling the reader function to look for more input if the current input buffer is completely exhausted. It cannot work in general, for splitting the input stream arbitrarily, because Perl's regular expression engine does not give sufficient feedback. It is not possible to ask, after a match attempt, whether the engine reached the end of the stream, For example, when looking for a match for &lt;tt&gt;m/food/&lt;/tt&gt;, an input of &lt;tt&gt;"fool"&lt;/tt&gt; definitely fails, whereas an input of &lt;tt&gt;"foo"&lt;/tt&gt; is not yet a failure, because it might be that reading more input from the stream can complete the match. If the regular expression engine gave such feedback, then the reader function could be invoked again to provide more input that may help to resolve the parse.&lt;br /&gt;&lt;br /&gt;My second problem concerns how to handle UTF-8 encoded data in nonblocking reads. An &lt;a href="http://search.cpan.org/perldoc?IO::Async::Stream"&gt;&lt;tt&gt;IO::Async::Stream&lt;/tt&gt;&lt;/a&gt; object wraps a bytestream, such as a TCP socket or pipe. If the underlying stream contains UTF-8 encoded Unicode text, then the Unicode characters need to be decoded from these bytes, by using the &lt;tt&gt;Encode&lt;/tt&gt; module.&lt;br /&gt;&lt;br /&gt;The trouble here is that &lt;a href="http://search.cpan.org/perldoc?Encode"&gt;&lt;tt&gt;Encode&lt;/tt&gt;&lt;/a&gt; does not provide a way to do this sanely. It is quite likely that a multibyte UTF-8 sequence gets split across multiple read calls. To cope with such a case, &lt;tt&gt;Encode&lt;/tt&gt; has a mode where it will stop on the first error it encounters (called &lt;tt&gt;FB_QUIET&lt;/tt&gt;), returning the prefix it has decoded so far, and deleting the bytes so consumed from the input. The intention here is that another call supplies more bytes, and it continues from there. Problem is, it returns on any failure, whether that's running out of input bytes or encountering an invalid byte. Without the ability to distinguish these two different conditions, it is impossible to handle nonblocking or stream-based UTF-8 decoding while still having sensible error handling.&lt;br /&gt;&lt;br /&gt;The common theme of these two problems is that neither considers the nature of a failure, treating various reasons the same. Both cases have two kinds of failure: one a failure because something has been received that is not correct; the other a failure because something that would be correct has simply not yet been received.&lt;br /&gt;&lt;br /&gt;Sometimes, failure is not really failure at all. Sometimes it is simply deferred success that is yet to happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-6045641467230871702?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/6045641467230871702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/03/when-failure-isnt-failure.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/6045641467230871702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/6045641467230871702'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/03/when-failure-isnt-failure.html' title='When failure isn&apos;t failure'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-4992766134940123783</id><published>2011-03-04T16:12:00.000Z</published><updated>2011-03-04T16:12:18.308Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='module naming'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='CPS'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='Carp'/><title type='text'>Carp from somewhere else</title><content type='html'>&lt;tt&gt;Carp&lt;/tt&gt; provides two main functions, &lt;tt&gt;carp&lt;/tt&gt; and &lt;tt&gt;croak&lt;/tt&gt;, as replacements for core Perl's &lt;tt&gt;warn&lt;/tt&gt; and &lt;tt&gt;die&lt;/tt&gt;. The functions from &lt;tt&gt;Carp&lt;/tt&gt; report the file and line number slightly differently from core Perl; walking up the callstack looking for a different package name. The idea being these are used to report errors in values passed in to the function, typically bad arguments from the caller.&lt;br /&gt;&lt;br /&gt;These functions use the dynamic callstack (as provided by &lt;tt&gt;caller()&lt;/tt&gt;) at the time the message is warned (or thrown) to create their context. One scenario where this does not lead to sensible results is when the called function is internally implemented using a closure via some other package again.&lt;br /&gt;&lt;br /&gt;Having thought about this one a bit, it seems what's required is to split collecting the callstack information, from creating the message. Collect the information in one function call, and pass it into the other.&lt;br /&gt;&lt;br /&gt;This would be useful in &lt;a href="http://search.cpan.org/perldoc?CPS"&gt;&lt;tt&gt;CPS&lt;/tt&gt;&lt;/a&gt; for example. Because the closures used in &lt;tt&gt;CPS::kseq&lt;/tt&gt; or &lt;tt&gt;kpar&lt;/tt&gt; aren't necessarily invoked during the dynamic scope of the function that lexically contains the code, a call to &lt;tt&gt;croak&lt;/tt&gt; may not be able to infer the calling context. Even if they are, the presence of stack frames in the &lt;tt&gt;CPS&lt;/tt&gt; package would confuse &lt;tt&gt;croak&lt;/tt&gt;'s scanning of the callstack. Instead, it would be better to capture the calling context using &lt;tt&gt;whence&lt;/tt&gt;, and pass it into &lt;tt&gt;whoops&lt;/tt&gt; if required for generating a message.&lt;br /&gt;&lt;br /&gt;For example, this from &lt;a href="http://search.cpan.org/perldoc?IO::Async::Connector"&gt;&lt;tt&gt;IO::Async::Connector&lt;/tt&gt;&lt;/a&gt;:&lt;pre&gt;sub connect&lt;br /&gt;{&lt;br /&gt;   my ( %params ) = @_;&lt;br /&gt;   ...&lt;br /&gt;&lt;br /&gt;   my $where = whence;&lt;br /&gt;&lt;br /&gt;   kpar(&lt;br /&gt;      sub {&lt;br /&gt;         my ( $k ) = @_;&lt;br /&gt;         if( exists $params{host} and exists $params{service} ) { &lt;br /&gt;            my $on_resolve_error = $params{on_resolve_error} or whoops $where, "Expected 'on_resolve_error' callback";&lt;br /&gt;            ...&lt;br /&gt;}&lt;/pre&gt;These functions would be a fairly simple replacement of &lt;tt&gt;carp&lt;/tt&gt; and &lt;tt&gt;croak&lt;/tt&gt;; capture the callsite information at entry to a function, and pass it to the message warning function.&lt;br /&gt;&lt;br /&gt;It does occur to me though, the code will be small and self-contained, and not specific to &lt;tt&gt;CPS&lt;/tt&gt;. I think it ought to live in its own module somewhere - any ideas on a name?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-4992766134940123783?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/4992766134940123783/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/03/carp-from-somewhere-else.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4992766134940123783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4992766134940123783'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/03/carp-from-somewhere-else.html' title='Carp from somewhere else'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-1411880635389593655</id><published>2011-01-22T14:39:00.002Z</published><updated>2011-01-22T20:23:19.911Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Socket'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Socket::IP'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='IPv6'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>IPv6 in Perl</title><content type='html'>A lot of people are talking about IPv6 lately. And perhaps with good reason - it's been years in coming, but finally we're really starting to run out of IPv4 addresses. Tools like the &lt;a href="http://www.potaroo.net/tools/ipv4/"&gt;IPv4 Address Report&lt;/a&gt; may put a certain amount of panic on things with their realtime Flash-based countdown widget, but the problem is real and does need sorting.&lt;br /&gt;&lt;br /&gt;The latest development release of Perl; &lt;a href="http://www.cpan.org/src/perl-5.13.9.tar.gz"&gt;perl-5.13.9&lt;/a&gt;, now has full support for IPv6, and the new address handling functions specified in &lt;a href="http://www.ietf.org/rfc/rfc2553.txt"&gt;RFC 2553&lt;/a&gt;. The new functions all live in &lt;a href="http://search.cpan.org/~jesse/perl-5.13.9/ext/Socket/Socket.pm"&gt;&lt;tt&gt;Socket&lt;/tt&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As well as the low-level &lt;tt&gt;AF_INET6&lt;/tt&gt; constant, and the &lt;tt&gt;pack_sockaddr_in6&lt;/tt&gt; and &lt;tt&gt;unpack_sockaddr_in6&lt;/tt&gt; structure functions (already in place in 5.13.8 in fact), there is now the full set of &lt;tt&gt;getaddrinfo&lt;/tt&gt;, &lt;tt&gt;getnameinfo&lt;/tt&gt; and associated constants. These allow fully protocol-agnostic handling of connections and addresses. There is now enough in core to support &lt;a href="http://search.cpan.org/~pevans/IO-Socket-IP-0.06/"&gt;&lt;tt&gt;IO::Socket::IP&lt;/tt&gt;&lt;/a&gt;. This is a fully protocol-agnostic replacement of &lt;tt&gt;IO::Socket::INET&lt;/tt&gt;.&lt;pre&gt;use IO::Socket::IP;&lt;br /&gt;&lt;br /&gt;my $sock = IO::Socket::IP-&gt;new(&lt;br /&gt;   PeerHost    =&gt; "www.google.com",&lt;br /&gt;   PeerService =&gt; "www",&lt;br /&gt;) or die "Cannot construct socket - $@";&lt;br /&gt;&lt;br /&gt;printf "Now connected to %s:%s\n", $sock-&gt;peerhost_service;&lt;br /&gt;&lt;br /&gt;...&lt;/pre&gt;What could be simpler?&lt;br /&gt;&lt;br /&gt;Perhaps now is the time to make a case for putting &lt;tt&gt;IO::Socket::IP&lt;/tt&gt; itself in the core distribution, such that when &lt;tt&gt;perl-5.14.0&lt;/tt&gt; comes out, it will be properly ready for the next 30 years of the Internet?&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;IO::Socket::IP&lt;/tt&gt;'s API is designed to be a drop-in replacement for the IPv4-only &lt;tt&gt;IO::Socket::INET&lt;/tt&gt;. Any program currently using &lt;tt&gt;INET&lt;/tt&gt; ought to work exactly the same, by simply substituting &lt;tt&gt;IP&lt;/tt&gt; instead, and now will also work on IPv6.&lt;br /&gt;&lt;br /&gt;If you maintain a distribution that uses &lt;tt&gt;IO::Socket::INET&lt;/tt&gt;, please try out &lt;tt&gt;IO::Socket::IP&lt;/tt&gt; instead. I'd be very keen to hear from anyone who finds it doesn't JustWork in their situation.&lt;br /&gt;&lt;br /&gt;See also my earlier post on the subject; &lt;a href="http://leonerds-code.blogspot.com/2010/10/perl-iosocketip.html"&gt;Perl - IO::Socket::IP&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-1411880635389593655?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/1411880635389593655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2011/01/ipv6-in-perl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1411880635389593655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1411880635389593655'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2011/01/ipv6-in-perl.html' title='IPv6 in Perl'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-8576312811901260743</id><published>2010-12-30T18:17:00.006Z</published><updated>2010-12-30T18:42:34.120Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>Perl - IO::Async - version 0.34</title><content type='html'>There's been four releases of &lt;a href="http://search.cpan.org/dist/IO-Async/"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt; since I last wrote about version 0.30. Here's a rough summary of the more important changes and additions between then and version 0.34:&lt;ul&gt;&lt;li&gt;New Notifier class &lt;a href="http://search.cpan.org/perldoc?IO::Async::Timer::Absolute"&gt;&lt;tt&gt;IO::Async::Timer::Absolute&lt;/tt&gt;&lt;/a&gt;, to invoke events at a fixed point in the future.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;New Notifier class &lt;a href="http://search.cpan.org/perldoc?IO::Async::PID"&gt;&lt;tt&gt;IO::Async::PID&lt;/tt&gt;&lt;/a&gt;, to watch a child process for &lt;tt&gt;exit(2)&lt;/tt&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;New Notifier class &lt;a href="http://search.cpan.org/perldoc?IO::Async::Protocol::LineStream"&gt;&lt;tt&gt;IO::Async::Protocol::LineStream&lt;/tt&gt;&lt;/a&gt;, to implement stream protocols that use lines of plain text.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;New method on &lt;a href="http://search.cpan.org/perldoc?IO::Async::Protocol"&gt;&lt;tt&gt;IO::Async::Protocol&lt;/tt&gt;&lt;/a&gt; that wraps &lt;tt&gt;connect(2)&lt;/tt&gt; functionallity, allowing for simpler network protocol client modules.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;&lt;a href="http://search.cpan.org/perldoc?IO::Async::Loop"&gt;IO::Async::Loop&lt;/a&gt;-&gt;connect&lt;/tt&gt;'s &lt;tt&gt;on_connect_error&lt;/tt&gt; and &lt;tt&gt;IO::Async::Loop-&gt;listen&lt;/tt&gt;'s &lt;tt&gt;on_listen_error&lt;/tt&gt; continuations now both receive &lt;tt&gt;errno&lt;/tt&gt; information.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;New direct name resolution methods on &lt;a href="http://search.cpan.org/perldoc?IO::Async::Resolver"&gt;&lt;tt&gt;IO::Async::Resolver&lt;/tt&gt;&lt;/a&gt; for &lt;tt&gt;getaddrinfo(3)&lt;/tt&gt; and &lt;tt&gt;getnameinfo(3)&lt;/tt&gt;. The resolver is now directly accessible from the &lt;tt&gt;IO::Async::Loop&lt;/tt&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;IO::Async::Resolver&lt;/tt&gt; supports deadline timeouts.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;&lt;a href="http://search.cpan.org/perldoc?IO::Async::Stream"&gt;IO::Async::Stream&lt;/a&gt;-&gt;write&lt;/tt&gt; supports taking a &lt;tt&gt;CODE&lt;/tt&gt; reference to dynamically generate data for the stream on-demand.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;tt&gt;IO::Async::Stream-&gt;write&lt;/tt&gt; supports an &lt;tt&gt;on_flush&lt;/tt&gt; callback.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The &lt;tt&gt;IO::Async::Loop-&gt;new&lt;/tt&gt; magic constructor now caches the loop. This is useful for wrapping modules, other event system integration, etc..&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Documentation has been rearranged to add new EVENTS sections, documenting the events that Notifier classes can fire either as callbacks in coderefs, or as methods on subclasses.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Various bugfixes, other documentation additions&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-8576312811901260743?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/8576312811901260743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/12/perl-ioasync-version-034.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/8576312811901260743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/8576312811901260743'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/12/perl-ioasync-version-034.html' title='Perl - IO::Async - version 0.34'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-3022406728088147911</id><published>2010-12-24T13:29:00.008Z</published><updated>2010-12-24T14:39:21.922Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='AnyEvent'/><category scheme='http://www.blogger.com/atom/ns#' term='LPW2010'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='POE'/><category scheme='http://www.blogger.com/atom/ns#' term='events'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><category scheme='http://www.blogger.com/atom/ns#' term='Glib'/><title type='text'>Event loops and Jenga; or 24 Advent Calendar Events in One Go</title><content type='html'>There are many event loops systems in Perl. Do they play together?&lt;br /&gt;&lt;br /&gt;I was thinking about this recently, at my &lt;a href="http://conferences.yapceurope.org/lpw2010/"&gt;LPW2010&lt;/a&gt; talk about &lt;a href="http://search.cpan.org/dist/IO-Async"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt;. In the hackathon the following day, I managed to write &lt;a href="http://search.cpan.org/dist/IO-Async-Loop-POE"&gt;&lt;tt&gt;IO::Async::Loop::POE&lt;/tt&gt;&lt;/a&gt;; a way to run &lt;tt&gt;IO::Async&lt;/tt&gt; atop &lt;a href="http://search.cpan.org/dist/POE"&gt;&lt;tt&gt;POE&lt;/tt&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So I started thinking further; if you can run one event loop system on top of another, how high can we stack them? Can we build a tower, putting each atop the previous, growing taller. Each new layer we try to add would start to get harder, more difficult, increasing the chances the whole thing came crashing down. Sortof like a Jenga tower.&lt;br /&gt;&lt;br /&gt;So what would a Perl event loop Jenga tower look like?&lt;br /&gt;&lt;br /&gt;My attempt looks like this: (326 lines, &lt;a href="http://paste.scsys.co.uk/76194"&gt;paste.scsys.co.uk&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;The output looks something like this:&lt;pre&gt;$ perl jenga.pl&lt;br /&gt;AnyEvent resolved 127.0.0.1:80&lt;br /&gt;Glib reads Hello world!&lt;br /&gt;POE reads Hello world!&lt;br /&gt;POE resolved 127.0.0.1:80&lt;br /&gt;IO::Async reads Hello world!&lt;br /&gt;AnyEvent reads Hello world!&lt;br /&gt;AnyEvent listener accepted&lt;br /&gt;POE listener accepted&lt;br /&gt;IO::Async resolved 127.0.0.1:80&lt;br /&gt;AnyEvent connected received&lt;br /&gt;POE connected received&lt;br /&gt;IO::Async listener accepted&lt;br /&gt;IO::Async connected received&lt;br /&gt;Glib child exited 0&lt;br /&gt;POE child exited 0&lt;br /&gt;IO::Async child exited 0&lt;br /&gt;AnyEvent child exited 0&lt;br /&gt;Glib timer&lt;br /&gt;POE timer&lt;br /&gt;IO::Async timer&lt;br /&gt;AnyEvent timer&lt;br /&gt;^CIO::Async SIGINT&lt;br /&gt;AnyEvent SIGINT&lt;br /&gt;POE SIGINT&lt;br /&gt;Stopping...&lt;/pre&gt;That's 24 events. Count them. It combines &lt;a href="http://search.cpan.org/dist/Glib"&gt;&lt;tt&gt;Glib&lt;/tt&gt;&lt;/a&gt;, &lt;tt&gt;POE&lt;/tt&gt;, &lt;tt&gt;IO::Async&lt;/tt&gt; and &lt;a href="http://search.cpan.org/dist/AnyEvent"&gt;&lt;tt&gt;AnyEvent&lt;/tt&gt;&lt;/a&gt;. It performs a basic filehandle read, a child process watch, and a timed wait in each of these four systems. Because &lt;tt&gt;Glib&lt;/tt&gt; lacks signal watching, only the other three perform this. The other three are also used to perform name resolution, socket listening, and socket connecting.&lt;br /&gt;&lt;br /&gt;Everyone seems to be doing Advent Calendar blogs this year. 24 daily posts, each showing one small thing. Someone suggested I should write a Perl Event systems advent calendar. So perhaps here, consider this to be one. Except it has 24 windows all in one go.&lt;br /&gt;&lt;br /&gt;As it turns out, it's possible to make this tower a little higher. There's a module to run &lt;a href="http://search.cpan.org/dist/Event"&gt;&lt;tt&gt;Event&lt;/tt&gt;&lt;/a&gt; beneath &lt;tt&gt;Glib&lt;/tt&gt;; that is, it replaces the core polling function of &lt;tt&gt;Glib&lt;/tt&gt; to use &lt;tt&gt;Event&lt;/tt&gt; instead. And I suspect it may just about be possible to run &lt;a href="http://search.cpan.org/dist/Tk"&gt;&lt;tt&gt;Tk&lt;/tt&gt;&lt;/a&gt; on &lt;tt&gt;Glib&lt;/tt&gt;, and the &lt;tt&gt;POE&lt;/tt&gt; on &lt;tt&gt;Tk&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;At some point in the new year, I have some plans to turn this one-program script into a more useful resource of examples and translations. The &lt;a href="http://bhami.com/rosetta.html"&gt;Rosetta Stone for Unix&lt;/a&gt; provides a cross-reference for looking up Unix concepts between different systems. I feel that a similar attempt at Perl event loops could be quite useful too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-3022406728088147911?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/3022406728088147911/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/12/event-loops-and-jenga-or-24-advent.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/3022406728088147911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/3022406728088147911'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/12/event-loops-and-jenga-or-24-advent.html' title='Event loops and Jenga; or 24 Advent Calendar Events in One Go'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-420576380591115446</id><published>2010-12-19T11:43:00.006Z</published><updated>2010-12-19T12:22:49.283Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='LPW2010'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='CPS'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>Perl - CPS - version 0.11</title><content type='html'>&lt;a href="http://search.cpan.org/perldoc?CPS"&gt;&lt;tt&gt;CPS&lt;/tt&gt;&lt;/a&gt; is a Perl module that provides several utilities for writing programs in Continuation Passing Style.&lt;br /&gt;&lt;br /&gt;In a nutshell, CPS is a method of control flow within a program, which uses values passed around as continuations as a replacement of the usual call/return semantics. In Perl, this is done by passing &lt;tt&gt;CODE&lt;/tt&gt; references; calling a function and passing in a &lt;tt&gt;CODE&lt;/tt&gt; reference to be invoked with the result, rather than having the function return it. While at first this doesn't seem to be very useful, most of its power comes from the observation that the function doesn't need to invoke its continuation immediately; if it performs some IO operation or similar, it can perform this in an asynchronous fashion, invoking its continuation later. This style of coding is often associated with nonblocking or asynchronous event-driven programming. It is typical of such event systems as &lt;a href="http://search.cpan.org/dist/IO-Async"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A typical problem with implementing CPS control flow, is that all of the usual Perl control-flow mechanisms are built for immediate call/return semantics, where the use of CPS gets in the way. The &lt;tt&gt;CPS&lt;/tt&gt; module provides utility functions for implementing control flow in a continuation passing style, by providing a set of functions that replace the usual Perl control-flow keywords. For example the Perl control structure of a &lt;tt&gt;foreach&lt;/tt&gt; loop&lt;pre&gt;foreach my $frob ( @frobs ) {&lt;br /&gt;   my $wibble = mangle( $frob );&lt;br /&gt;   say "Mangled $frob looks like $wibble";&lt;br /&gt;}&lt;br /&gt;say "All done";&lt;/pre&gt;becomes a call to &lt;tt&gt;CPS::kforeach&lt;/tt&gt;&lt;pre&gt;use CPS qw( kforeach );&lt;br /&gt;&lt;br /&gt;kforeach( \@frobs, sub {&lt;br /&gt;   my ( $frob, $knext ) = @_;&lt;br /&gt;   kmangle( $frob, sub {&lt;br /&gt;      my ( $wibble ) = @_;&lt;br /&gt;      say "Mangled $frob looks like $wibble";&lt;br /&gt;      $knext-&gt;();&lt;br /&gt;   } );&lt;br /&gt;}, sub {&lt;br /&gt;   say "All done";&lt;br /&gt;} );&lt;/pre&gt;We haven't really gained anything by doing this though. If the process of mangling a frob involves some IO tasks, perhaps talking to some remote server, then we'll spend most of our time waiting for it to respond when we could be sending multiple requests and waiting on their responses. We could likely save some time by running them concurrently.&lt;br /&gt;&lt;br /&gt;I gave a talk at &lt;a href="http://conferences.yapceurope.org/lpw2010/"&gt;LPW2010&lt;/a&gt; about Continuation Passing Style and CPS, the slides of which are available &lt;a href="http://www.leonerd.org.uk/lpw2010/CPS-slides.pdf"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;After discussing &lt;tt&gt;CPS&lt;/tt&gt; and &lt;tt&gt;IO::Async&lt;/tt&gt; at LPW, I was talking with &lt;a href="http://search.cpan.org/~mstrout/"&gt;mst&lt;/a&gt; about his &lt;a href="http://search.cpan.org/perldoc?IPC::Command::Multiplex"&gt;&lt;tt&gt;IPC::Command::Multiplex&lt;/tt&gt;&lt;/a&gt; module. He came up with the idea for another control-flow function; a combination of &lt;tt&gt;kpar&lt;/tt&gt; and &lt;tt&gt;kforeach&lt;/tt&gt;, which I called &lt;tt&gt;kpareach&lt;/tt&gt;. In use it looks exactly like &lt;tt&gt;kforeach&lt;/tt&gt;, except that it starts the loop body for each item all at the same time, in parallel, rather than waiting for each one to finish before invoking the next.&lt;br /&gt;&lt;br /&gt;This is a new addition to CPS version 0.11, which is now on CPAN. It is also one of the first new control-flow structures that doesn't have a direct plain-Perl counterpart; a demonstration of the usefulness of CPS in event-driven programming.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-420576380591115446?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/420576380591115446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/12/perl-cps-version-011.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/420576380591115446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/420576380591115446'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/12/perl-cps-version-011.html' title='Perl - CPS - version 0.11'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-5763663046037636168</id><published>2010-11-21T23:24:00.000Z</published><updated>2010-11-21T23:24:42.591Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Net::Async::HTTP'/><category scheme='http://www.blogger.com/atom/ns#' term='Net::LibAsyncNS'/><category scheme='http://www.blogger.com/atom/ns#' term='LPW2010'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Socket::IP'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::KQueue'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>General Updates</title><content type='html'>I have no big specific updates today. Instead, a list of lots of little things I've been working on:&lt;ul&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/perldoc?IO::Socket::IP"&gt;&lt;tt&gt;IO::Socket::IP&lt;/tt&gt;&lt;/a&gt; now has preliminary non-blocking connect support (version &lt;a href="http://search.cpan.org/~pevans/IO-Socket-IP-0.05_003/"&gt;0.05_003&lt;/a&gt;). This isn't quite a perfect solution because of blocking name resolvers, but see also &lt;tt&gt;Net::LibAsyncNS&lt;/tt&gt; below.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Created a new CPAN dist, wrapping &lt;a href="http://0pointer.de/lennart/projects/libasyncns/"&gt;&lt;tt&gt;libasyncns&lt;/tt&gt;&lt;/a&gt;, called &lt;a href="http://search.cpan.org/perldoc?Net::LibAsyncNS"&gt;&lt;tt&gt;Net::LibAsyncNS&lt;/tt&gt;&lt;/a&gt;. This allows a simple way to asynchronise name resolver lookups.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Have fixed a few &lt;a href="https://rt.cpan.org/Public/Bug/Display.html?id=61481"&gt;bugs&lt;/a&gt; in &lt;a href="http://search.cpan.org/perldoc?IO::KQueue"&gt;&lt;tt&gt;IO::KQueue&lt;/tt&gt;&lt;/a&gt;, relating to dodgy handling of Perl scalars in the udata field. Some memory leak bugs still exist, but I believe these to be the kernel's fault. See below.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Spent some time on &lt;a href="http://lists.freebsd.org/pipermail/freebsd-hackers/"&gt;&lt;tt&gt;Freebsd-hackers@&lt;/tt&gt;&lt;/a&gt; &lt;a href="http://lists.freebsd.org/pipermail/freebsd-hackers/2010-November/033565.html"&gt;arguing&lt;/a&gt; about &lt;tt&gt;kqueue&lt;/tt&gt; and managing user data pointers. Long story short I believe &lt;tt&gt;kqueue&lt;/tt&gt; API itself is missing a feature, making generic wrapping of it impossible from any high-level language, or properly by C libraries also.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Both talks I submitted for &lt;a href="http://conferences.yapceurope.org/lpw2010/"&gt;LPW2010&lt;/a&gt; were accepted; on the subjects of &lt;a href="http://search.cpan.org/perldoc?CPS"&gt;&lt;tt&gt;CPS&lt;/tt&gt;&lt;/a&gt; and &lt;a href="http://search.cpan.org/perldoc?IO::Async"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/perldoc?Net::Async::HTTP"&gt;&lt;tt&gt;Net::Async::HTTP&lt;/tt&gt;&lt;/a&gt; now has SSL support and can stream response body content as it arrives, rather than waiting for the whole response (version &lt;a href="http://search.cpan.org/~pevans/Net-Async-HTTP-0.08/"&gt;0.08&lt;/a&gt;).&lt;/li&gt;&lt;/ul&gt;That's all for a quick update, but I may write about any or all of these topics in more detail later...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-5763663046037636168?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/5763663046037636168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/11/general-updates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5763663046037636168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5763663046037636168'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/11/general-updates.html' title='General Updates'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-2520947671071372379</id><published>2010-10-31T19:39:00.007Z</published><updated>2010-10-31T21:31:10.153Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test::Identity'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - Test::Identity</title><content type='html'>Today I uploaded a new module to CPAN; &lt;a href="http://search.cpan.org/perldoc?Test::Identity"&gt;&lt;tt&gt;Test::Identity&lt;/tt&gt;&lt;/a&gt;. It's possibly the quickest module I've ever written, from when I decided to write it, to when it was actually uploaded:&lt;blockquote&gt;(18:02) &lt;LeoNerd&gt; sub Test::Identity::identical { is refaddr $_[0], refaddr $_[1], $_[2] }     &lt;==  I'm about to write such in a module, unless anyone can suggest me a module that already has it&lt;br /&gt;...&lt;br /&gt;(19:21) * GumbyPAN CPAN Upload: Test-Identity-0.01 by PEVANS&lt;/blockquote&gt;I won't spend a long time explaining why, I'll just quote the docs:&lt;br /&gt;&lt;br /&gt;&lt;quote&gt;This module provides a single testing function, identical. It asserts that a given reference is as expected; that is, it either refers to the same object or is undef. It is similar to Test::More::is except that it uses refaddr, ensuring that it behaves correctly even if the references under test are objects that overload stringification or numification.&lt;br /&gt;&lt;br /&gt;It also provides better diagnostics if the test fails:&lt;pre&gt;$ perl -MTest::More=tests,1 -MTest::Identity -e'identical [], {}'&lt;br /&gt;1..1&lt;br /&gt;not ok 1&lt;br /&gt;#   Failed test at -e line 1.&lt;br /&gt;# Expected an anonymous HASH ref, got an anonymous ARRAY ref&lt;br /&gt;# Looks like you failed 1 test of 1.&lt;br /&gt;&lt;br /&gt;$ perl -MTest::More=tests,1 -MTest::Identity -e'identical [], []'&lt;br /&gt;1..1&lt;br /&gt;not ok 1&lt;br /&gt;#   Failed test at -e line 1.&lt;br /&gt;# Expected an anonymous ARRAY ref to the correct object&lt;br /&gt;# Looks like you failed 1 test of 1.&lt;/pre&gt;&lt;/quote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-2520947671071372379?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/2520947671071372379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/10/perl-testidentity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/2520947671071372379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/2520947671071372379'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/10/perl-testidentity.html' title='Perl - Test::Identity'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-7101717703163701793</id><published>2010-10-18T05:32:00.004+01:00</published><updated>2010-10-19T20:21:10.529+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Socket::GetAddrInfo'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Socket::IP'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='IPv6'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - IO::Socket::IP</title><content type='html'>&lt;a href="http://search.cpan.org/perldoc?IO::Socket::IP"&gt;&lt;tt&gt;IO::Socket::IP&lt;/tt&gt;&lt;/a&gt; is a subclass of &lt;a href="http://search.cpan.org/perldoc?IO::Socket"&gt;&lt;tt&gt;IO::Socket&lt;/tt&gt;&lt;/a&gt; that provides a protocol-independent way to use IPv4 and IPv6 sockets. It provides an API compatible with the IPv4-only &lt;a href="http://search.cpan.org/perldoc?IO::Socket::INET"&gt;&lt;tt&gt;IO::Socket::INET&lt;/tt&gt;&lt;/a&gt;, but does so in a way that ensures properly transparent IPv6 support.&lt;br /&gt;&lt;br /&gt;The following example shows it has an identical API to the &lt;tt&gt;::INET&lt;/tt&gt; module:&lt;pre&gt;use IO::Socket::IP;&lt;br /&gt;&lt;br /&gt;my $sock = IO::Socket::IP-&gt;new(&lt;br /&gt;   PeerHost =&gt; "www.google.com",&lt;br /&gt;   PeerPort =&gt; "www",&lt;br /&gt;) or die "Cannot construct socket - $@";&lt;/pre&gt;At this point, &lt;tt&gt;$sock&lt;/tt&gt; is just another &lt;tt&gt;IO::Socket&lt;/tt&gt;-derived filehandle, and supports all the usual methods and IO functionality. The only difference here is that, where &lt;tt&gt;IO::Socket::INET&lt;/tt&gt; would have used a legacy &lt;tt&gt;gethostbyname&lt;/tt&gt; call and made a &lt;tt&gt;PF_INET&lt;/tt&gt; socket, &lt;tt&gt;IO::Socket::IP&lt;/tt&gt; will use &lt;tt&gt;getaddrinfo&lt;/tt&gt; (via &lt;a href="http://search.cpan.org/perldoc?Socket::GetAddrInfo"&gt;&lt;tt&gt;Socket::GetAddrInfo&lt;/tt&gt;&lt;/a&gt;), and will use either &lt;tt&gt;PF_INET&lt;/tt&gt; or &lt;tt&gt;PF_INET6&lt;/tt&gt; as appropriate.&lt;br /&gt;&lt;br /&gt;It's not yet a complete 100% API clone of &lt;tt&gt;::INET&lt;/tt&gt; though. While it supports all the methods, there are a few constructor arguments not yet supported, being &lt;tt&gt;Blocking&lt;/tt&gt; and &lt;tt&gt;Timeout&lt;/tt&gt;. The way that &lt;tt&gt;getaddrinfo&lt;/tt&gt; returns a list of candidate addresses, to be tried in order, makes nonblocking support hard to do, and complicates the model for what timeout really means. For nonblocking connect support, better solutions already exist, such as &lt;a href="http://search.cpan.org/dist/IO-Async/"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt;'s &lt;a href="http://search.cpan.org/perldoc?IO::Async::Connector"&gt;&lt;tt&gt;Connector&lt;/tt&gt;&lt;/a&gt;, which has always supported IPv6 via &lt;tt&gt;getaddrinfo&lt;/tt&gt;. As for timeouts, eventually &lt;tt&gt;IO::Socket::IP&lt;/tt&gt; should support it, but for now a &lt;tt&gt;local&lt;/tt&gt;'ised &lt;tt&gt;$SIG{ALRM}&lt;/tt&gt; and &lt;tt&gt;alarm&lt;/tt&gt; call should suffice.&lt;br /&gt;&lt;br /&gt;For almost all use cases, switching to using &lt;tt&gt;IO::Socket::IP&lt;/tt&gt; should be a simple matter, because of the API similarities. Just adding an extra dependency (because &lt;tt&gt;::IP&lt;/tt&gt; isn't core), and substituting the package name in source should be enough.&lt;br /&gt;&lt;br /&gt;Finally, in case you don't want to pull in an extra hard dependency, you might consider the following fragment I've used quite successfully:&lt;pre&gt;   my $class = eval { require IO::Socket::IP&lt;br /&gt;                         and "IO::Socket::IP" } ||&lt;br /&gt;               do   { require IO::Socket::INET&lt;br /&gt;                         and "IO::Socket::INET" };&lt;br /&gt;&lt;br /&gt;   $socket = $class-&gt;new(&lt;br /&gt;      PeerHost =&gt; $host,&lt;br /&gt;      PeerPort =&gt; $port,&lt;br /&gt;   ) or die "Cannot connect - $@\n";&lt;/pre&gt;There. Now you have no excuse for not being IPv6-ready.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-7101717703163701793?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/7101717703163701793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/10/perl-iosocketip.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/7101717703163701793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/7101717703163701793'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/10/perl-iosocketip.html' title='Perl - IO::Socket::IP'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-5015777549584475052</id><published>2010-09-23T20:40:00.003+01:00</published><updated>2010-09-23T20:43:01.246+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>Perl - IO::Async - version 0.30</title><content type='html'>Yesterday, I put the next version of &lt;a href="http://search.cpan.org/~pevans/IO-Async-0.30/"&gt;&lt;tt&gt;IO::Async&lt;/tt&gt;&lt;/a&gt; on CPAN; version 0.30. This was primarily an update to add some new features, though also a few minor bugfixes and documentation updates were included too. Here I want to focus on a few of these new features.&lt;br /&gt;&lt;br /&gt;The first of these new features is nothing groundbreaking in itself, but feeds into the others. It's simply the addition of &lt;a href="http://search.cpan.org/perldoc?IO::Async::Socket"&gt;&lt;tt&gt;IO::Async::Socket&lt;/tt&gt;&lt;/a&gt;, a notifier subclass to contain a socket that isn't necessarily a stream (primarily &lt;tt&gt;SOCK_DGRAM&lt;/tt&gt; or &lt;tt&gt;SOCK_RAW&lt;/tt&gt; sockets such as UDP, &lt;a href="http://search.cpan.org/perldoc?IO::Socket::Packet"&gt;&lt;tt&gt;PF_PACKET&lt;/tt&gt;&lt;/a&gt; or &lt;a href="http://search.cpan.org/perldoc?IO::Socket::Netlink"&gt;&lt;tt&gt;PF_NETLINK&lt;/tt&gt;&lt;/a&gt;). This neatens up a few rough edges with trying to put such sockets directly in &lt;a href="http://search.cpan.org/perldoc?IO::Async::Handle"&gt;&lt;tt&gt;IO::Async::Handle&lt;/tt&gt;&lt;/a&gt; objects.&lt;br /&gt;&lt;br /&gt;The second main new feature is the creation of the &lt;a href="http://search.cpan.org/perldoc?IO::Async::Protocol"&gt;&lt;tt&gt;IO::Async::Protocol&lt;/tt&gt;&lt;/a&gt; class, and &lt;a href="http://search.cpan.org/perldoc?IO::Async::Protocol::Stream"&gt;&lt;tt&gt;IO::Async::Protocol::Stream&lt;/tt&gt;&lt;/a&gt; subclass. These derive directly from &lt;a href="http://search.cpan.org/perldoc?IO::Async::Notifier"&gt;&lt;tt&gt;IO::Async::Notifier&lt;/tt&gt;&lt;/a&gt; rather than &lt;tt&gt;IO::Async::Handle&lt;/tt&gt;, and are intended to be abstract containers of code, and not perform any IO operations directly. Instead, they contain a Handle or Stream object as a child notifier. By exposing an API identical to &lt;tt&gt;IO::Async::Stream&lt;/tt&gt;, the &lt;tt&gt;IO::Async::Protocol::Stream&lt;/tt&gt; should be a drop-in replacement for any modules trying to implement a network protocol.&lt;br /&gt;&lt;br /&gt;With the addition of &lt;a href="http://search.cpan.org/perldoc?IO::Async::SSL"&gt;&lt;tt&gt;IO::Async::SSL&lt;/tt&gt;&lt;/a&gt;, not every stream-like connection can be represented by &lt;tt&gt;IO::Async::Stream&lt;/tt&gt;, so separating the transport layer from the protocol layer is required. This wasn't possible by subclassing, whereas object containment makes it much simpler.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://search.cpan.org/dist/Net-Async-FTP/"&gt;&lt;tt&gt;Net::Async::FTP&lt;/tt&gt;&lt;/a&gt;, &lt;a href="http://search.cpan.org/dist/Net-Async-HTTP/"&gt;&lt;tt&gt;Net::Async::HTTP&lt;/tt&gt;&lt;/a&gt;, and &lt;a href="http://search.cpan.org/dist/Net-Async-IRC/"&gt;&lt;tt&gt;Net::Async::IRC&lt;/tt&gt;&lt;/a&gt; have all been updated to use it, and most other use cases should be simple to change.&lt;br /&gt;&lt;br /&gt;The final main change is that &lt;a href="http://search.cpan.org/~pevans/IO-Async-0.30/lib/IO/Async/Connector.pm#$loop-%3Econnect%28_%params_%29"&gt;&lt;tt&gt;$loop-&gt;connect&lt;/tt&gt;&lt;/a&gt; and &lt;a href="http://search.cpan.org/perldoc?IO::Async::Listener"&gt;&lt;tt&gt;IO::Async::Listener&lt;/tt&gt;&lt;/a&gt; now support direct &lt;tt&gt;on_stream&lt;/tt&gt; or &lt;tt&gt;on_socket&lt;/tt&gt; continuations, which will be provided an instance of Stream or Socket directly, rather than requiring the invoked code to wrap one. This can then be easily configured as a &lt;tt&gt;IO::Async::Protocol&lt;/tt&gt;'s transport.&lt;br /&gt;&lt;br /&gt;Having made this change, it leads the way to transparent SSL support across all protocols, and possibly other concerns like SOCKS proxies, by extending the arguments to &lt;tt&gt;$loop-&gt;connect&lt;/tt&gt; or Listener. But that's for another post...&lt;br /&gt;&lt;br /&gt;Finally, I should announce that I've now started a channel on &lt;tt&gt;irc.perl.org&lt;/tt&gt; called &lt;tt&gt;#ioasync&lt;/tt&gt;, as the official IRC home for &lt;tt&gt;IO::Async&lt;/tt&gt;. Feel free to drop by if you have any issues, comments, questions,...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-5015777549584475052?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/5015777549584475052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/09/perl-ioasync-version-030.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5015777549584475052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5015777549584475052'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/09/perl-ioasync-version-030.html' title='Perl - IO::Async - version 0.30'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-5459193509509565031</id><published>2010-09-20T19:41:00.002+01:00</published><updated>2010-09-20T20:09:22.477+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='overload::substr'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - overload::substr</title><content type='html'>&lt;a href="http://search.cpan.org/perldoc?overload"&gt;&lt;tt&gt;overload&lt;/tt&gt;&lt;/a&gt; allows an object class to provide methods which Perl should use to implement certain operators, like numerical addition or string concatenation. One operator that &lt;tt&gt;overload&lt;/tt&gt; doesn't allow to be provided, is &lt;tt&gt;substr&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://search.cpan.org/perldoc?overload::substr"&gt;&lt;tt&gt;overload::substr&lt;/tt&gt;&lt;/a&gt; allows this to be overloaded. This allows objects that behave like a string, to specify to Perl how they will handle the &lt;tt&gt;substr&lt;/tt&gt; operator.&lt;pre&gt;$ cat example.pl &lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;use strict;&lt;br /&gt;use feature qw( say );&lt;br /&gt;&lt;br /&gt;package ExampleString;&lt;br /&gt;&lt;br /&gt;use overload::substr;&lt;br /&gt;&lt;br /&gt;sub new { return bless [ @_ ]; }&lt;br /&gt;&lt;br /&gt;sub _substr&lt;br /&gt;{&lt;br /&gt;   my $self = shift;&lt;br /&gt;   my ( $offs, $len, $replace ) = @_;&lt;br /&gt;&lt;br /&gt;   return sprintf "&gt;&gt; %s between %d and %d &amp;lt;&amp;lt;", $self, $offs, $offs+$len;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package main;&lt;br /&gt;&lt;br /&gt;my $str = ExampleString-&gt;new( "Hello, world" );&lt;br /&gt;&lt;br /&gt;say substr( $str, 2, 5 );&lt;br /&gt;&lt;br /&gt;$ perl example.pl&lt;br /&gt;&gt;&gt; ExampleString=ARRAY(0x86dd9c8) between 2 and 7 &amp;lt;&amp;lt;&lt;/pre&gt;The module is still in its early days yet, but the basics appear to be working on all Perl versions back to 5.8. I also want to try extending it, so that &lt;tt&gt;split()&lt;/tt&gt; and regexp matches with &lt;tt&gt;m//&lt;/tt&gt; and substitutions with &lt;tt&gt;s///&lt;/tt&gt; also use the &lt;tt&gt;substr&lt;/tt&gt; operation. The identity that&lt;pre&gt;$1 == substr( $str, $-[1], $+[1] - $-[1] )&lt;/pre&gt;is sure to be useful here.&lt;br /&gt;&lt;br /&gt;I need a good example to show it off with sometime. I have in mind a string-alike object with real positional cursors, which remember their contextual position even after edits in other parts of the string. But more on that later...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-5459193509509565031?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/5459193509509565031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/09/perl-overloadsubstr.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5459193509509565031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5459193509509565031'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/09/perl-overloadsubstr.html' title='Perl - overload::substr'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-3228297719464490024</id><published>2010-09-06T14:59:00.007+01:00</published><updated>2010-09-23T20:47:39.834+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IO::Socket'/><category scheme='http://www.blogger.com/atom/ns#' term='module naming'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='IPv6'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Module name suggestions: A proper IO::Socket for IPv4/IPv6 duallity</title><content type='html'>I currently don't have a good name for a module I'd like to write, because I think it is very much required right now.&lt;br /&gt;&lt;br /&gt;We have &lt;a href="http://search.cpan.org/~gbarr/IO-1.25/lib/IO/Socket/INET.pm"&gt;&lt;tt&gt;IO::Socket::INET&lt;/tt&gt;&lt;/a&gt;. It wraps &lt;tt&gt;PF_INET&lt;/tt&gt;, thus making it IPv4 only.&lt;br /&gt;&lt;br /&gt;We have &lt;a href="http://search.cpan.org/~shlomif/IO-Socket-INET6-2.65/lib/IO/Socket/INET6.pm"&gt;&lt;tt&gt;IO::Socket::INET6&lt;/tt&gt;&lt;/a&gt;. It wraps either &lt;tt&gt;PF_INET&lt;/tt&gt; or &lt;tt&gt;PF_INET6&lt;/tt&gt;, despite its name. It also uses &lt;a href="http://search.cpan.org/~umemoto/Socket6-0.23/Socket6.pm"&gt;&lt;tt&gt;Socket6&lt;/tt&gt;&lt;/a&gt;, thus restricting it to only working on machines capable of supporting IPv6.&lt;br /&gt;&lt;br /&gt;Thus any author wanting to write code to communicate to the internet (apparently that's some new fad everyone's talking about this week) is presented a moral dilema: Support IPv6 at the cost of not working on older v4-only machines, or support older machines but be incapable of using IPv6.&lt;br /&gt;&lt;br /&gt;I originally partially solved this problem some years ago by the creation of &lt;a href="http://search.cpan.org/~pevans/Socket-GetAddrInfo-0.16/lib/Socket/GetAddrInfo.pm"&gt;&lt;tt&gt;Socket::GetAddrInfo&lt;/tt&gt;&lt;/a&gt;, a module that presents the interface of &lt;a href="http://www.ietf.org/rfc/rfc2553.txt"&gt;RFC2553&lt;/a&gt;'s &lt;tt&gt;getaddrinfo(3)&lt;/tt&gt; and &lt;tt&gt;getnameinfo(3)&lt;/tt&gt; functions. This however is not enough for actually connecting and using sockets.&lt;br /&gt;&lt;br /&gt;I'd therefore like to propose a new &lt;a href="http://search.cpan.org/~gbarr/IO-1.25/lib/IO/Socket.pm"&gt;&lt;tt&gt;IO::Socket&lt;/tt&gt;&lt;/a&gt; subclass that uses these &lt;em&gt;and only these&lt;/em&gt; functions, for converting between addresses and name/service pairs.&lt;pre&gt;use IO::Socket::YourNameHere;&lt;br /&gt;&lt;br /&gt;my $sock = IO::Socket::YourNameHere-&gt;new(&lt;br /&gt;   PeerHost    =&gt; "www.google.com",&lt;br /&gt;   PeerService =&gt; "www",&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;printf "Now connected to %s:%s\n", $sock-&gt;peerhost, $sock-&gt;peerservice;&lt;br /&gt;&lt;br /&gt;...&lt;/pre&gt;Since it would use &lt;tt&gt;Socket::GetAddrInfo&lt;/tt&gt;, it can transparently support IPv4 or IPv6. Since it would &lt;em&gt;only&lt;/em&gt; use &lt;tt&gt;Socket::GetAddrInfo&lt;/tt&gt;, it will work in a v4-only mode on machines incapable of supporting IPv6, and will not be restricted to only IPv4 or IPv6 if and when some new addressing family comes along to replace IPv6 one day; as v6 is now trying to do with v4.&lt;br /&gt;&lt;br /&gt;In order to provide an easy transition period, I'd also support additional IO::Socket::INET options where they still make sense; e.g. accepting &lt;tt&gt;{Local/Peer}Port&lt;/tt&gt; as a synonym for &lt;tt&gt;{Local/Peer}Service&lt;/tt&gt;. The upshot here ought to be that you can simply&lt;pre&gt;sed -i s/IO::Socket::INET/IO::Socket::YourNameHere/&lt;/pre&gt;and suddenly your code will JustWork on IPv6 in a good &gt;90% of cases. &lt;br /&gt;&lt;br /&gt;Can anyone suggest me a better module name for this?&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;Edit 2010/09/07: We seem to be settling on &lt;tt&gt;IO::Socket::IP&lt;/tt&gt; for this currently.&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;Edit 2010/09/23: We did indeed settle on &lt;tt&gt;IO::Socket::IP&lt;/tt&gt;; this is now up on CPAN, and will be the subject of a future posting...&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;&lt;i&gt;This cross-posted from &lt;tt&gt;module-authors@perl&lt;/tt&gt;.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-3228297719464490024?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/3228297719464490024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/09/module-name-suggestions-proper-iosocket.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/3228297719464490024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/3228297719464490024'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/09/module-name-suggestions-proper-iosocket.html' title='Module name suggestions: A proper IO::Socket for IPv4/IPv6 duallity'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-4394873842818675485</id><published>2010-08-15T15:51:00.002+01:00</published><updated>2010-08-15T15:55:58.280+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Test to assert object identity</title><content type='html'>I've just copypasted the following test function into about the fifth different test script:&lt;pre&gt;use Scalar::Util qw( refaddr );&lt;br /&gt;sub identical&lt;br /&gt;{&lt;br /&gt;   my ( $got, $expected, $name ) = @_;&lt;br /&gt;&lt;br /&gt;   my $got_addr = refaddr $got;&lt;br /&gt;   my $exp_addr = refaddr $expected;&lt;br /&gt;&lt;br /&gt;   ok( !defined $got_addr &amp;&amp; !defined $exp_addr ||&lt;br /&gt;          $got_addr == $exp_addr,&lt;br /&gt;       $name ) or&lt;br /&gt;      diag( "Expected $got and $expected to refer to the same object" );&lt;br /&gt;}&lt;/pre&gt;Rather than continuing to copypaste it around some more, can anyone suggest a standard &lt;tt&gt;Test::&lt;/tt&gt; module that contains it? Failing that, if it's really honestly the case that nobody has yet felt it necessary to provide one, could someone suggest a suitable module to contain it?&lt;br /&gt;&lt;br /&gt;This behaviour cannot be implemented using, say, &lt;tt&gt;is( $obj, $expected )&lt;/tt&gt; because that will attempt to compare numerical equality, which of course will fail for any object that overloads numberification or numeric comparison operators.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-4394873842818675485?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/4394873842818675485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/08/test-to-assert-object-identity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4394873842818675485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4394873842818675485'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/08/test-to-assert-object-identity.html' title='Test to assert object identity'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-4033903785293182196</id><published>2010-08-10T00:23:00.004+01:00</published><updated>2010-08-10T01:24:34.995+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Error'/><category scheme='http://www.blogger.com/atom/ns#' term='Module::PluginFinder'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='Config::XPath'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='Module::Build'/><title type='text'>Perl - Config::XPath - new version 0.16</title><content type='html'>&lt;a href="http://search.cpan.org/perldoc?Config::XPath"&gt;Config::XPath&lt;/a&gt; is a Perl module for accessing configuration files using XPath queries. It provides some wrapping around &lt;a href="http://search.cpan.org/dist/XML-XPath/"&gt;XML::XPath&lt;/a&gt; for convenience in using a single config file, and easily fetching string, list or map values from it. It plays nicely alongside, for example, &lt;a href="http://search.cpan.org/perldoc?Module::PluginFinder"&gt;Module::PluginFinder&lt;/a&gt; (about which I shall write more another day) for easily building powerful configuration-driven plugin-based programs.&lt;pre&gt;use Config::XPath;&lt;br /&gt;use Module::PluginFinder;&lt;br /&gt;&lt;br /&gt;my $conf = Config::XPath-&gt;new( filename =&gt; 'foomangler.conf' );&lt;br /&gt;my $finder = Module::PluginFinder-&gt;new(&lt;br /&gt;                search_path =&gt; 'FooMangler::Plugin',&lt;br /&gt;                typefunc    =&gt; 'TYPE',&lt;br /&gt;             );&lt;br /&gt;&lt;br /&gt;my %plugins;&lt;br /&gt;&lt;br /&gt;foreach my $plugin_conf ( $conf-&gt;get_sub_list( '/plugin' ) ) {&lt;br /&gt;   my $name = $plugin_conf-&gt;get_string( '@name' );&lt;br /&gt;   my $type = $plugin_conf-&gt;get_string( '@type' );&lt;br /&gt;&lt;br /&gt;   $plugins{$name} = $finder-&gt;construct( $type, $plugin_conf );&lt;br /&gt;}&lt;/pre&gt;Given a config file that perhaps looks like&lt;pre&gt;&amp;lt;foomangler&gt;&lt;br /&gt;  &amp;lt;plugin type="hello" name="hello_world"&gt;&lt;br /&gt;    &amp;lt;message&gt;Hello, world&amp;lt;/message&gt;&lt;br /&gt;  &amp;lt;/plugin&gt;&lt;br /&gt;&amp;lt;/foomangler&gt;&lt;/pre&gt;We can implement a plugin for this system quite simply, and have it be automatically discovered by the plugin system, instances created, and passed in its configuration from the config file:&lt;pre&gt;package FooMangler::Plugin::Hello;&lt;br /&gt;use constant TYPE =&gt; "hello";&lt;br /&gt;&lt;br /&gt;sub new&lt;br /&gt;{&lt;br /&gt;   my $class = shift;&lt;br /&gt;   my ( $config ) = @_;&lt;br /&gt;&lt;br /&gt;   my $message = $config-&gt;get_string( 'message' );&lt;br /&gt;   ...&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;As well as providing one-shot reading support, it also has a subclass &lt;a href="http://search.cpan.org/perldoc?Config::XPath::Reloadable"&gt;Config::XPath::Reloadable&lt;/a&gt; which allows for convenient reloading of config files. It itself keeps track of which XML nodes it has already seen, based on some defined key attribute, so it can determine additions and deletions. It will invoke callback functions when items are added or deleted, or their underlying config may have changed.&lt;pre&gt;use Config::XPath::Reloadable;&lt;br /&gt;&lt;br /&gt;my $conf = Config::XPath::Reloadable-&gt;new( filename =&gt; 'foomangler.conf' );&lt;br /&gt;my $finder = Module::PluginFinder-&gt;new( ... );&lt;br /&gt;&lt;br /&gt;$SIG{HUP} = sub { $conf-&gt;reload };&lt;br /&gt;&lt;br /&gt;my %manglers;&lt;br /&gt;&lt;br /&gt;$conf-&gt;associate_nodeset( '/mangler', '@name',&lt;br /&gt;   add =&gt; sub {&lt;br /&gt;      my ( $name, $mangler_conf ) = @_;&lt;br /&gt;      my $type = $mangler_conf-&gt;get_string( '@type' );&lt;br /&gt;&lt;br /&gt;      $manglers{$name} = $finder-&gt;construct( $type, $mangler_conf );&lt;br /&gt;   },&lt;br /&gt;&lt;br /&gt;   keep =&gt; sub {&lt;br /&gt;      my ( $name, $mangler_conf ) = @_;&lt;br /&gt;&lt;br /&gt;      $manglers{$name}-&gt;reconfigure( $mangler_conf );&lt;br /&gt;   },&lt;br /&gt;&lt;br /&gt;   remove =&gt; sub {&lt;br /&gt;      my ( $name ) = @_;&lt;br /&gt;&lt;br /&gt;      delete $manglers{$name};&lt;br /&gt;   },&lt;br /&gt;);&lt;/pre&gt;Now, whenever a &lt;tt&gt;SIGHUP&lt;/tt&gt; signal is received, the config file is re-read. The configurations for all the current manglers are updated, new ones added, and old ones deleted.&lt;br /&gt;&lt;hr/&gt;I've just uploaded a new release, 0.16. This release finally gets rid of the awkward &lt;a href="http://search.cpan.org/perldoc?Error"&gt;Error&lt;/a&gt;-based exceptions, instead using plain-old &lt;a href="http://search.cpan.org/perldoc?Carp"&gt;Carp&lt;/a&gt;-based string exceptions. This removes a dependency on the old, deprecated, and unsupported &lt;tt&gt;Error&lt;/tt&gt; distribution.&lt;br /&gt;&lt;br /&gt;I've also manually set the &lt;tt&gt;configure_requires&lt;/tt&gt; element to set the required version of &lt;a href="http://search.cpan.org/perldoc?Module::Build"&gt;Module::Build&lt;/a&gt; down to &lt;tt&gt;0.2808&lt;/tt&gt;, which is what Perl 5.10.0 shipped with, rather than let it pick its own version, where it sets it to &lt;tt&gt;0.36&lt;/tt&gt;. Hopefully this should lead to no awkward "please upgrade Module::Build" on clean-slate installs. If this comes out OK I might start applying that by default across all my dists (where appropriate). It does seem a little awkward, but then I can't really think of a neater way for it to detect that - hard for it to know, for example, about random methods or functionality invoked during the &lt;tt&gt;Build.PL&lt;/tt&gt; file itself, or bugs/features implicitly relied upon. Something to think about for next time, I feel...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-4033903785293182196?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/4033903785293182196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/08/perl-configxpath-new-version-016.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4033903785293182196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4033903785293182196'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/08/perl-configxpath-new-version-016.html' title='Perl - Config::XPath - new version 0.16'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-4097343082940627988</id><published>2010-07-30T22:32:00.005+01:00</published><updated>2011-06-10T12:31:27.011+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='List::UtilsBy'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - List::UtilsBy</title><content type='html'>&lt;a href="http://search.cpan.org/perldoc?List::UtilsBy"&gt;List::UtilsBy&lt;/a&gt; is a module containing a number of list utility functions which all take a block of code to control their behaviour. Among its delights are a neat wrapping of &lt;tt&gt;sort&lt;/tt&gt; by a custom accessor, optimisation, and rearrangement functions. The functions in this module are a loose collection of functions I've written or found useful over the past few months or so. I won't give a full overview here, you can read the docs yourselves; but I will give a brief description of a few functions.&lt;br /&gt;&lt;br /&gt;One frequent question we often get in &lt;tt&gt;#perl&lt;/tt&gt; on Freenode concerns how to sort a list of items by some property of the items, perhaps the value of an object accessor or the result of some regexp extraction. Sometimes the answer comes in variants on a theme of&lt;pre&gt;@sorted_items = sort { $a-&gt;accessor cmp $b-&gt;accessor } @items;&lt;/pre&gt;&lt;pre&gt;@sorted_items = sort { ( $a =~ m/^(\d+)/ )[0] &lt;=&gt; ( $b =~ m/^(\d+)/ )[0] } @items;&lt;/pre&gt;Sometimes a mention of the Schwartzian Transform comes.&lt;br /&gt;&lt;br /&gt;I decided to take this often-use pattern and find a nicer way to represent it. The result is the &lt;tt&gt;sort_by&lt;/tt&gt; functional.&lt;pre&gt;@sorted_items = sort_by { $_-&gt;accessor } @items;&lt;/pre&gt;&lt;pre&gt;@sorted_items = sort_by { ( $_ =~ m/^(\d+)/ )[0] } @items;&lt;/pre&gt;As well as neatness of code, this also has advantage of invoking the accessor only once per item, rather than once per item pair.&lt;br /&gt;&lt;br /&gt;An operation I've often wanted to perform is to search a list of items for the best match by some metric. For this, there is &lt;tt&gt;max_by&lt;/tt&gt; and variations.&lt;pre&gt;$longest = max_by { length $_ } @strings;&lt;/pre&gt;&lt;pre&gt;$closest = min_by { distance_between( $_-&gt;location, $here ) } @places;&lt;/pre&gt;&lt;br /&gt;Finally, as a replacement for the often-used pattern&lt;pre&gt;@array = grep { wanted $_ } @array;&lt;/pre&gt;We have&lt;pre&gt;extract_by { not wanted $_ } @array;&lt;/pre&gt;As noted in the documentation, this is implemented by &lt;tt&gt;splice&lt;/tt&gt;ing the unwanted elements out, not by assigning a new list, so this is safe to use on lists containing weak references, or &lt;tt&gt;tie&lt;/tt&gt;d variables.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-4097343082940627988?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/4097343082940627988/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/07/perl-listutilsby.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4097343082940627988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4097343082940627988'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/07/perl-listutilsby.html' title='Perl - List::UtilsBy'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-4054148353600498179</id><published>2010-07-19T21:05:00.006+01:00</published><updated>2010-07-20T08:36:38.786+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Circle'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>My current Perl project - Circle</title><content type='html'>Recently &lt;a href="http://www.wgz.org/~chromatic"&gt;chromatic&lt;/a&gt; wrote that we should &lt;a href="http://www.modernperlbooks.com/mt/2010/07/the-urge-to-brag.html"&gt;"tell the world, what are you working on with Perl?"&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So, to answer this then, my current project is &lt;a href="http://www.leonerd.org.uk/code/circle/"&gt;Circle&lt;/a&gt;, an IRC client. Actually, it's much more than an IRC client, but that will do as a first approximation.&lt;br /&gt;&lt;br /&gt;Rather than being Just Another IRC client, this one is split into two programs; a backend server that runs on some machine somewhere, likely your co-located shell hosting box, or home server. This maintains all the connections to the IRC networks, persists the scrollback and so on; it is the guts of the logic. Then there's the frontend program, a lightweight GTK application that draws the UI for the backend logic. The frontend doesn't really understand IRC, the backend has no knowledge of GTK. Several readers may recognise something of the MVC pattern about this. &lt;br /&gt;&lt;br /&gt;Without going into too much detail here (you can read the above link), this gives you the advantages of a real local native-UI client, plus the advantages of a persistent server. The UI interactions are local, no network latency or bandwidth to get in the way of line editing, backbuffer scrolling, window switching, and so on; yet all the data is persisted in the server so you can just disconnect the thin client and reconnect it from anywhere else.&lt;br /&gt;&lt;br /&gt;A common way people usually solve this sort of problem is to run irssi in a screen session, and reconnect over SSH. The primary downside of this setup is it requires a low-latency, high-bandwidth connection to the server, as every keypress of the line editor to send your next line, will have to round-trip over that network. Every backbuffer operation, scrolling up and down, or switching between windows, has to redraw over the link. If that link has high latency, or low bandwidth, the user experience will suffer. If the network charges for bandwidth, you will end up paying many times to keep re-sending the same screenful of scrollback as you switch windows. By not having a real presence on the local desktop, irssi-in-screen also cannot take advantage of local desktop features such as notification sounds or highlight popups, nor can it access the local filesystem to perform DCC transfers or similar.&lt;br /&gt;&lt;br /&gt;Another solution to remote persistant IRC is to run an IRC proxy server or bouncer, and point a regular IRC client at that. These either don't support backbuffer refills, or save and replay events, possibly by prefixing timestamps in the message text. They suffer many shortcomings by being a hacked-on proxy in front of an existing IRC client, which overall doesn't really support the disconnect/reconnect model. These solutions almost exclusively are also IRC-specific, and cannot integrate non-IRC (such as Instant Messaging) alongside.&lt;br /&gt;&lt;br /&gt;Right now this is pretty-much all there is to it, though the design is such that it can accommodate much more. There's also a plain telnet-alike backend module, but it could quite easily accept Instant Messaging, Email, PIM, whatever. Right now, the only frontend is GTK, but nothing says one couldn't also be written for Qt, Windows, or any other GUI toolkit. I'm also slowly in the process of writing a terminal-mode one.&lt;br /&gt;&lt;br /&gt;The code is available on CPAN:&lt;ul&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/dist/circle-be/"&gt;Circle&lt;/a&gt; (backend)&lt;/li&gt;&lt;li&gt;&lt;a href="http://search.cpan.org/dist/circle-fe-gtk/"&gt;Circle-FE-Gtk&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;Patches, they say, are Welcome.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-4054148353600498179?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/4054148353600498179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/07/my-current-perl-project-circle.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4054148353600498179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/4054148353600498179'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/07/my-current-perl-project-circle.html' title='My current Perl project - Circle'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-2119538308131714323</id><published>2010-07-01T22:39:00.000+01:00</published><updated>2010-07-01T22:42:01.249+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async::SSL'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Good code, bad tests</title><content type='html'>I've been working on &lt;a href="http://search.cpan.org/~pevans/IO-Async-SSL-0.02/"&gt;IO::Async::SSL&lt;/a&gt; recently. Both the previous upload, and the next one I shall shortly do, are fixes for failing smoke tests. Moreover, they're fixes for failing tests, of correct code.&lt;br /&gt;&lt;br /&gt;The first concerns the semantics of the &lt;tt&gt;END&lt;/tt&gt; block. The code looked roughly like&lt;pre&gt;use Test::More&lt;br /&gt;system( 'socat -help' ) == 0 or plan skip_all =&gt; "No socat";&lt;br /&gt;plan tests =&gt; 3;&lt;br /&gt;&lt;br /&gt;open my $kid, "-|", "socat", .... or die;&lt;br /&gt;END { kill TERM =&gt; $kid }&lt;/pre&gt;The idea of this code was to ensure that &lt;tt&gt;socat&lt;/tt&gt; is no longer running when the test exits. Of course, if the &lt;tt&gt;socat&lt;/tt&gt; program isn't installed, the entire test is skipped. And the &lt;tt&gt;END&lt;/tt&gt; block is still run. The result of this is that since &lt;tt&gt;$kid&lt;/tt&gt; is undefined, the containing &lt;tt&gt;perl&lt;/tt&gt; process is sent &lt;tt&gt;SIGTERM&lt;/tt&gt; instead, and the test harness exits with an error. Ooops.&lt;br /&gt;&lt;br /&gt;Now what I actually wanted here was&lt;pre&gt;END { kill TERM =&gt; $kid if defined $kid }&lt;/pre&gt;I wonder if this situation would warrant a new block-alike, perhaps lets call it &lt;tt&gt;ENDX&lt;/tt&gt;, which is only executed at &lt;tt&gt;END&lt;/tt&gt; time if the line declaring it was actually reached in code. Perhaps it can be hacked up by&lt;pre&gt;my @ends;&lt;br /&gt;sub ENDX(&amp;) {&lt;br /&gt;   push @ends, $_[0];&lt;br /&gt;}&lt;br /&gt;END { $_-&gt;() for @ends }&lt;br /&gt;...&lt;br /&gt;ENDX { kill TERM =&gt; $kid };&lt;/pre&gt;The second failure is a curious one that starts off looking like an OS-specific bug in the code. All the Linux smoke boxes were giving fails on a particularly innocent-looking test&lt;pre&gt;is( $client-&gt;peeraddr, $server-&gt;sockaddr, 'Client socket address' );&lt;/pre&gt;Under closer inspection, it seems that the way Linux returns socket addresses from the kernel doesn't initialise the "holes" in the address structure, whereas most other OSes do.&lt;br /&gt;&lt;br /&gt;The result of this is that rendered as strings of bytes, the two addresses don't necessarily contain all the same bytes as each other, even though they represent the same address. The way to fix this one is to unpack the addresses, known to be &lt;tt&gt;AF_INET&lt;/tt&gt; addresses, and use &lt;tt&gt;is_deeply&lt;/tt&gt; instead:&lt;pre&gt;use Socket qw( unpack_sockaddr_in );&lt;br /&gt;&lt;br /&gt;is_deeply( [ unpack_sockaddr_in $client-&gt;peeraddr ],&lt;br /&gt;           [ unpack_sockaddr_in $server-&gt;sockaddr ],&lt;br /&gt;           'Client socket address' );&lt;/pre&gt;This doesn't look too neat this way, but perhaps there's some scope for considering a &lt;tt&gt;Test::Sockaddr&lt;/tt&gt; module or somesuch, to neaten it up. Perhaps a little special-purpose though..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-2119538308131714323?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/2119538308131714323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/06/good-code-bad-tests.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/2119538308131714323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/2119538308131714323'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/06/good-code-bad-tests.html' title='Good code, bad tests'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-1136507281008637563</id><published>2010-06-03T12:57:00.004+01:00</published><updated>2010-06-03T13:08:21.103+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Why you should never use indirect object notation</title><content type='html'>On the subject of indirect object notation, &lt;a href="http://use.perl.org/~kappa/journal/40374"&gt;kappa writes&lt;/a&gt; "Do not use it when it causes problems".&lt;br /&gt;&lt;br /&gt;It always causes problems.&lt;pre&gt;$ perl -MO=Deparse -e 'package Container;&lt;br /&gt;  sub new { shift-&gt;BUILD }&lt;br /&gt;  sub BUILD { my $contained = new Contained() }'&lt;br /&gt;package Container;&lt;br /&gt;sub new {&lt;br /&gt;    shift(@_)-&gt;BUILD;&lt;br /&gt;}&lt;br /&gt;sub BUILD {&lt;br /&gt;    my $contained = new(Contained());&lt;br /&gt;}&lt;br /&gt;-e syntax OK&lt;/pre&gt;What you meant, perhaps, was&lt;pre&gt;$ perl -MO=Deparse -e 'package Container;&lt;br /&gt;  sub new { shift-&gt;BUILD }&lt;br /&gt;  sub BUILD { my $contained = Contained-&gt;new() }'&lt;br /&gt;package Container;&lt;br /&gt;sub new {&lt;br /&gt;    shift(@_)-&gt;BUILD;&lt;br /&gt;}&lt;br /&gt;sub BUILD {&lt;br /&gt;    my $contained = 'Contained'-&gt;new;&lt;br /&gt;}&lt;br /&gt;-e syntax OK&lt;/pre&gt;Basically, indirect notation breaks any time you're actually writing an object class. If you start indirectly invoking constructors (likely), you'll accidentally hit your own. Any time you go adding a new method to your own class - bang; you've just broken any indirect calls to that named method on any other object you'd be using. That sounds &lt;em&gt;excessively&lt;/em&gt; fragile to me. Code that used to mean one thing suddenly means a different thing when you add seemingly-unrelated code in another place. Fragile breakage by action-at-a-distance. It even depends on the order of the source code:&lt;pre&gt;$ perl -MO=Deparse -e 'package Container;&lt;br /&gt;  sub BUILD { my $contained = new Contained() }&lt;br /&gt;  sub new { shift-&gt;BUILD }'&lt;br /&gt;package Container;&lt;br /&gt;sub BUILD {&lt;br /&gt;    my $contained = 'Contained'-&gt;new;&lt;br /&gt;}&lt;br /&gt;sub new {&lt;br /&gt;    shift(@_)-&gt;BUILD;&lt;br /&gt;}&lt;br /&gt;-e syntax OK&lt;/pre&gt;And given probably most of the time you're writing code, you're writing objects, right? Even if the function you're writing currently isn't in an object class, it probably uses objects. Maybe one day you'll decide that function is useful in an object, so you'll copypaste that code elsewhere. This probably means most of your code ought not use indirect notation. If already most of it isn't using it, just get out of the habit NOW, before it is too late, and pretend that indirect notation does not exist at all. You'll save yourself a lot of pain later on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-1136507281008637563?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/1136507281008637563/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/06/why-you-should-never-use-indirect.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1136507281008637563'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1136507281008637563'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/06/why-you-should-never-use-indirect.html' title='Why you should never use indirect object notation'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-7688400357034105808</id><published>2010-05-27T16:48:00.004+01:00</published><updated>2010-08-05T14:34:59.393+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>Weasels in the Code</title><content type='html'>I've recently written the following utility method on an object:&lt;br /&gt;&lt;pre&gt;sub _capture_weakself&lt;br /&gt;{&lt;br /&gt;   my $self = shift;&lt;br /&gt;   my ( $code ) = @_;   # actually bare method names work too&lt;br /&gt;&lt;br /&gt;   weaken $self;&lt;br /&gt;&lt;br /&gt;   return sub { $self-&gt;$code( @_ ) };&lt;br /&gt;}&lt;/pre&gt;It's quite a useful little method for creating a new CODE ref around either a given code ref, or a method on the object. This CODE ref captures a reference to the object, passing it as the first argument. This makes it useful for passing around elsewhere, perhaps as an event callback (as it happens, this method lives in &lt;tt&gt;&lt;a href="http://search.cpan.org/perldoc?IO::Async::Notifier"&gt;IO::Async::Notifier&lt;/a&gt;&lt;/tt&gt;). Because the object ref is stored weakly in this closure, it means the returned closure can safely be stored in the object itself without creating a cycle.&lt;br /&gt;&lt;br /&gt;It's sufficiently useful that I feel sure this technique must have a name, but so far I'm failing to find one. I manage to keep reading the name here as "capture weasel". This gives me an idea - perhaps it could be said this closure has been weaseled; short for wea(k)sel(f)ed.&lt;br /&gt;&lt;pre&gt;my $weasled_code = $notifier-&gt;_capture_weakself( sub {&lt;br /&gt;     my $self = shift;&lt;br /&gt;     my ( $x, $y ) = @_;&lt;br /&gt;     ....&lt;br /&gt;} );&lt;br /&gt;&lt;br /&gt;$weaseled_code-&gt;( 123, 456 );&lt;/pre&gt;What does anyone think here? Does this technique have a name already? If not; does this seem suitable? I find it unlikely this name already exists somewhere else in CompSci (&lt;a href="http://foldoc.org/weasel"&gt;FOLDOC&lt;/a&gt; doesn't have a use in this sense), so it would be a good unique name...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-7688400357034105808?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/7688400357034105808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/05/weasels-in-code.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/7688400357034105808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/7688400357034105808'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/05/weasels-in-code.html' title='Weasels in the Code'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-5332165293308190349</id><published>2010-05-18T19:10:00.010+01:00</published><updated>2010-05-18T20:26:49.893+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sockets'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='IPv6'/><category scheme='http://www.blogger.com/atom/ns#' term='BPF'/><category scheme='http://www.blogger.com/atom/ns#' term='ironman'/><title type='text'>PF_PACKET, Linux Socket Filters, and IPv6</title><content type='html'>For diagnosing network-related problems, it's often useful to be able to capture packets transmitted or received by a machine. Linux implements a socket family, &lt;tt&gt;PF_PACKET&lt;/tt&gt;, to this end. Sockets in this family receive raw datagrams containing packets received or transmitted on network interfaces. A network capture program creates such a socket, then sits in a loop receiving datagrams. Each datagram contains the bytes of the packet. The &lt;tt&gt;AF_PACKET&lt;/tt&gt; address format gives information about, among other things, packet direction and interface number.&lt;br /&gt;&lt;br /&gt;In situations where a machine is passing lots of traffic, such as a busy internet router, but the problem being diagnosed concerns only a narrow selection of this traffic, capturing every single packet would be very CPU-intensive. The application could inspect each packet and discard all of those not of interest to it. But since each packet requires a &lt;tt&gt;recvfrom(2)&lt;/tt&gt; system call, this gets quite expensive in context switches, and wasted buffer space. A far more efficient scheme is to have the kernel filter the packets, or at least throw away most of the uninteresting ones.&lt;br /&gt;&lt;br /&gt;In Linux, this is done using the &lt;tt&gt;SO_ATTACH_FILTER&lt;/tt&gt; socket option. This option attaches a filter program, which executes on a simple virtual machine within the kernel. This machine is given access to inspect the bytes of the packet, and can return a value indicating whether the packet should be kept, or discarded. This machine is based on BSD's BPF mechanism, with some extensions.&lt;br /&gt;&lt;br /&gt;This virtual machine is a register machine. It has a single accumulator (&lt;tt&gt;A&lt;/tt&gt;), a single index register (&lt;tt&gt;X&lt;/tt&gt;), and the various usual sorts of arithmetic and logical operations one would expect. To inspect the actual packet contents it has instructions to load data from the captured packet, in 8, 16, or 32bit unsigned quantities, into the accumulator. The program gives its answer by returning a number to the kernel, which should be the number of bytes of the packet to capture, or 0 to discard it entirely.&lt;br /&gt;&lt;br /&gt;For example, lets consider the following example, which selects any TCP packets:&lt;br /&gt;&lt;pre&gt;LD BYTE[9]&lt;br /&gt;JEQ 6, 0, 2&lt;br /&gt;&lt;br /&gt;LD len&lt;br /&gt;RET A&lt;br /&gt;&lt;br /&gt;RET 0&lt;/pre&gt;The &lt;tt&gt;LD BYTE[offs]&lt;/tt&gt; instruction loads a byte from the packet (at offset 9, being where IPv4 headers keep their protocol number) into the &lt;tt&gt;A&lt;/tt&gt; register. &lt;tt&gt;JEQ&lt;/tt&gt; is a conditional jump instruction which compares the &lt;tt&gt;A&lt;/tt&gt; register to the immediate constant (6, the protocol number of TCP). If they are equal it jumps to the first label; if not, the second. Both jump labels are unsigned integers, being the number of instructions forwards to skip. In the true case (i.e. the protocol is TCP), the length of the packet is loaded into the accumulator and returned from the filter. In the false case, the number 0 is returned, to discard the packet.&lt;br /&gt;&lt;br /&gt;Of course, this filter isn't much use yet, because we don't know for sure it's even an IPv4 packet we've caught. The original BSD BPF doesn't define any metadata access scheme, so Linux has invented a way for programs to access this. It reserves the topmost 4KiB of packet buffer, to provide some virtual "registers" containing metadata. Since the load instruction offsets are 32bit integers, it is unlikely any real packet would ever be anywhere near this size, so in practice this works well.&lt;br /&gt;&lt;br /&gt;In this extra data area, called the Ancillary Data, the first offset stores the ethertype of the packet (this field address has a symbolic name, &lt;tt&gt;SKF_AD_PROTOCOL&lt;/tt&gt;). In IPv4's case, this will be 0x0800. We can extend our filter to look at this protocol number (not to be confused with IPv4's protocol field), and check it.&lt;br /&gt;&lt;pre&gt;LD WORD[AD_PROTOCOL]&lt;br /&gt;JEQ 0x0800, 0, 4&lt;br /&gt;&lt;br /&gt;LD BYTE[9]&lt;br /&gt;JEQ 6, 0, 2&lt;br /&gt;&lt;br /&gt;LD len&lt;br /&gt;RET A&lt;br /&gt;&lt;br /&gt;RET 0&lt;/pre&gt;We can further extend our filter, looking only for a certain TCP port number (such as 80, for http). Presuming an IPv4 header with no extra options, it is 20 bytes long, and therefore, the TCP header will start at offset 20:&lt;br /&gt;&lt;pre&gt;LD WORD[AD_PROTOCOL]&lt;br /&gt;JEQ 0x0800, 0, 8&lt;br /&gt;&lt;br /&gt;LD BYTE[9]&lt;br /&gt;JEQ 6, 0, 6&lt;br /&gt;&lt;br /&gt;LD HALF[20]&lt;br /&gt;JEQ 22, 2, 0&lt;br /&gt;LD HALF[22]&lt;br /&gt;JEQ 22, 0, 2&lt;br /&gt;&lt;br /&gt;LD len&lt;br /&gt;RET A&lt;br /&gt;&lt;br /&gt;RET 0&lt;/pre&gt;Of course, this filter isn't much use in the real world, because we made the rather large assumption that an IPv4 header would be 20 bytes long. This is where the index register becomes useful. We can load the index register, &lt;tt&gt;X&lt;/tt&gt;, with the size of the IPv4 header, and access the TCP header relative to this. BPF provides a very special instruction, &lt;tt&gt;LDMSHX&lt;/tt&gt;, for exactly this purpose. Given the address of a byte, it loads that byte, masking off the bottom 4 bits, and shifts up by 2 bits. This calculates the size in bytes of an IPv4 header, given the first byte.&lt;br /&gt;&lt;pre&gt;LD WORD[AD_PROTOCOL]&lt;br /&gt;JEQ 0x0800, 0, 9&lt;br /&gt;&lt;br /&gt;LD BYTE[9]&lt;br /&gt;JEQ 6, 0, 7&lt;br /&gt;&lt;br /&gt;LDMSHX BYTE[0]&lt;br /&gt;LD HALF[X+0]&lt;br /&gt;JEQ 22, 2, 0&lt;br /&gt;LD HALF[X+2]&lt;br /&gt;JEQ 22, 0, 2&lt;br /&gt;&lt;br /&gt;LD len&lt;br /&gt;RET A&lt;br /&gt;&lt;br /&gt;RET 0&lt;/pre&gt;Finally, this filter is only of any use on a &lt;tt&gt;SOCKET_DGRAM&lt;/tt&gt; socket; a socket where the kernel will throw away the link-level header (such as the Ethernet or PPP framing), and present only the network-level header. A packet capturing program would very likely be interested in those link-level bytes too, so would be using a &lt;tt&gt;SOCKET_RAW&lt;/tt&gt; socket instead. In this case, we don't directly know the offset of the IPv4 header, but once again, Linux comes to our rescue. It provides a "virtual view" over the part of the packet from the start of the network header. It provides a virtual offset, &lt;tt&gt;NET&lt;/tt&gt;, where load instructions read relative to the start of the network header, rather than from the start of the packet buffer as a whole.&lt;br /&gt;&lt;br /&gt;On a &lt;tt&gt;SOCKET_RAW&lt;/tt&gt; socket, this filter would probably be appropriate to select TCP port 80 over IPv4:&lt;br /&gt;&lt;pre&gt;LD WORD[AD_PROTOCOL]&lt;br /&gt;JEQ 0x0800, 0, 9&lt;br /&gt;&lt;br /&gt;LD BYTE[NET+9]&lt;br /&gt;JEQ 6, 0, 7&lt;br /&gt;&lt;br /&gt;LDMSHX BYTE[NET+0]&lt;br /&gt;LD HALF[NET+X+0]&lt;br /&gt;JEQ 22, 2, 0&lt;br /&gt;LD HALF[NET+X+2]&lt;br /&gt;JEQ 22, 0, 2&lt;br /&gt;&lt;br /&gt;LD len&lt;br /&gt;RET A&lt;br /&gt;&lt;br /&gt;RET 0&lt;/pre&gt;This is internally implemented by carving up a further extra data area, 1MiB from the top of the packet buffer (defined by a constant &lt;tt&gt;SKF_NET_OFF&lt;/tt&gt;). This offset gives a virtual view of the bytes in the packet, starting at the network protocol header.&lt;br /&gt;&lt;br /&gt;Of course, I have been looking IPv4 quite specifically here. With the slowly-growing popularity of IPv6, it's inevitable that packet capture programs might want to capture IPv6 packets too.&lt;br /&gt;&lt;br /&gt;IPv6 follows a different style from IPv4 in terms of its header options. In IPv4, all the IP-level options are stored in the header, one after another. The "header length" field in the header gives the total size of the header, with all these options. In IPv6, the header contains fewer fields (because things like fragmentation are now options). At the end of this header is the "next header" number, which is either a protocol number such as TCP or UDP, or gives an IPv6 extension header number (such as fragmentation control, or IPsec's authenticating header). Each option links on to the next with its own "next header" field.&lt;br /&gt;&lt;br /&gt;This presents us something of a problem when it comes to packet capture filters. Recall how, for the &lt;tt&gt;JEQ&lt;/tt&gt; instruction, the branch labels in both cases are unsigned integers? This is how BPF guarantees termination of a program in finite time - every jump has to be forwards. There can be no loops. Without loops, the program is guaranteed to terminate.&lt;br /&gt;&lt;br /&gt;But now how do we parse these IPv6 headers? We can't write a while() loop in the program to walk down the headers, until we find a TCP one. Furtheremore, IPv6 doesn't define a standard header layout for all headers. Each header type puts its "next header" field in possibly a different place. Some headers are fixed-length, some carry a "header length" field of their own. It's a total mess, from the point of view of packet filtering.&lt;br /&gt;&lt;br /&gt;What I would propose, is to create two new metadata constants:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;A new Ancillary Data area field, &lt;tt&gt;SKF_AD_TRANSPROTO&lt;/tt&gt; to store the transport level protocol.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;A new data area offset, &lt;tt&gt;SKF_TRANS_OFF&lt;/tt&gt;, to give a virtual view of the transport header.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;This will allow us to very easily write a packet filter to capture TCP port 80, say, agnostic of IPv4 or IPV6. The filter program would look like:&lt;br /&gt;&lt;pre&gt;LD WORD[AD_PROTOCOL]&lt;br /&gt;JEQ 0x0800, 9, 0&lt;br /&gt;JEQ 0x86dd, 0, 8&lt;br /&gt;&lt;br /&gt;LD WORD[AD_TRANSPROTO]&lt;br /&gt;JEQ 6, 0, 6&lt;br /&gt;&lt;br /&gt;LD HALF[TRANS+0]&lt;br /&gt;JEQ 22, 2, 0&lt;br /&gt;LD HALF[TRANS+2]&lt;br /&gt;JEQ 22, 0, 2&lt;br /&gt;&lt;br /&gt;LD len&lt;br /&gt;RET A&lt;br /&gt;&lt;br /&gt;RET 0&lt;/pre&gt;We've now created a filter which can detect the transport protocol of TCP, and inspect the transport header, without having to directly calculate its offset from hard-coded knowledge of the network protocol.&lt;br /&gt;&lt;br /&gt;I would like to propose that Linux adopts these two constants, and finds a way to implement them. I have some thoughts on implementation but I will defer these to a later post; as this one has gone on quite long enough already. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-5332165293308190349?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/5332165293308190349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/05/pfpacket-linux-socket-filters-and-ipv6.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5332165293308190349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5332165293308190349'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/05/pfpacket-linux-socket-filters-and-ipv6.html' title='PF_PACKET, Linux Socket Filters, and IPv6'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-1844691602704614075</id><published>2010-04-30T22:18:00.006+01:00</published><updated>2010-04-30T22:40:31.902+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='ExtUtils::H2PM'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl - ExtUtils::H2PM</title><content type='html'>I've spent a lot of time lately writing modules that wrap Linux kernel features in some way or another. They all boil down to basically the same thing - export a bunch of constants, and structure packing/unpacking functions. Various bits of extra fancy interface code are sometimes nice, but most of the time these can be written in Pure Perl once the base bits are done.&lt;br /&gt;&lt;br /&gt;It's always annoyed me that one has to write an XS module just to obtain these. It's a lot of extra work and bother, for something that ought to be so simple. So instead, I started thinking about it, how can I make this much simpler from Perl?&lt;br /&gt;&lt;br /&gt;What I came up with is &lt;a href="http://search.cpan.org/dist/ExtUtils-H2PM/"&gt;ExtUtils::H2PM&lt;/a&gt;; a module to make it trivially-easy to write this sort of boring module to wrap some constants and structures from OS's header files.&lt;br /&gt;&lt;br /&gt;As a brief example, consider the following&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;use ExtUtils::H2PM;&lt;br /&gt;&lt;br /&gt;module "Fcntl";&lt;br /&gt;&lt;br /&gt;include "fcntl.h";&lt;br /&gt;&lt;br /&gt;constant "O_RDONLY";&lt;br /&gt;&lt;br /&gt;write_output $ARGV[0];&lt;/pre&gt;&lt;br /&gt;This is it. This is all the code you, as a module author, have to write. You store that in some file, lets call it &lt;tt&gt;Fcntl.pm.PL&lt;/tt&gt;. You let the build system go about converting that into &lt;tt&gt;Fcntl.pm&lt;/tt&gt;; which on my system now looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;package Fcntl;&lt;br /&gt;# This module was generated automatically by ExtUtils::H2PM from -e&lt;br /&gt;&lt;br /&gt;push @EXPORT_OK, 'O_RDONLY';&lt;br /&gt;use constant O_RDONLY =&gt; 0;&lt;br /&gt;&lt;br /&gt;1;&lt;/pre&gt;&lt;br /&gt;This is a plain standard Perl module that can be installed and used, to provide that constant.&lt;br /&gt;&lt;br /&gt;We can also create pack/unpack-style functions to wrap structure types too. Consider&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;use ExtUtils::H2PM;&lt;br /&gt;&lt;br /&gt;module "Time";&lt;br /&gt;&lt;br /&gt;include "time.h";&lt;br /&gt;&lt;br /&gt;structure "struct timespec",&lt;br /&gt;  members =&gt; [&lt;br /&gt;    tv_sec  =&gt; member_numeric,&lt;br /&gt;    tv_nsec =&gt; member_numeric,&lt;br /&gt;  ];&lt;br /&gt;&lt;br /&gt;write_output $ARGV[0];&lt;/pre&gt;&lt;br /&gt;For this we obtain:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;package Time;&lt;br /&gt;# This module was generated automatically by ExtUtils::H2PM from -e&lt;br /&gt;&lt;br /&gt;use Carp;&lt;br /&gt;push @EXPORT_OK, 'pack_timespec', 'unpack_timespec';&lt;br /&gt;&lt;br /&gt;sub pack_timespec&lt;br /&gt;{&lt;br /&gt;   @_ == 2 or croak "usage: pack_timespec(tv_sec, tv_nsec)";&lt;br /&gt;   my @v = @_;&lt;br /&gt;   pack "q q ", @v;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;sub unpack_timespec&lt;br /&gt;{&lt;br /&gt;   length $_[0] == 16 or croak "unpack_timespec: expected 16 bytes";&lt;br /&gt;   my @v = unpack "q q ", $_[0];&lt;br /&gt;   @v;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;1;&lt;/pre&gt;&lt;br /&gt;This was done entirely automatically too.&lt;br /&gt;&lt;br /&gt;In a real use-case, you'd be using this to wrap things like socket option constants/structures, and so on; cases where existing Perl functions wrap existing syscalls, you simply want to provide new option values or structures. I've now written several modules mostly or entirely relying on &lt;tt&gt;ExtUtils::H2PM&lt;/tt&gt; to build them, freeing me of having to write all that XS code to implement them.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://search.cpan.org/dist/Linux-SocketFilter/"&gt;Linux::SocketFilter&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://search.cpan.org/dist/Socket-Netlink/"&gt;Socket::Netlink&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://search.cpan.org/dist/Socket-Netlink-Route/"&gt;Socket::Netlink::Route&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;a href="http://search.cpan.org/dist/Socket-Netlink-Taskstats/"&gt;Socket::Netlink::Taskstats&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-1844691602704614075?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/1844691602704614075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/04/perl-extutilsh2pm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1844691602704614075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/1844691602704614075'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/04/perl-extutilsh2pm.html' title='Perl - ExtUtils::H2PM'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-162101569525574265</id><published>2010-04-26T16:20:00.005+01:00</published><updated>2010-04-26T16:59:47.815+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='YAML'/><title type='text'>Order matters even when it doesn't</title><content type='html'>Revision control diffs are most readable when they aren't noisy. Operations that disturb the order of many lines in the file create noise which makes it hard to read the interesting change. YAML specifies mappings (hashes, to us perl-types), that are unordered associations of keys to values. Even though YAML doesn't put an ordering on those, sometimes we'd like to pretend that it does, so as to preserve the order when we load a file, edit the data, then dump it back to the file.&lt;br /&gt;&lt;br /&gt;At work we store a YAML document in Subversion, which describes a lot of details about IPsec tunnels. In an ideal world this would be the initial source of the information. The world, as you may have observed, is not yet ideal, so this file is in fact back-scraped from information in the actual config files, to keep it up to date. Naturally that's done in Perl.&lt;br /&gt;&lt;br /&gt;The YAML file stores a big mapping, each entry itself being a record-like mapping, containing details in named keys. This causes great trouble for our load/edit/dump script, because YAML doesn't specify an ordering in mapping keys. They'll be dumped in "no particular order".&lt;br /&gt;This wouldn't normally be a problem, except that because it's stored in Subversion, a commit changing one line of actual detail might suddenly produce hundreds of lines of false diff, because of reordered keys.&lt;br /&gt;&lt;br /&gt;To solve this, I had to apply Much Evil Hackery. The YAML Perl module, it turns out, has a data structure tied to a hash, which remembers the order of keys. By subclassing YAML::Loader and replacing its method to read a mapping into a hash ref, we can force it to use this structure instead. This alteration is transparent to the perl code inbetween, it just sees a normal hash. However, YAML::Dumper sees the ordering and preserves it when it writes out.&lt;br /&gt;&lt;br /&gt;The upshot: Load/edit/dump of trees of mappings in YAML preserves ordering, allowing cleaner commits into revision control.&lt;br /&gt;&lt;br /&gt;This has been suggested as a wishlist bug against YAML; see also &lt;a href="https://rt.cpan.org/Ticket/Display.html?id=56741"&gt;https://rt.cpan.org/Ticket/Display.html?id=56741&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-162101569525574265?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/162101569525574265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/04/order-matters-even-when-it-doesnt.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/162101569525574265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/162101569525574265'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/04/order-matters-even-when-it-doesnt.html' title='Order matters even when it doesn&apos;t'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-5652063772229300310</id><published>2010-04-06T11:33:00.006+01:00</published><updated>2010-04-06T12:07:36.429+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ironman'/><title type='text'>Why I won't tell you what to do</title><content type='html'>Often in #perl we get people asking a question, whether explicitly or implied, that requires us to pick a solution for them. I try hard not to do this. The closest I'll get is to listen to their description of the problem, and suggest some things which I think might help. Hardly ever do I suggest just one thing.&lt;br /&gt;&lt;br /&gt;I do this because it's hard for us to know the entire surrounding context of a problem. If anyone else is like me, then there'll be days, weeks, maybe even months of history behind it; various attempts they've tried already, other bits and pieces of code, system, whatever, that they haven't been able to explain in the 5 minutes they tried to give us the problem. You can't explain a 1-month problem in 5-minutes, nor can I give a solution to it in similar timeframe.&lt;br /&gt;&lt;br /&gt;What I can do is name a few things that I'd include in a shortlist of things to think about in more detail, were I to find myself with a similar problem. They can then go away and think about these things. Maybe he already was aware of them, and we've just given some more confidence that those might be correct. Or maybe he wasn't, so we've given him something new to read about. Either way, we've helped guide the decision process, without outright saying "thou shalt do this" - because, without having that month of context around it; for all we know it could be completely wrong. But it's a good start.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-5652063772229300310?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/5652063772229300310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/04/why-i-wont-tell-you-what-to-do.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5652063772229300310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5652063772229300310'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/04/why-i-wont-tell-you-what-to-do.html' title='Why I won&apos;t tell you what to do'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9112560338291574360.post-5020137580559344954</id><published>2010-03-31T08:30:00.000+01:00</published><updated>2010-03-31T08:30:37.783+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='IO::Async'/><title type='text'>Perl - IO::Async</title><content type='html'>&lt;a href="http://search.cpan.org/dist/IO-Async/"&gt;IO::Async&lt;/a&gt; is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a Perl module distribution&lt;br /&gt;&lt;/li&gt;&lt;li&gt;a generic eventing framework&lt;/li&gt;&lt;li&gt;suitable for all kinds of IO-bound tasks&lt;/li&gt;&lt;li&gt;a way to achieve IO concurrency&lt;/li&gt;&lt;li&gt;portable to Linux, Solaris, BSDs, other POSIXes&lt;br /&gt;&lt;/li&gt;&lt;li&gt;mostly-working on cygwin&lt;/li&gt;&lt;li&gt;able to use OS-specific optimisations where appropriate&lt;/li&gt;&lt;li&gt;able to use Glib for running GTK2-based GUI applications&lt;/li&gt;&lt;/ul&gt;IO::Async serves as a base layer for all kinds of IO-heavy programs.&lt;br /&gt;&lt;br /&gt;Its design is centred around passing code references as continuations; handlers to invoke when a certain event happens, or after a certain operation has completed. By relying on lexical variable capture in these code references, these continuations can easily store state in normal variables.&lt;br /&gt;&lt;br /&gt;It's a different approach than that taken by POE, the other eventing system for Perl, but I find this approach fits better in my head. If you dislike storing state in a hash to pass it around disjoint named functions loosely connected by event names, you might just want to give it a try...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9112560338291574360-5020137580559344954?l=leonerds-code.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://leonerds-code.blogspot.com/feeds/5020137580559344954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://leonerds-code.blogspot.com/2010/03/perl-ioasync.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5020137580559344954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9112560338291574360/posts/default/5020137580559344954'/><link rel='alternate' type='text/html' href='http://leonerds-code.blogspot.com/2010/03/perl-ioasync.html' title='Perl - IO::Async'/><author><name>LeoNerd</name><uri>http://www.blogger.com/profile/06161372680495361467</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_dfG4RsRKyjs/S7LjP8b_ieI/AAAAAAAAAAM/WQTFByqtOZI/S220/PEVANS.jpg'/></author><thr:total>0</thr:total></entry></feed>
