| line | stmt | bran | cond | sub | pod | time | code | 
| 1 | 1 |  |  | 1 |  | 2883 | use strict; use warnings; | 
|  | 1 |  |  | 1 |  | 2 |  | 
|  | 1 |  |  |  |  | 26 |  | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 29 |  | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  |  | 
| 4 |  |  |  |  |  |  | use Scalar::Util (); | 
| 5 | 1 |  |  | 1 |  | 5 | use Carp (); | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 11 |  | 
| 6 | 1 |  |  | 1 |  | 4 |  | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 367 |  | 
| 7 |  |  |  |  |  |  | our $VERSION = '1.004'; | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | my $c = shift; | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 2 |  |  | 2 | 1 | 348423 | my ( $action, $path ); | 
| 12 |  |  |  |  |  |  | if ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Catalyst::Action' ) ) { | 
| 13 | 2 |  |  |  |  | 4 | $action = shift; | 
| 14 | 2 | 50 | 33 |  |  | 18 | } | 
| 15 | 0 |  |  |  |  | 0 | else { | 
| 16 |  |  |  |  |  |  | $path   = shift; | 
| 17 |  |  |  |  |  |  | $path   = $c->stack->[-1]->namespace . '/' . $path if $path !~ m!/!; | 
| 18 | 2 |  |  |  |  | 5 | $action = $c->dispatcher->get_action_by_path( $path ) | 
| 19 | 2 | 100 |  |  |  | 23 | or Carp::croak "Cannot digress to nonexistant action '$path'"; | 
| 20 | 2 | 50 |  |  |  | 33 | } | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | my $scope_guard = bless [ $c ], 'Catalyst::Plugin::Digress::_ScopeGuard'; | 
| 23 |  |  |  |  |  |  | if ( $c->use_stats ) { # basically Catalyst::_stats_start_execute with less nonsense | 
| 24 | 2 |  |  |  |  | 141 | my $action_name = $action->reverse; | 
| 25 | 2 | 50 |  |  |  | 6 | my $uid = $action_name . ++$c->counter->{ $action_name }; | 
| 26 | 0 |  |  |  |  | 0 | my $stats_info = '-> ' . ( $action_name =~ /->/ ? '' : '/' ) . $action_name; | 
| 27 | 0 |  |  |  |  | 0 | my ( $parent ) = grep exists $c->counter->{ $_ }, $c->stack->[-1] || (); | 
| 28 | 0 | 0 |  |  |  | 0 | $c->stats->profile( | 
| 29 | 0 |  | 0 |  |  | 0 | begin => $stats_info, | 
| 30 |  |  |  |  |  |  | uid   => $uid, | 
| 31 |  |  |  |  |  |  | $parent ? ( parent => $parent . $c->counter->{ $parent } ) : (), | 
| 32 |  |  |  |  |  |  | ); | 
| 33 | 0 | 0 |  |  |  | 0 | push @$scope_guard, $stats_info; | 
| 34 |  |  |  |  |  |  | } | 
| 35 | 0 |  |  |  |  | 0 | push @{ $c->stack }, $action; | 
| 36 |  |  |  |  |  |  |  | 
| 37 | 2 |  |  |  |  | 15 | # using a scope guard to unwind the Catalyst stack allows this call to | 
|  | 2 |  |  |  |  | 40 |  | 
| 38 |  |  |  |  |  |  | # happen as the last thing in the function, which avoids the need to | 
| 39 |  |  |  |  |  |  | # explicitly recreate caller context with wantarray | 
| 40 |  |  |  |  |  |  | $action->code->( $c->components->{ $action->class }, $c, @_ ); | 
| 41 |  |  |  |  |  |  | } | 
| 42 | 2 |  |  |  |  | 14 |  | 
| 43 |  |  |  |  |  |  | my ( $c, $stats_info ) = @{ $_[0] }; | 
| 44 |  |  |  |  |  |  | $c->stats->profile( end => $stats_info ) if $stats_info; | 
| 45 |  |  |  |  |  |  | pop @{ $c->stack }; | 
| 46 | 2 |  |  | 2 |  | 350 | } | 
|  | 2 |  |  |  |  | 7 |  | 
| 47 | 2 | 50 |  |  |  | 5 |  | 
| 48 | 2 |  |  |  |  | 3 | 1; | 
|  | 2 |  |  |  |  | 39 |  | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | =pod | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | =encoding UTF-8 | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | =head1 NAME | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | Catalyst::Plugin::Digress - A cleaner, simpler, action-only $c->forward | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | $c->digress( 'some/other/action' ); | 
| 62 |  |  |  |  |  |  | $c->digress( 'action_in_same_controller' ); | 
| 63 |  |  |  |  |  |  | $c->digress( $self->action_for( 'action_in_same_controller' ) ); | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | my %form = $c->digress( 'validate_params', { | 
| 66 |  |  |  |  |  |  | name  => { required => 1 }, | 
| 67 |  |  |  |  |  |  | email => { type => 'Str' }, | 
| 68 |  |  |  |  |  |  | } ); | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | $c->digress( $c->view ); # FAIL: cannot digress to components | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | This plugin gives you the useful part of the Catalyst C<forward> method without | 
| 75 |  |  |  |  |  |  | the weirdness (or the madness). | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | =head1 METHODS | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | =head2 C<digress> | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | This is akin to C<forward>, with the following differences: | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | =over 2 | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | =item * It does not catch exceptions (the most important benefit). | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | =item * It passes parameters like in a normal Perl method call. | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | =item * It does not mess with C<< $c->request->arguments >>. | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | =item * It preserves list vs scalar context for the call. | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | =item * | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | It does not walk the Perl call stack every time (or ever, even once) | 
| 96 |  |  |  |  |  |  | to figure out what its own name was (or for any other purpose). | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | =item * | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | It cannot forward to components, only actions | 
| 101 |  |  |  |  |  |  | (because don’t ask how forwarding to components works). | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | =back | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | In other words, is almost identical to a straight method call: | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | package MyApp::Controller::Some; | 
| 108 |  |  |  |  |  |  | sub other_action : Private { ... } | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | package MyApp::Controller::Root; | 
| 111 |  |  |  |  |  |  | sub index : Path { | 
| 112 |  |  |  |  |  |  | my ( $c, @some_args ) = ( shift, @_ ); | 
| 113 |  |  |  |  |  |  | # ... | 
| 114 |  |  |  |  |  |  | my @some_return = $c->digress( '/some/other_action', @any_old_args ); | 
| 115 |  |  |  |  |  |  | # this is nearly identical to the following line: | 
| 116 |  |  |  |  |  |  | my @some_return = $c->controller( 'Some' )->other_action( $c, @any_old_args ); | 
| 117 |  |  |  |  |  |  | # ... | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | Except, of course, that it takes an action path instead of a plain method name, | 
| 121 |  |  |  |  |  |  | and it maintains the Catalyst action stack for you just like C<forward> would, | 
| 122 |  |  |  |  |  |  | which keeps various Catalyst mechanisms working, such as calling C<forward> and | 
| 123 |  |  |  |  |  |  | friends from C<other_action> with a local action name. | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | =head1 AUTHOR | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | Aristotle Pagaltzis <pagaltzis@gmx.de> | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | This software is copyright (c) 2021 by Aristotle Pagaltzis. | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | This is free software; you can redistribute it and/or modify it under | 
| 134 |  |  |  |  |  |  | the same terms as the Perl 5 programming language system itself. | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | =cut |