2010. 11. 29
Devel::Declare, Method::Signatures, oh my
Actually, I got another inspiration from Method::Signatures, for use with CGI::Application.
But while implementing that, I decided to extract the hard Devel::Declare bits, and make a macro installer.
Here’s a re-implementation of Method::Signatures using my Devel::Declare::Macro:
package Method::Signatures;
use Devel::Declare::Macro;
sub import {
install_macro(
into => scalar(caller),
name => 'method',
proto_parser => \&make_proto_unwrap,
proto_injector => \&inject_from_signature
);
}
sub make_proto_unwrap {} # as before, except return \%signature
sub inject_from_signature {} # as before
1;
I’m somewhat confident it could simplify the implementation of Sub::Curried and MooseX::Method::Signatures as well.
Basically it packages the synopsis of Devel::Declare. As such, I don’t think I should maintain it. Comments welcome.
package Devel::Macro;
sub import {
my $class = shift;
my $pkg = caller;
no strict 'refs';
*{$pkg.'::install_macro'} = \&install_macro;
}
# Stolen from Devel::Declare's t/method-no-semi.t
use Devel::Declare ();
use Scope::Guard;
use Sub::Name;
sub install_macro {
my %args = @_;
# I don't really understand why we need to declare method
# in the caller's namespace.
{
no strict 'refs';
*{$args{into}.'::'.$args{name}} = sub (&) {};
}
Devel::Declare->setup_for(
$args{into},
{ $args{name} => {
const => mk_parser(
$args{proto_parser}||sub{''},
$args{proto_injector}||sub{join' ', @_},
$args{pre_install}||sub{},
)
},
},
);
}
our ($Declarator, $Offset);
sub skip_declarator {
$Offset += Devel::Declare::toke_move_past_token($Offset);
}
sub skipspace {
$Offset += Devel::Declare::toke_skipspace($Offset);
}
sub strip_name {
skipspace;
if (my $len = Devel::Declare::toke_scan_word($Offset, 1)) {
my $linestr = Devel::Declare::get_linestr();
my $name = substr($linestr, $Offset, $len);
substr($linestr, $Offset, $len) = '';
Devel::Declare::set_linestr($linestr);
return $name;
}
return;
}
sub strip_proto {
skipspace;
my $linestr = Devel::Declare::get_linestr();
if (substr($linestr, $Offset, 1) eq '(') {
my $length = Devel::Declare::toke_scan_str($Offset);
my $proto = Devel::Declare::get_lex_stuff();
Devel::Declare::clear_lex_stuff();
$linestr = Devel::Declare::get_linestr();
substr($linestr, $Offset, $length) = '';
Devel::Declare::set_linestr($linestr);
return $proto;
}
return;
}
sub shadow {
my $pack = Devel::Declare::get_curstash_name;
Devel::Declare::shadow_sub("${pack}::${Declarator}", $_[0]);
}
sub inject_if_block {
my $inject = shift;
skipspace;
my $linestr = Devel::Declare::get_linestr;
if (substr($linestr, $Offset, 1) eq '{') {
substr($linestr, $Offset+1, 0) = $inject;
Devel::Declare::set_linestr($linestr);
}
}
sub scope_injector_call {
return ' BEGIN { ' . __PACKAGE__ . '::inject_scope }; ';
}
sub mk_parser {
my $proto_parser = shift;
my $proto_injector = shift;
my $install_cb = shift;
return sub {
local ($Declarator, $Offset) = @_;
skip_declarator;
my $name = strip_name;
my $proto = strip_proto;
my @decl = $proto_parser->($proto);
my $inject = $proto_injector->(@decl);
if (defined $name) {
$inject = scope_injector_call().$inject;
}
inject_if_block($inject);
if (defined $name) {
$name = join('::', Devel::Declare::get_curstash_name(), $name)
unless ($name =~ /::/);
}
shadow(sub (&) {
no strict 'refs';
my $code = shift;
$install_cb->($name, $code, \@decl);
# So caller() gets the subroutine name
*{$name} = subname $name => $code if defined $name;
});
};
}
sub inject_scope {
$^H |= 0x120000;
$^H{DD_METHODHANDLERS} = Scope::Guard->new(sub {
my $linestr = Devel::Declare::get_linestr;
my $offset = Devel::Declare::get_linestr_offset;
substr($linestr, $offset, 0) = ';';
Devel::Declare::set_linestr($linestr);
});
}
1;
No comments yet [ / programming / perl ] permalink
Some of my favorite applications
In no particular order, the following applications make my life so much easier:
- debian/ubuntu
- gaim
- galeon
- gnome
- liferea
- pan
- perl
- privoxy
- rhythmbox
- subversion
- thunderbird
- vim
No comments yet [ / software / favorites ] permalink
Email::MIME::* modules aren’t very close friends
The Email::*
modules are all pretty neat, with a pleasant API. But combining them isn’t always as effortless as you’d
expect.
For my email2blog script, I use Email::Filter as the bridge between the MTA and
blosxom:
# grab email from STDIN
my $mail = Email::Filter->new;
The $mail object has nifty methods that make it very simple to accept or reject a
message.
Once I accept a message, I take out the attachments with Email::MIME::Attachment::Stripper.
The first step is to construct a stripper based on the incoming email:
# make stripper
my $strip = Email::MIME::Attachment::Stripper->new(
Email::MIME->new( $mail->simple->as_string ),
force_filename => 1
);
I’m not impressed with the hoops I have to jump through there. It should be easy for
EMA::Stripper to build its own Email::MIME object when handed an
Email::Simple object. But in fact, even Email::MIME itself doesn’t offer that
option.
Next up is taking apart the MIME email:
# strip attachments
my $msg = $strip->message;
my @attachments = $strip->attachments;
That’s pretty straightforward. $msg is an Email::MIME object, without the
attachments. To get at the plaintext body is still not very comfortable:
# extract plaintext body
my $text = first { $_->content_type =~ m{text/plain} } $msg->parts;
Maybe that’s because there may not be a text/plain part with meaningful content, but I
wouldn’t expect $msg->body to be empty after the strip operation. It is though, so that fancy
grep is necessary.
The @attachments array on the other hand is very easy to work with. It has just the things
you need, and nothing else.
All in all, the script ended up being about 60 well-spaced lines long, with most of that being taken up by sanitizing the input. The fact that I didn’t actually have to think how MIME encoding works under the hood was a big plus, and for that I’m very happy with the PEP Project.
No comments yet [ / text / blosxom / email ] permalink
First impressions
I installed Blosxom today. Getting it up and running was a piece of cake. Finding useful plugins took a little longer, but I’m happy with the current set:
- categories, meta, directorybrowse, flavourdir
- MarkDown
- SmartyPants
I stole the layout from my Perl pages.
No comments yet [ / text / blosxom ] permalink
Test Driven Development and refactoring
On Safari Bookshelf:
- “Test-Driven Development By Example”, Kent Beck
- “Perl Testing: A Developer’s Notebook”, chromatic , Ian Langworth
- “Refactoring: Improving the Design of Existing Code”, Martin Fowler, Kent Beck et al
On PerlMonks:
- OT: TDD question
- TDD: a test drive and a confession
- TDD in Perl
- TDD with Coverage Analysis. Wow.
- Refactoring
Other books I’ve heard good things about:
- “Code Complete”, Second Edition, Steve McConnell
- “The Pragmatic Programmer: From Journeyman to Master”, Andrew Hunt, David Thomas
No comments yet [ / programming / references / refactoring ] permalink
Tidyhtml 0.01
Initial version
I’ve just written a tiny blosxom plugin that cleans up your html. It uses the 1.07_01 dev version of
HTML::Tidy, which in
turn uses libtidy.
Since this is the first ever version, I’m just going to paste it here. I’ll build a proper release later on.
# Blosxom Plugin: tidyhtml
# Author(s): Rhesa Rozendaal
# Version: 0.01
# URL: http://oss.rhesa.com/blog/text/blosxom/plugins/tidyhtml
package tidyhtml;
use strict;
# --- Configurable variables -----
my $tidy_config = {
tidy_mark => 'no',
wrap => '120',
indent => 'auto',
output_xhtml => 'yes',
char_encoding => 'utf8',
doctype => 'strict',
add_xml_decl => 'yes',
alt_text => 'photo',
};
# --------------------------------
use HTML::Tidy;
sub last {
# only operate on html content types.
return unless $blosxom::header->{-type} =~ /html/;
$blosxom::output = HTML::Tidy->new( $tidy_config )
->clean( $blosxom::output );
return;
}
sub start { 1 }
1;
No comments yet [ / text / blosxom / plugins / tidyhtml ] permalink
JavaScript-driven syntax highlighting
Based on a PerlMonks idea, I’ve added syntax highlighting on code blocks. The javascript is here, and the css here.
See this post for an example (you need javascript enabled for this).
No comments yet [ / text / blosxom ] permalink
Markdown
Markdown is neat.
No comments yet [ / text / formatting ] permalink
This time, with attachments

Let’s hear a “YAY!” :-)
No comments yet [ / text / blosxom / email ] permalink
A couple of Vim links
- Efficient Editing With vim - Jonathan McPherson
- Why, oh WHY, do those #?@! nutheads use vi?
- Search vim online tips by rating
Emacs is far too small to be a proper kitchen sink — david feuer
No comments yet [ / text / editing ] permalink