Wednesday, July 14, 2010

Catalyst $c->req->params sucks

Catalyst has added parameters() to its Catalyst::Request object and it allows you to get values in an array ref if there are multiple.



my $form = $c->request->parameters;

# ?a=b&b=c
# $form = { a => 'b', b => 'c' }
# ?a=b&a=c&b=c
# $form = { a => [ 'b', 'c' ], b => 'c' };



This might look intuitive but wait a minute. The data structure gets different per user input rather than how you code it, and that sucks. This means you have to always check if the value is an array ref or not, since:



my $v = $c->request->parameters;
my $query = $v->{query};
my @names = @{$v->{name}};



$query might become ARRAY(0xabcdef) if there are multiple query= parameters in the query. @names line might cause Can't use string as an ARRAY ref error if there's only one (or zero) name parameter. This causes horrible issues when using standard HTML elements like option or checkbox forms, or tools like jQuery's serialize().

The correct way to write that would be:



my $v = $c->request->parameters;
my $query = ref $v->{query} eq 'ARRAY' ? $v->{query}->[0] : $v->{query};
my @names = ref $v->{name} eq 'ARRAY' ? @{$v->{name}} : ($v->{name});



and it is tedious and gross.

Thursday, July 8, 2010

Real private method in Perl

For a truly private method, you would usually write the following:


my $_private_method = sub { my ($self, ...) = @_; ... };
...
$self->$_private_method($some, $arguments);
...


which makes the method scoped to the block it was defined in, or the file if it’s not within braces.

This is Perl.

The reason is $_private_method is not special, it's just a "my" variable. So it will be "invisible" outside block or file scope.