This is english blog, so people as minimum will be happy to see already translated version.
]]>$app->plugin( Auth => {
user_check => sub{
my( $user ) = @_;
# authentication_code_here;
},
);
But I prefer to keep my sturtup sub clean. Thus I route to controller’s action:
$app->plugin( Auth => { auth_check => 'auth#check' } );
Doing so I need to check in my plugin passed value. Is it sub or shortcut auth#check
?
And to simplify checking I implement next route shourtcut
sub register {
my( $plugin, $app, $conf ) = @_;
$app->routes->add_shortcut( xto => \&xto );
...
$app->routes->post ( '/auth' )->xto( $conf->{ auth_check } )
->name( 'authenticate' );
}
sub xto {
my $r = shift;
ref $_[0] eq 'CODE'?
$r->to({ cb => $_[0] }):
$r->to( @_ );
return $r;
}
Unfortunately this is not supported by core ->to
. I do not know why.
Finally when we create route we want bind it to some action. The callback and controller’s method are both actions: 1
my $cb = $field->{cb};
$self->_callback($c, $cb, $last);
...
_action($app, $c, $cb, $last);
and 2
$self->_controller($c, $field, $last);
my $method = $field->{action};
my $sub = $new->can($method);
...
_action($app, $new, $sub, $last);
Supporting this via ->to
interface seems natural, does not?
I discuss this on IRC. kraih was nor against, nor support that. Just not enough votes from other members.
]]>You should just use it in right place. By `unless` you should mark code which SHOULD NOT RUN in usual case.
Look:
sub process {
my( $self ) = @_;
return unless $self->is_valid; # Read this code as: $self should be valid
my $result = ...;
return $result;
}
Look next examples where I use `unless` with success (And I think code with `unless` here is clear in compare to usual `if`):
$self->error( $tx->res->json ) unless $tx->res->is_success;
Transaction response SHOULD BE success
return $c->render( text => 'We support only HTML and JSON', status => 415 )
unless $f eq 'json' || $f eq 'html';
Format $f SHOULD BE json or html
(Try to rewrite this with usual `if`. I think it will be more complex ;-) )
Another real code:
return unless my $d = $c->stash( 'data' );
return unless $c->app->mode eq 'production';
# There SHOULD BE data in production mode
Even complex conditions are easy to understand. Just keep in mind that: **you go forward if EXPR is true**, so:
return 'IP is not IPv' .$version unless !$version || $ip->version eq $version;
Go forward if $version is not required OR $ip have required $version. We return error in all other cases.
Just remember. you mark your code with until/unless which usually will not work:
until( $x > 0 ) {
$x += 3;
}
$x usually >0 here and you skip { $x += 3 } block. Is this easy to understand? I think, it is!
Because you usually read file the `while( !eof )` is more intuitive.
But different IDs we should check through different models.
This pull request tries to add this functionality. If it will be appiled you can do next:
$v->required( 'invoice_id', [ data_exists => 'Invoice' ] );
$v->required( 'order_id', [data_exists => 'Order' ] );
And the fileter:
$v->add_filter( data_exists => sub { data_exists( $app, @_ ) } );
sub data_exists {
my( $app, $v, $name, $value, $model ) = @_;
my $obj = $app->rows( $model )->find( $value )
or return ();
return $obj;
}
If you want your model do advanced decision about its data accessible or not you may pass current context:
$v->required( 'invoice_id', [ data_exists => $c, 'Invoice' ] );
The filter:
sub data_exists {
my( $v, $name, $value, $c, $model ) = @_;
my $obj = $c->rows( $model )->find( $value )
or return ();
return $obj;
}
And somewhere in the model:
sub rows {
my( $c, $table_name ) = @_;
...
$c->db->relation_ship( $table_name )->search({ user_id => $c->uid });
}
So after validation you are guarantied to have objects which are allowed to access only for current user.
And there is no way to access other objects the user do not own
]]>And I’ve been thinking about the idea of a “soft call” for a long time.
Even when writing in ASM always irritated exceptions when CALL 0
Well, here again returned to this topic.
What’s wrong? Very often I have to write the following code:
my $ x; my $ y;
If( ($x = $ obj-> method) && ($y = $x->another_method) ) {
$ y = ...;
}
An example from life:
If ($ db-> query (...) -> hash -> {value}) {...}
If ($ db-> resultset ('table') -> search (...) -> related_resultset ('table2') {...}
Here if the query returned an empty result, the code will fall.
But when you use a soft call operator, you can not be afraid of exceptions and the code will become easier:
use pragma 'soft_call';
If( my $ x = $ obj-> method ~> another_method ) {...}
If ($db-> query (...) ~> hash -> {value}) {...}
If( $db-> resultset ('table') -> search (...) ~> related_resultset ('table2') {...}
And it seems like everything is expressive.
Even the very implementation of the pragma in a dozen lines:
.
sub soft_call_operator {
my ($ left_operand, $ right_operand) = @_;
return undef if! defined $left_operand;
# Do normal processing of the function call
'->'($left_operand, $right_operand);
}
I try to google existing analogues and found the Postgres when RETURNS NULL ON NULL INPUT
Comments Wellcome
UPD Thank to choroba for the link. This theme was discussed here
]]>