CatalystX-Declare
view release on metacpan or search on metacpan
lib/CatalystX/Declare/Keyword/Action.pm view on Meta::CPAN
}
return undef;
}
method _handle_action_option (Object $ctx, HashRef $attrs) {
# action name
my $name = $self->_strip_actionpath($ctx, interpolate => 1)
or croak "Anonymous actions not yet supported";
$ctx->skipspace;
my $populator;
# shortcut under base option is basically handled by the under handler
if (substr($ctx->get_linestr, $ctx->offset, 2) eq '<-') {
my $linestr = $ctx->get_linestr;
substr($linestr, $ctx->offset, 2) = '';
$ctx->set_linestr($linestr);
$populator = $self->_handle_under_option($ctx, $attrs);
}
# signature
my $proto = $ctx->strip_proto || '';
$proto = join(', ', 'Object $self: Object $ctx', $proto || ());
$attrs->{Subname} = $name;
$attrs->{Signature} = $proto;
$attrs->{Action} = [];
push @{ $attrs->{CatalystX_Declarative_DefaultActionRoles} ||= [] }, CatchValidationError;
# default chained base to the global under var, to be resolved at runtime
$attrs->{Chained} ||= UNDER_VAR;
return unless $populator;
return $populator;
}
method _handle_final_option (Object $ctx, HashRef $attrs) {
return $self->_build_flag_populator($ctx, $attrs, 'final');
}
method _handle_is_option (Object $ctx, HashRef $attrs) {
my $what = $ctx->strip_name
or croak "Expected symbol token after is symbol, not " . substr($ctx->get_linestr, $ctx->offset);
return $self->_build_flag_populator($ctx, $attrs, $what);
}
method _build_flag_populator (Object $ctx, HashRef $attrs, Str $what) {
$attrs->{Private} = []
if $what eq 'private';
return sub {
my $method = shift;
if ($what eq any qw( end endpoint final )) {
$attrs->{Args} = delete $attrs->{CaptureArgs};
}
elsif ($what eq 'private') {
$attrs->{Private} = [];
}
};
}
method _handle_under_option (Object $ctx, HashRef $attrs) {
my $target = $self->_strip_actionpath($ctx, interpolate => 1);
$ctx->skipspace;
if ($ctx->peek_next_char eq '{' and $self->identifier eq 'under') {
$ctx->inject_if_block(
$ctx->scope_injector_call .
sprintf ';local %s = %s;',
UNDER_VAR,
$target,
);
return STOP_PARSING;
}
$attrs->{Chained} = $target;
return sub {
my $method = shift;
};
}
method _handle_chains_option (Object $ctx, HashRef $attrs) {
$ctx->skipspace;
$ctx->strip_name eq 'to'
or croak "Expected to token after chains symbol, not " . substr($ctx->get_linestr, $ctx->offset);
return $self->_handle_under_option($ctx, $attrs);
}
method _handle_as_option (Object $ctx, HashRef $attrs) {
$ctx->skipspace;
my $path = $self->_strip_actionpath($ctx, interpolate => 1);
$attrs->{PathPart} = $path;
return;
}
method _count_positional_arguments (Object $method) {
my $signature = $method->parsed_signature;
if ($signature->has_positional_params) {
my $count = @{ scalar($signature->positional_params) };
if ($count and ($signature->positional_params)[-1]->sigil eq '@') {
return undef;
}
return $count - 1;
lib/CatalystX/Declare/Keyword/Action.pm view on Meta::CPAN
$ctx->set_linestr($linestr);
return $interp->($1);
}
# double quoted strings and variables
elsif ($interpolate and my $str = $ctx->get_string) {
return $str;
}
# not suitable as action path
else {
croak "Invalid syntax for action path: $rest";
}
}
# down here because it requires the parse method
with 'MooseX::Declare::Syntax::KeywordHandling';
around context_traits { $self->$orig, StringParsing }
}
__END__
=head1 NAME
CatalystX::Declare::Keyword::Action - Declare Catalyst Actions
=head1 SYNOPSIS
use CatalystX::Declare;
controller MyApp::Web::Controller::Example {
# chain base action with path part setting of ''
# body-less actions don't do anything by themselves
action base as '' under '/';
# simple end-point action
action controller_class is final under base {
$ctx->response->body( 'controller: ' . ref $self );
}
# chain part actions can have arguments
action str (Str $string) under base {
$ctx->stash(chars => [split //, $string]);
}
# and end point actions too, of course
action uc_chars (Int $count) under str is final {
my $chars = $ctx->stash->{chars};
...
}
# you can use a shortcut for multiple actions with
# a common base
under base {
# this is an endpoint after base
action normal is final;
# the final keyword can be used to be more
# visually explicit about end-points
final action some_action { ... }
# type dispatching works
final action with_str (Str $x) as via_type;
final action with_int (Int $x) as via_type;
}
# of course you can also chain to external actions
final action some_end under '/some/controller/some/action';
}
=head1 DESCRIPTION
This handler class provides the user with C<action>, C<final> and C<under>
keywords. There are multiple ways to define actions to allow for greater
freedom of expression. While the parts of the action declaration itself do
not care about their order, their syntax is rather strict.
You can choose to separate syntax elements via C<,> if you think it is more
readable. The action declaration
action foo is final under base;
is parsed in exactly the same way if you write it as
action foo, is final, under base;
=head2 Basic Action Declaration
The simplest possible declaration is
action foo;
This would define a chain-part action chained to nothing with the name C<foo>
and no arguments. Since it isn't followed by a block, the body of the action
will be empty.
You will automatically be provided with two variables: C<$self> is, as you
might expect, your controller instance. C<$ctx> will be the Catalyst context
object. Thus, the following code would stash the value returned by the
C<get_item> method:
action foo {
$ctx->stash(item => $self->get_item);
}
=head2 Why $ctx instead of $c
Some might ask why the context object is called C<$ctx> instead of the usual
C<$c>. The reason is simple: It's an opinionated best practice, since C<$ctx>
stands out more.
=head2 Setting a Path Part
As usual with Catalyst actions, the path part (the public name of this part of
the URI, if you're not familiar with the term yet) will default to the name of
( run in 1.844 second using v1.01-cache-2.11-cpan-9581c071862 )