CatalystX-ActionBuilders

 view release on metacpan or  search on metacpan

lib/CatalystX/ActionBuilders.pm  view on Meta::CPAN

        global  => sub { _builder([ Global  => 1 ], @_) },
        path    => sub { _builder([              ], @_) },

        default_action => sub { _action([ path_name(q{})             ], @_) },
        index_action   => sub { _action([ index_parts()              ], @_) },
        begin_action   => sub { _action([                            ], @_) },
        end_action     => sub { _action([ action_class('RenderView') ], @_) },
        auto_action    => sub { _action([                            ], @_) },
    ],

    groups => {

        default => [ qw{
            :basic
            :actions
        } ],

        basic => [ qw{
            public private global path
            chained args capture_args path_name path_part action_class
            index_parts
            action
        } ],

        actions => sub { _build_actions(@_) },

        experimental => [ qw{
            before_action after_action template tweak_stash
        } ],

        navigation => [
            ':default',
            (map { "menu_$_" } qw{ label parent args cond order roles title }),
        ],

        action_role  => [ qw{ does }        ],
        simple_login => [ qw{ needs_login } ],
    },
};

sub index_parts() { (path_name(q{}), args(0)) }
sub action(&)     { return shift              }

# experimental - beore/after wrappers for our action method
sub before_action(&) { ( _before => $_[0] ) }
sub after_action(&)  { ( _after  => $_[0] ) }

#sub template($)    { my $t = shift; (_before => sub    { $_[1]->stash-> { template} = $t }) }
sub tweak_stash($$) { my ($k, $v) = @_; (_before => sub { $_[1]->stash-> { $k} = $v })       }
sub template($)     { tweak_stash(template => $_[0])                                         }

# standard atts
sub chained($)      { _att(Chained     => @_) }
sub args($)         { _att(Args        => @_) }
sub capture_args($) { _att(CaptureArgs => @_) }
sub path_part($)    { _att(PathPart    => @_) }
sub path_name($)    { _att(Path        => @_) }
sub action_class($) { _att(ActionClass => @_) }

# Catalyst::Plugin::Navigation specific bits
sub menu_label($)  { _att(Menu       => @_) }
sub menu_parent($) { _att(MenuParent => @_) }
sub menu_args($)   { _att(MenuArgs   => @_) }
sub menu_cond($)   { _att(MenuCond   => @_) }
sub menu_order($)  { _att(MenuOrder  => @_) }
sub menu_roles($)  { _att(MenuRoles  => @_) }
sub menu_title($)  { _att(MenuTitle  => @_) }

# Catalyst::Plugin::ActionRole
sub does($) { _att(Does => @_) }

# CatalystX::SimpleLogin
sub needs_login() { does 'NeedsLogin' }

sub _att { ( shift(@_) => [ @_ ] ) }

# XXX
my %counter = ();

sub _add_path {
    my ($path, $meta, $name, @args) = @_;
    my $sub = pop @args;

    # default
    do { push @args, $sub; $sub = sub {} }
        unless $sub && ref $sub eq 'CODE';

    $counter{$meta->name} ||= 0;

    # XXX squash them down before adding to config
    #my $action_attributes = { @$path, @args };
    my $action_attributes = Hash::MultiValue->new(@$path, @args);

    my @before = $action_attributes->get_all('_before');
    delete $action_attributes->{'_before'};
    my @after = $action_attributes->get_all('_after');
    delete $action_attributes->{'_after'};

    # some menu defaults
    if (exists $action_attributes->{Menu}) {

        $action_attributes->{MenuOrder} = $counter{$meta->name} += 10
            unless exists $action_attributes->{MenuOrder};
    }

    # so there's two ways (I know of) to proceed here...  The first (and the
    # one we use) is to poke at our class' config() and establish our actions
    # here.  The second would be to fiddle with the method's metaclass to add
    # attributes to it.  Both allow the standard action discovery to work, but
    # the config method seems a little less magical, so that's what we're
    # using right now.
    #
    # ...and by "less magical" I mean "without the additional metaclass
    # tinkering that would be necessary".

    $meta->name->config->{actions}->{$name} = $action_attributes;

    # handle either a method name or a coderef to be installed
    # XXX broken
    $meta->add_method($name => sub { goto &$sub })
        if (ref $sub || 'nope') eq 'CODE';

    $meta->add_before_method_modifier($name => $_) for @before;
    $meta->add_after_method_modifier($name => $_) for @after;

    return;
}

# Catalyst::Controller::REST
#sub rest { _att(ActionClass => 'REST') }
#sub rest() { action_class 'REST' }
#sub public_rest { public(_att(ActionClass => 'REST'), @_) }

#sub rest(&)   { (action_class 'REST', action_method => shift) }
#sub http_get(&)    { ... }
#sub http_put(&)    { ... }
#sub http_post(&)   { ... }
#sub http_delete(&) { ... }

sub _builder {
    my ($pathref, $class, $name, $arg, $col) = @_;

    my $into = $col->{INIT}->{into};
    return sub { _add_path($pathref, $into->meta, @_) };
}

sub _build_public {
    my ($class, $name, $arg, $col) = @_;

    my $into = $col->{INIT}->{into};
    return sub { _add_path([ Path => $_[0]], $into->meta, @_) };
}

sub _action {
    my ($pathref, $class, $name, $arg, $col) = @_;

    my %opts = (
        default => [ path_name(q{})             ],
        index   => [ index_parts                ],
        begin   => [                            ],
        end     => [ action_class('RenderView') ],
        auto    => [                            ],
    );



( run in 2.273 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )