Catalyst-Runtime

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

          parse_on_demand is on

5.80003 2009-04-29 16:23:53
        - Various POD tweaks. (hdp, dandv)
        - Fix formatting error in the regex fallback warning.
        - Convert the dispatcher's and restarter engine's BUILD method to
          attribute builders to not override the BUILD method from
          MooseX::Emulate::Class::Accessor::Fast.
        - Fix classes without metaclasses restarting, when not using
          B::Hooks::OP::Check::StashChange
        - Fix the unattached chain debug table for endpoints with no
          parents at all.
        - Turn off test aggregation by default. Only aggregate if the
          AGGREGATE_TESTS environment variable is set and a recent
          Test::Aggregate is available.
        - Bump to MooseX::MethodAttributes 0.09, to gain the
          get_nearest_methods_with_attributes method allowing methods without
          attributes in a subclass to override those with attributes in a
          superclass. This fixes CatalystX::CRUD's method of overriding /
          disabling functionality from base controllers.
        - Bump HTTP::Request::AsCGI dependency to avoid broken version

lib/Catalyst/Controller.pm  view on Meta::CPAN

specifically (for a single action).

    __PACKAGE__->config(
        action => {
            '*' => { Chained => 'base', Args => 0  },
            base => { Chained => '/', PathPart => '', CaptureArgs => 0 },
        },
     );

In the case above every sub in the package would be made into a Chain
endpoint with a URI the same as the sub name for each sub, chained
to the sub named C<base>. Ergo dispatch to C</example> would call the
C<base> method, then the C<example> method.

=head2 action_args

Allows you to set constructor arguments on your actions. You can set arguments
globally and specifically (as above).
This is particularly useful when using C<ActionRole>s
(L<Catalyst::Controller::ActionRole>) and custom C<ActionClass>es.

lib/Catalyst/Controller.pm  view on Meta::CPAN


Please keep in mind that when dispatching, L<Catalyst> will match the first most
relevant case, so if you use the C<Consumes> attribute, you should place your
most accurate matches early in the Chain, and your 'catchall' actions last.

See L<Catalyst::ActionRole::ConsumesContent> for more.

=head2 Scheme(...)

