File Coverage

blib/lib/CGI/Application/Plugin/ActionDispatch.pm
Criterion Covered Total %
statement 101 101 100.0
branch 30 34 88.2
condition 3 8 37.5
subroutine 19 19 100.0
pod 1 6 16.6
total 154 168 91.6


line stmt bran cond sub pod time code
1             package CGI::Application::Plugin::ActionDispatch;
2              
3 7     7   420335 use strict;
  7         18  
  7         282  
4 7     7   8939 use Data::Dumper;
  7         67507  
  7         686  
5 7     7   6586 use Class::Inspector;
  7         54187  
  7         364  
6 7     7   6304 use CGI::Application::Plugin::ActionDispatch::Attributes;
  7         25  
  7         1601  
7             require Exporter;
8              
9             our $VERSION = '0.99';
10             our @ISA = qw(Exporter);
11             our @EXPORT = qw(action_args);
12              
13             our %_attr_cache;
14             my %methods;
15              
16             sub CGI::Application::Path :ATTR {
17 11     11 0 27 my ($class, $referent, $attr, $data) = @_;
18              
19 11   50     29 $data ||='';
20 11         28 $data =~ s/\/$//;
21 11 100       41 unless( $data =~ /^\// ) {
22 4         11 $data = "/" . $data;
23             }
24              
25 11         238 my $regex = qr/^$data\/?(\/.*)?$/;
26 11         21 push(@{ $_attr_cache{$class}{$attr} }, [ $referent, $regex ]);
  11         2318  
27 7     7   44 }
  7         13  
  7         114  
28              
29             sub CGI::Application::Regex :ATTR {
30 2     2 0 8 my ($package, $referent, $attr, $data) = @_;
31 2         42 my $regex = qr/$data/;
32 2         5 push(@{ $_attr_cache{$package}{$attr} }, [$referent, $regex ]);
  2         15  
33 7     7   1759 }
  7         13  
  7         54  
34              
35             sub CGI::Application::Runmode :ATTR {
36 2     2 0 6 my ($package, $referent, $attr, $data) = @_;
37              
38 2         6 $data = $methods{$referent};
39 2         76 my $regex = qr/^\/$data\/?$/;
40 2         7 push(@{ $_attr_cache{$package}{$attr} }, [ $referent, $regex ]);
  2         21  
41 7     7   1217 }
  7         41  
  7         31  
42              
43             sub CGI::Application::Default :ATTR {
44 4     4 0 15 my ($package, $referent, $attr, $data) = @_;
45 4         25 $_attr_cache{$package}{$attr} = $referent;
46 7     7   1069 }
  7         13  
  7         28  
47              
48             sub CGI::Application::ErrorRunmode :ATTR {
49 1     1 0 3 my ($package, $referent, $attr, $data) = @_;
50 1         5 $_attr_cache{$package}{$attr} = $referent;
51 7     7   1037 }
  7         11  
  7         54  
52              
53             sub import {
54 7     7   71 my $caller = caller;
55 7         82 $caller->add_callback('init', \&_ad_init);
56 7         120 $caller->add_callback('prerun', \&_ad_prerun);
57 7         1808 goto &Exporter::import;
58             }
59              
60             sub _ad_init {
61 21     21   40143 my $self = shift;
62 21   33     87 my $class = ref $self || $self;
63              
64             # Setup a hash table of all the methods in the class.
65 21 50       409 $methods{$self->can($_)} = $_
66 21         37 foreach @{ Class::Inspector->methods($class) || [] }; #NOTE: This will search through ISA also.
67            
68 21         22163 CGI::Application::Plugin::ActionDispatch::Attributes::init();
69              
70 21 100       438 if(defined $_attr_cache{$class}{'Default'}) {
71 15         45 my $runmode = $methods{$_attr_cache{$class}{'Default'}};
72 15         58 $self->start_mode($runmode);
73 15         195 $self->run_modes($runmode => $runmode);
74             }
75              
76 21 100       519 if(defined $_attr_cache{$class}{'ErrorRunmode'}) {
77 1         6 $self->error_mode($methods{$_attr_cache{$class}{'ErrorRunmode'}});
78             }
79             }
80              
81             sub _ad_prerun {
82 21     21   54629 my $self = shift;
83 21   33     95 my $class = ref $self || $self;
84              
85 21 100       85 return unless defined $ENV{PATH_INFO};
86              
87 18         61 my $start_mode = $self->start_mode();
88 18         214 ATTR: foreach my $type (qw( Runmode Regex Path )) {
89 46         273 my($code, @args) = _match_type($class, $type, $ENV{PATH_INFO});
90 46 100       168 if($code) {
91             # Make sure the runmode isn't set already and prerun_mode isn't set.
92 17 50       68 if(! $self->prerun_mode()) {
93             # Sorta of a hack here to actually get the runmode to run.
94 17         271 my $runmode = $methods{$code};
95 17         57 $self->run_modes($runmode => $runmode);
96 17         989 $self->prerun_mode($runmode);
97              
98             # Set the action_args array.
99 17         178 $self->action_args(@args);
100             }
101              
102 17         74 last ATTR;
103             }
104             }
105             }
106              
107             sub _match_type {
108 46     46   87 my($class, $type, $path_info) = @_;
109              
110 46         50 my $min;
111 46         59 my(@path_args, $code);
112 46         54 foreach my $attr (@{ $_attr_cache{$class}{$type} }) {
  46         132  
113 49 100       365 if(my @args = ($path_info =~ $attr->[1])) {
114             # We want to match the most accurate Path(). This is
115             # done by counting the args, and finding the Path with
116             # the fewest amount of args left over.
117 18 100       54 if($type eq 'Path') {
118 13 100       38 if(defined($args[0])) {
119 5         24 $args[0] =~ s/^\///;
120 5         23 @path_args = split('/', $args[0]);
121             }
122              
123             # Set min if not defined.
124 13 100       46 $min = scalar(@path_args) if( not defined $min );
125              
126             # If complete match return.
127 13 100       37 if( scalar(@path_args) == 0 ) {
    50          
128 8         30 return ($attr->[0], undef);
129             } elsif(scalar(@path_args) <= $min) {
130             # Has fewest @path_args so far.
131 5         11 $min = scalar(@path_args);
132 5         18 $code = $attr->[0];
133             }
134             } else {
135 5         27 return ($attr->[0], @args);
136             }
137             }
138             }
139 33 100       132 return @path_args ? ($code, @path_args) : 0;
140             }
141              
142             sub action_args {
143 24     24 1 488 my($self, @args) = @_;
144              
145             # If args are passed set them.
146 24 100       72 if(@args) {
147 17         54 $self->{__CAP_ACTION_ARGS} = [ @args ];
148 17         43 return;
149             }
150              
151 7 50       25 return undef unless defined $self->{__CAP_ACTION_ARGS};
152 7 100       22 return wantarray ? @{$self->{__CAP_ACTION_ARGS}} : shift @{$self->{__CAP_ACTION_ARGS}};
  6         24  
  1         5  
153             }
154            
155             1;
156             __END__