Allows you to specify a URI scheme for the action or action chain.  For example
you can required that a given path be C<https> or that it is a websocket endpoint
C<ws> or C<wss>.  For an action chain you may currently only have one defined
Scheme.

    package MyApp::Controller::Root;

    use base 'Catalyst::Controller';

    sub is_http :Path(scheme) Scheme(http) Args(0) {
      my ($self, $c) = @_;
      $c->response->body("is_http");

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN

use Moose;
extends 'Catalyst::DispatchType';

use Text::SimpleTable;
use Catalyst::ActionChain;
use Catalyst::Utils;
use URI;
use Scalar::Util ();
use Encode 2.21 'decode_utf8';

has _endpoints => (
                   is => 'rw',
                   isa => 'ArrayRef',
                   required => 1,
                   default => sub{ [] },
                  );

has _actions => (
                 is => 'rw',
                 isa => 'HashRef',
                 required => 1,

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN

=head1 SYNOPSIS

Path part matching, allowing several actions to sequentially take care of processing a request:

  #   root action - captures one argument after it
  sub foo_setup : Chained('/') PathPart('foo') CaptureArgs(1) {
      my ( $self, $c, $foo_arg ) = @_;
      ...
  }

  #   child action endpoint - takes one argument
  sub bar : Chained('foo_setup') Args(1) {
      my ( $self, $c, $bar_arg ) = @_;
      ...
  }

=head1 DESCRIPTION

Dispatch type managing default behaviour.  For more information on
dispatch types, see:

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN


=head2 $self->list($c)

Debug output for Path Part dispatch points

=cut

sub list {
    my ( $self, $c ) = @_;

    return unless $self->_endpoints;

    my $avail_width = Catalyst::Utils::term_width() - 9;
    my $col1_width = ($avail_width * .50) < 35 ? 35 : int($avail_width * .50);
    my $col2_width = $avail_width - $col1_width;
    my $paths = Text::SimpleTable->new(
        [ $col1_width, 'Path Spec' ], [ $col2_width, 'Private' ],
    );

    my $has_unattached_actions;
    my $unattached_actions = Text::SimpleTable->new(
        [ $col1_width, 'Private' ], [ $col2_width, 'Missing parent' ],
    );

    ENDPOINT: foreach my $endpoint (
                  sort { $a->reverse cmp $b->reverse }
                           @{ $self->_endpoints }
                  ) {
        my $args = $endpoint->list_extra_info->{Args};

        my @parts;
        if($endpoint->has_args_constraints) {
            @parts = map { "{$_}" } $endpoint->all_args_constraints;
        } elsif(defined $endpoint->attributes->{Args}) {
            @parts = (defined($endpoint->attributes->{Args}[0]) ? (("*") x $args) : '...');
        }

        my @parents = ();
        my $parent = "DUMMY";
        my $extra  = $self->_list_extra_http_methods($endpoint);
        my $consumes = $self->_list_extra_consumes($endpoint);
        my $scheme = $self->_list_extra_scheme($endpoint);
        my $curr = $endpoint;
        while ($curr) {
            if (my $cap = $curr->list_extra_info->{CaptureArgs}) {
                if($curr->has_captures_constraints) {
                    my $names = join '/', map { "{$_}" } $curr->all_captures_constraints;
                    unshift(@parts, $names);
                } else {
                    unshift(@parts, (("*") x $cap));
                }
            }
            if (my $pp = $curr->attributes->{PathPart}) {
                unshift(@parts, $pp->[0])
                    if (defined $pp->[0] && length $pp->[0]);
            }
            $parent = $curr->attributes->{Chained}->[0];
            $curr = $self->_actions->{$parent};
            unshift(@parents, $curr) if $curr;
        }
        if ($parent ne '/') {
            $has_unattached_actions = 1;
            $unattached_actions->row('/' . ($parents[0] || $endpoint)->reverse, $parent);
            next ENDPOINT;
        }
        my @rows;
        foreach my $p (@parents) {
            my $name = "/${p}";

            if (defined(my $extra = $self->_list_extra_http_methods($p))) {
                $name = "${extra} ${name}";
            }
            if (defined(my $cap = $p->list_extra_info->{CaptureArgs})) {

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN

            if (defined(my $s = $p->list_extra_info->{Scheme})) {
                $scheme = uc $s;
            }

            unless ($p eq $parents[0]) {
                $name = "-> ${name}";
            }
            push(@rows, [ '', $name ]);
        }

        my $endpoint_arg_info = $endpoint;
        if($endpoint->has_args_constraints) {
          my $tc = join ',', @{$endpoint->args_constraints};
          $endpoint_arg_info .= " ($tc)";
        } else {
          $endpoint_arg_info .= defined($endpoint->attributes->{Args}[0]) ? " ($args)" : " (...)";
        }
        push(@rows, [ '', (@rows ? "=> " : '').($extra ? "$extra " : ''). ($scheme ? "$scheme: ":'')."/${endpoint_arg_info}". ($consumes ? " :$consumes":"" ) ]);
        my @display_parts = map { $_ =~s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; decode_utf8 $_ } @parts;
        $rows[0][0] = join('/', '', @display_parts) || '/';
        $paths->row(@$_) for @rows;
    }

    $c->log->debug( "Loaded Chained actions:\n" . $paths->draw . "\n" );
    $c->log->debug( "Unattached Chained actions:\n", $unattached_actions->draw . "\n" )
        if $has_unattached_actions;
}

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN

    $self->_actions->{'/'.$action->reverse} = $action;

    if (exists $action->attributes->{Args} and exists $action->attributes->{CaptureArgs}) {
        Catalyst::Exception->throw(
          "Combining Args and CaptureArgs attributes not supported registering " .
          $action->reverse()
        );
    }

    unless ($action->attributes->{CaptureArgs}) {
        unshift(@{ $self->_endpoints }, $action);
    }

    return 1;
}

=head2 $self->uri_for_action($action, $captures)

Get the URI part for the action, using C<$captures> to fill
the capturing parts.

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN

__PACKAGE__->meta->make_immutable;
1;

=head1 USAGE

=head2 Introduction

The C<Chained> attribute allows you to chain public path parts together
by their private names. A chain part's path can be specified with
C<PathPart> and can be declared to expect an arbitrary number of
arguments. The endpoint of the chain specifies how many arguments it
gets through the C<Args> attribute. C<:Args(0)> would be none at all,
C<:Args> without an integer would be unlimited. The path parts that
aren't endpoints are using C<CaptureArgs> to specify how many parameters
they expect to receive. As an example setup:

  package MyApp::Controller::Greeting;
  use base qw/ Catalyst::Controller /;

  #   this is the beginning of our chain
  sub hello : PathPart('hello') Chained('/') CaptureArgs(1) {
      my ( $self, $c, $integer ) = @_;
      $c->stash->{ message } = "Hello ";
      $c->stash->{ arg_sum } = $integer;
  }

  #   this is our endpoint, because it has no :CaptureArgs
  sub world : PathPart('world') Chained('hello') Args(1) {
      my ( $self, $c, $integer ) = @_;
      $c->stash->{ message } .= "World!";
      $c->stash->{ arg_sum } += $integer;

      $c->response->body( join "<br/>\n" =>
          $c->stash->{ message }, $c->stash->{ arg_sum } );
  }

The debug output provides a separate table for chained actions, showing

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN

  [debug] Loaded Path Part actions:
  .-----------------------+------------------------------.
  | Path Spec             | Private                      |
  +-----------------------+------------------------------+
  | /hello/*/world/*      | /greeting/hello (1)          |
  |                       | => /greeting/world           |
  '-----------------------+------------------------------'
  ...

As you can see, Catalyst only deals with chains as whole paths and
builds one for each endpoint, which are the actions with C<:Chained> but
without C<:CaptureArgs>.

Let's assume this application gets a request at the path
C</hello/23/world/12>. What happens then? First, Catalyst will dispatch
to the C<hello> action and pass the value C<23> as an argument to it
after the context. It does so because we have previously used
C<:CaptureArgs(1)> to declare that it has one path part after itself as
its argument. We told Catalyst that this is the beginning of the chain
by specifying C<:Chained('/')>. Also note that instead of saying
C<:PathPart('hello')> we could also just have said C<:PathPart>, as it
defaults to the name of the action.

After C<hello> has run, Catalyst goes on to dispatch to the C<world>
action. This is the last action to be called: Catalyst knows this is an
endpoint because we did not specify a C<:CaptureArgs>
attribute. Nevertheless we specify that this action expects an argument,
but at this point we're using C<:Args(1)> to do that. We could also have
said C<:Args> or left it out altogether, which would mean this action
would get all arguments that are there. This action's C<:Chained>
attribute says C<hello> and tells Catalyst that the C<hello> action in
the current controller is its parent.

With this we have built a chain consisting of two public path parts.
C<hello> captures one part of the path as its argument, and also
specifies the path root as its parent. So this part is
C</hello/$arg>. The next part is the endpoint C<world>, expecting one
argument. It sums up to the path part C<world/$arg>. This leads to a
complete chain of C</hello/$arg/world/$arg> which is matched against the
requested paths.

This example application would, if run and called by e.g.
C</hello/23/world/12>, set the stash value C<message> to "Hello" and the
value C<arg_sum> to "23". The C<world> action would then append "World!"
to C<message> and add C<12> to the stash's C<arg_sum> value.  For the
sake of simplicity no view is shown. Instead we just put the values of
the stash into our body. So the output would look like:

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN


  sub view : PathPart Chained('rev') Args(0) {
      my ( $self, $c ) = @_;
      #  display the revision in our stash. Another option
      #  would be to forward a compatible object to the action
      #  that displays the default wiki pages, unless we want
      #  a different interface here, for example restore
      #  functionality.
  }

It would now be possible to add other endpoints, for example C<restore>
to restore this specific revision as the current state.

You don't have to put all the chained actions in one controller. The
specification of the parent through C<:Chained> also takes an absolute
action path as its argument. Just specify it with a leading C</>.

If you want, for example, to have actions for the public paths
C</foo/12/edit> and C</foo/12>, just specify two actions with
C<:PathPart('foo')> and C<:Chained('/')>. The handler for the former
path needs a C<:CaptureArgs(1)> attribute and a endpoint with
C<:PathPart('edit')> and C<:Chained('foo')>. For the latter path give
the action just a C<:Args(1)> to mark it as endpoint. This sums up to
this debugging output:

  ...
  [debug] Loaded Path Part actions:
  .-----------------------+------------------------------.
  | Path Spec             | Private                      |
  +-----------------------+------------------------------+
  | /foo/*                | /controller/foo_view         |
  | /foo/*/edit           | /controller/foo_load (1)     |
  |                       | => /controller/edit          |

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN

  sub bar : Chained CaptureArgs(1) { ... }

  # in MyApp::Controller::Foo::Bar
  sub bar : ChainedParent Args(1) { ... }

This builds a chain like C</bar/*/bar/*>.

=item CaptureArgs

Must be specified for every part of the chain that is not an
endpoint. With this attribute Catalyst knows how many of the following
parts of the path (separated by C</>) this action wants to capture as
its arguments. If it doesn't expect any, just specify
C<:CaptureArgs(0)>.  The captures get passed to the action's C<@_> right
after the context, but you can also find them as array references in
C<< $c->request->captures->[$level] >>. The C<$level> is the
level of the action in the chain that captured the parts of the path.

An action that is part of a chain (that is, one that has a C<:Chained>
attribute) but has no C<:CaptureArgs> attribute is treated by Catalyst
as a chain end.

lib/Catalyst/DispatchType/Chained.pm  view on Meta::CPAN

      sub int_priority_chain :Chained(chain_base) PathPart('') Args(Int) { }

If you use a reference type constraint in CaptureArgs, it must be a type
like Tuple in L<Types::Standard> that allows us to determine the number of
args to match.  Otherwise this will raise an error during startup.

See L<Catalyst::RouteMatching> for more.

=item Args

By default, endpoints receive the rest of the arguments in the path. You
can tell Catalyst through C<:Args> explicitly how many arguments your
endpoint expects, just like you can with C<:CaptureArgs>. Note that this
also affects whether this chain is invoked on a request. A chain with an
endpoint specifying one argument will only match if exactly one argument
exists in the path.

You can specify an exact number of arguments like C<:Args(3)>, including
C<0>. If you just say C<:Args> without any arguments, it is the same as
leaving it out altogether: The chain is matched regardless of the number
of path parts after the endpoint.

Just as with C<:CaptureArgs>, the arguments get passed to the action in
C<@_> after the context object. They can also be reached through
C<< $c->request->arguments >>.

You should see 'Args' in L<Catalyst::Controller> for more details on using
type constraints in your Args declarations.

=back

=head2 Auto actions, dispatching and forwarding

Note that the list of C<auto> actions called depends on the private path
of the endpoint of the chain, not on the chained actions way. The
C<auto> actions will be run before the chain dispatching begins. In
every other aspect, C<auto> actions behave as documented.

The C<forward>ing to other actions does just what you would expect. i.e.
only the target action is run. The actions that that action is chained
to are not run.
If you C<detach> out of a chain, the rest of the chain will not get
called after the C<detach>.

=head2 match_captures

t/aggregate/live_component_controller_action_chained.t  view on Meta::CPAN

    my ($run_number) = @_;

    #
    #   This is a simple test where the parent and child actions are
    #   within the same controller.
    #
    {
        my @expected = qw[
          TestApp::Controller::Action::Chained->begin
          TestApp::Controller::Action::Chained->foo
          TestApp::Controller::Action::Chained->endpoint
          TestApp::Controller::Action::Chained->end
        ];

        my $expected = join( ", ", @expected );

        ok( my $response = request('http://localhost/chained/foo/1/end/2'), 'chained + local endpoint' );
        is( $response->header('X-Catalyst-Executed'),
            $expected, 'Executed actions' );
        is( $response->content, '1; 2', 'Content OK' );
    }

    #
    #   This makes sure the above isn't found if the argument for the
    #   end action isn't supplied.
    #
    {
        my $expected = undef;

        ok( my $response = request('http://localhost/chained/foo/1/end'),
            'chained + local endpoint; missing last argument' );
        is( $response->header('X-Catalyst-Executed'),
            $expected, 'Executed actions' );
        is( $response->code, 500, 'Status OK' );
    }

    #
    #   Tests the case when the child action is placed in a subcontroller.
    #
    {
        my @expected = qw[
          TestApp::Controller::Action::Chained->begin
          TestApp::Controller::Action::Chained->foo
          TestApp::Controller::Action::Chained::Foo->spoon
          TestApp::Controller::Action::Chained->end
        ];

        my $expected = join( ", ", @expected );

        ok( my $response = request('http://localhost/chained/foo/1/spoon'), 'chained + subcontroller endpoint' );
        is( $response->header('X-Catalyst-Executed'),
            $expected, 'Executed actions' );
        is( $response->content, '1; ', 'Content OK' );
    }

    #
    #   Tests if the relative specification (e.g.: Chained('bar') ) works
    #   as expected.
    #
    {
        my @expected = qw[
          TestApp::Controller::Action::Chained->begin
          TestApp::Controller::Action::Chained->bar
          TestApp::Controller::Action::Chained->finale
          TestApp::Controller::Action::Chained->end
        ];

        my $expected = join( ", ", @expected );

        ok( my $response = request('http://localhost/chained/bar/1/spoon'), 'chained + relative endpoint' );
        is( $response->header('X-Catalyst-Executed'),
            $expected, 'Executed actions' );
        is( $response->content, '; 1, spoon', 'Content OK' );
    }

    #
    #   Just a test for multiple arguments.
    #
    {
        my @expected = qw[
          TestApp::Controller::Action::Chained->begin
          TestApp::Controller::Action::Chained->foo2
          TestApp::Controller::Action::Chained->endpoint2
          TestApp::Controller::Action::Chained->end
        ];

        my $expected = join( ", ", @expected );

        ok( my $response = request('http://localhost/chained/foo2/10/20/end2/15/25'),
            'chained + local (2 args each)' );
        is( $response->header('X-Catalyst-Executed'),
            $expected, 'Executed actions' );
        is( $response->content, '10, 20; 15, 25', 'Content OK' );

t/aggregate/live_component_controller_action_chained.t  view on Meta::CPAN

        }
        else { pass( "Error on absolute path part arguments already tested" ) }
    }

    #
    #   Test chained actions in the root controller
    #
    {
        my @expected = qw[
          TestApp::Controller::Action::Chained::Root->rootsub
          TestApp::Controller::Action::Chained::Root->endpointsub
          TestApp::Controller::Root->end
        ];

        my $expected = join( ", ", @expected );

        ok( my $response = request('http://localhost/rootsub/1/endpointsub/2'), 'chained in root namespace' );
        is( $response->header('X-Catalyst-Executed'),
            $expected, 'Executed actions' );
        is( $response->content, '', 'Content OK' );
    }

    #
    #   Complex path with multiple empty pathparts
    #
    {
        my @expected = qw[

t/aggregate/live_component_controller_action_chained.t  view on Meta::CPAN

    {
        my @expected = qw[
          TestApp::Controller::Action::Chained->begin
          TestApp::Controller::Action::Chained::PathPrefix->instance
          TestApp::Controller::Action::Chained->end
        ];

        my $expected = join( ", ", @expected );

        ok( my $response = request('http://localhost/action/chained/pathprefix/1'),
            "PathPrefix (as an endpoint)" );
        is( $response->header('X-Catalyst-Executed'),
            $expected, 'Executed actions' );
        is( $response->content, '; 1', 'Content OK' );
    }

    #
    #   static paths vs. captures
    #
    {
        my @expected = qw[

t/aggregate/live_component_controller_action_go.t  view on Meta::CPAN

          TestApp::Controller::Action::Go->begin
          TestApp::Controller::Action::Go->go_chained
          TestApp::Controller::Action::Chained->begin
          TestApp::Controller::Action::Chained->foo
          TestApp::Controller::Action::Chained::Foo->spoon
          TestApp::Controller::Action::Chained->end
        ];

        my $expected = join( ", ", @expected );

        ok( my $response = request('http://localhost/action/go/go_chained'), 'go to chained + subcontroller endpoint' );
        is( $response->header('X-Catalyst-Executed'),
            $expected, 'Executed actions' );
        is( $response->content, 'captureme; arg1, arg2', 'Content OK' );
    }

}



sub _begin {

t/aggregate/live_component_controller_action_visit.t  view on Meta::CPAN

          TestApp::Controller::Action::Chained->foo
          TestApp::Controller::Action::Chained::Foo->spoon
          TestApp::Controller::Action::Chained->end
          TestApp::Controller::Root->end
        ];

        my $expected = join( ", ", @expected );

        for my $i ( 1..3 ) {
            ok( my $response = request("http://localhost/action/visit/visit_chained/$i/becomescapture/arg1/arg2"),
                "visit to chained + subcontroller endpoint for $i" );
            is( $response->header('X-Catalyst-Executed'),
                $expected, "Executed actions for $i" );
            is( $response->content, "becomescapture; arg1, arg2",
                "Content OK for $i" );
        }
    }

}


t/aggregate/unit_core_uri_for_action.t  view on Meta::CPAN

   "no URI returned for index action when snippets are given");

is($dispatcher->uri_for_action($index_action),
   "/action/index",
   "index action returns correct path");

#
#   Chained Action
#
my $chained_action = $dispatcher->get_action_by_path(
                       '/action/chained/endpoint',
                     );

ok(!defined($dispatcher->uri_for_action($chained_action)),
   "Chained action without captures returns undef");

ok(!defined($dispatcher->uri_for_action($chained_action, [ 1, 2 ])),
   "Chained action with too many captures returns undef");

is($dispatcher->uri_for_action($chained_action, [ 1 ]),
   "/chained/foo/1/end",

t/aggregate/unit_core_uri_for_action.t  view on Meta::CPAN

my $request = Catalyst::Request->new( {
                _log => Catalyst::Log->new,
                base => URI->new('http://127.0.0.1/foo')
              } );

my $context = TestApp->new( {
                request => $request,
                namespace => 'yada',
              } );

is($context->uri_for($context->controller('Action::Chained')->action_for('endpoint'), [ 1 ]),
   'http://127.0.0.1/foo/chained/foo/1/end',
   "uri_for a controller and action");

is( $context->uri_for_action( '/action/chained/endpoint', [ 1 ] ),
    'http://127.0.0.1/foo/chained/foo/1/end',
    "uri_for a controller and action as string");

is(TestApp->uri_for_action($context->controller('Action::Chained')->action_for('endpoint'), [ 1 ]),
    '/chained/foo/1/end',
    "uri_for a controller and action, called with only class name");

is(TestApp->uri_for_action('/action/chained/endpoint', [ 1 ] ),
    '/chained/foo/1/end',
    "uri_for a controller and action as string, called with only class name");

is(TestApp->uri_for_action(  $chained_action, [ 1 ]),
    '/chained/foo/1/end',
    "uri_for action via dispatcher, called with only class name");

is($context->uri_for($context->controller('Action')),
   "http://127.0.0.1/foo/yada/action/",
   "uri_for a controller");

t/aggregate/unit_core_uri_for_action.t  view on Meta::CPAN

   "no URI returned by uri_for for Path action with snippets");

is($context->uri_for($chained_action, [ 1 ], 2, { q => 1 }),
   "http://127.0.0.1/foo/chained/foo/1/end/2?q=1",
   "uri_for correct for chained with captures, args and query");

#
#   More Chained with Context Tests
#
{
    is( $context->uri_for_action( '/action/chained/endpoint2', [1,2], (3,4), { x => 5 } ),
        'http://127.0.0.1/foo/chained/foo2/1/2/end2/3/4?x=5',
        'uri_for_action correct for chained with multiple captures and args' );

    is( $context->uri_for_action( '/action/chained/endpoint2', [1,2,3,4], { x => 5 } ),
        'http://127.0.0.1/foo/chained/foo2/1/2/end2/3/4?x=5',
        'uri_for_action correct for chained with multiple captures and args combined' );

    is( $context->uri_for_action( '/action/chained/three_end', [1,2,3], (4,5,6) ),
        'http://127.0.0.1/foo/chained/one/1/two/2/3/three/4/5/6',
        'uri_for_action correct for chained with multiple capturing actions' );

    is( $context->uri_for_action( '/action/chained/three_end', [1,2,3,4,5,6] ),
        'http://127.0.0.1/foo/chained/one/1/two/2/3/three/4/5/6',
        'uri_for_action correct for chained with multiple capturing actions and args combined' );

    my $action_needs_two = '/action/chained/endpoint2';

    ok( ! defined( $context->uri_for_action($action_needs_two, [1],     (2,3)) ),
        'uri_for_action returns undef for not enough captures' );

    is( $context->uri_for_action($action_needs_two,            [1,2],   (2,3)),
        'http://127.0.0.1/foo/chained/foo2/1/2/end2/2/3',
        'uri_for_action returns correct uri for correct captures' );

    is( $context->uri_for_action($action_needs_two,            [1,2,2,3]),
        'http://127.0.0.1/foo/chained/foo2/1/2/end2/2/3',

t/bad_warnings.t  view on Meta::CPAN

    $c->response->body("This is the body");
    Test::More::is $c->action->comparable_arg_number, ~0;
  }

  sub midpoint :Chained(root) PathPart('') CaptureArgs('"Int"') {
    my ($self, $c) = @_;
    Test::More::is $c->action->number_of_captures, 1;
    #Test::More::is $c->action->number_of_captures_constraints, 1;
  }

  sub endpoint :Chained('midpoint') Args('"Int"') {
    my ($self, $c) = @_;
    Test::More::is $c->action->comparable_arg_number, 1;
    Test::More::is $c->action->normalized_arg_number, 1;
  }

  sub local :Local Args {
    my ($self, $c) = @_;
    $c->response->body("This is the body");
    Test::More::is $c->action->comparable_arg_number, ~0;
  }

t/bad_warnings.t  view on Meta::CPAN


  $SIG{__WARN__} = sub { $error = shift };

  MyApp->setup('-Log=fatal');
}

use Catalyst::Test 'MyApp';

request GET '/root/test/a/b/c';
request GET '/root/local/a/b/c';
request GET '/root/11/endpoint/22';


if($error) {
  unlike($error, qr[Argument ""Int"" isn't numeric in repeat]);
} else {
  ok 1;
}

done_testing(6);

t/dispatch_on_scheme.t  view on Meta::CPAN


    sub uri_for2 :Chained('base') Scheme(https) Args(0) {
      my ($self, $c) = @_;
      Test::More::is $c->action->scheme, 'https';
      $c->response->body($c->uri_for($self->action_for('is_http'))->as_string);
    }

    sub uri_for3 :Chained('base') Scheme(http) Args(0) {
      my ($self, $c) = @_;
      Test::More::is $c->action->scheme, 'http';
      $c->response->body($c->uri_for($self->action_for('endpoint'))->as_string);
    }

  sub base2 :Chained('/') CaptureArgs(0) { }
    sub link :Chained(base2) Scheme(https) CaptureArgs(0) { }
      sub endpoint :Chained(link) Args(0) {
        my ($self, $c) = @_;
        Test::More::is $c->action->scheme, 'https';
        $c->response->body("end");
      }


  package MyApp;
  use Catalyst;

  Test::More::ok(MyApp->setup, 'setup app');

t/dispatch_on_scheme.t  view on Meta::CPAN


{
  my $res = request "https://localhost/base/uri_for2";
  is $res->code, 200, 'OK';
  is $res->content, 'http://localhost/root/scheme', 'correct body';
}

{
  my $res = request "/base/uri_for3";
  is $res->code, 200, 'OK';
  is $res->content, 'https://localhost/base2/link/endpoint', 'correct body';
}

{
  my $res = request "https://localhost/base2/link/endpoint";
  is $res->code, 200, 'OK';
  is $res->content, 'end', 'correct body';
}

done_testing;

t/lib/TestApp/Controller/Action/Chained.pm  view on Meta::CPAN

#

#
#   Simple parent/child action test
#
sub foo  :PathPart('chained/foo')  :CaptureArgs(1) :Chained('/') {
    my ( $self, $c, @args ) = @_;
    die "missing argument" unless @args;
    die "more than 1 argument: got @args" if @args > 1;
}
sub endpoint  :PathPart('end')  :Chained('/action/chained/foo')  :Args(1) { }

#
#   Parent/child test with two args each
#
sub foo2 :PathPart('chained/foo2') :CaptureArgs(2) :Chained('/') { }
sub endpoint2 :PathPart('end2') :Chained('/action/chained/foo2') :Args(2) { }

#
#   Relative specification of parent action
#
sub bar :PathPart('chained/bar') :Chained('/') :CaptureArgs(0) { }
sub finale :PathPart('') :Chained('bar') :Args { }

#
#   three chain with concurrent endpoints
#
sub one   :PathPart('chained/one') :Chained('/')                   :CaptureArgs(1) { }
sub two   :PathPart('two')         :Chained('/action/chained/one') :CaptureArgs(2) { }
sub three_end :PathPart('three')       :Chained('two') :Args(3) { }
sub one_end   :PathPart('chained/one') :Chained('/')   :Args(1) { }
sub two_end   :PathPart('two')         :Chained('one') :Args(2) { }

#
#   Dispatch on number of arguments
#

t/lib/TestApp/Controller/Action/Chained.pm  view on Meta::CPAN


#
#   Priority: With no Args()
#
sub priority_c1 :PathPart('chained/priority_c') :Chained('/') :CaptureArgs(1) { }
sub priority_c2 :PathPart('') :Chained('priority_c1') { }
sub priority_c2_xyz :PathPart('xyz') :Chained('priority_c1')  { }


#
#   Optional specification of :Args in endpoint
#
sub opt_args :PathPart('chained/opt_args') :Chained('/') { }

#
#   Optional PathPart test -> /chained/optpp/*/opt_pathpart/*
#
sub opt_pp_start :Chained('/') :PathPart('chained/optpp') :CaptureArgs(1) { }
sub opt_pathpart :Chained('opt_pp_start') :Args(1) { }

#

t/lib/TestApp/Controller/Action/Chained/Root.pm  view on Meta::CPAN

package TestApp::Controller::Action::Chained::Root;

use strict;
use warnings;

use base qw( Catalyst::Controller );

__PACKAGE__->config->{namespace} = '';

sub rootsub     : PathPart Chained( '/' )       CaptureArgs( 1 ) { }
sub endpointsub : PathPart Chained( 'rootsub' ) Args( 1 )        { }

1;

t/lib/TestAppIndexDefault/Controller/IndexChained.pm  view on Meta::CPAN

package TestAppIndexDefault::Controller::IndexChained;

use base 'Catalyst::Controller';

sub index : Chained('/') PathPart('indexchained') CaptureArgs(0) {}

sub index_endpoint : Chained('index') PathPart('') Args(0) {
    my ($self, $c) = @_;
    $c->res->body('index_chained');
}

1;



( run in 0.603 second using v1.01-cache-2.11-cpan-b61123c0432 )