Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
168 lines (140 sloc) 3.86 KB
# the controller holds information that applies to all actions
# there. The initialization will look in the config file if there is
# a definition to any of the attributes defined in the package.
role Controller {}
# this is a normal private action
role Action {
has Controller $.controller;
has Str $.private-name;
multi method begin {...}
multi method execute(*@_, *%_) {...}
multi method end {...}
}
role Action::Private {
has Callable $.begin-closure;
has Callable $.execute-closure;
has Callable $.end-closure;
multi method begin {
$.begin-closure.(self)
if $.begin-closure;
}
multi method execute(*@_, *%_) {
$.execute-closure.(self, |@_, |%_)
if $.execute-closure;
}
multi method end {
$.end-closure.(self)
if $.end-closure;
}
}
# this is an action that might be part of a chain
role Action::Chained {
has Action::Chained $.parent;
has Regex $.regex;
has Callable $.begin-closure;
has Callable $.execute-closure;
has Callable $.end-closure;
multi method begin {
$.parent.*begin
if $.parent;
$.begin-closure.(self)
if $.begin-closure;
}
multi method execute(*@_, :¢_parent_action_capture, *%_) {
$.parent.*execute(|¢_parent_action_capture)
if $.parent;
$.execute-closure.(self, |@_, |%_)
if $.execute-closure;
}
multi method end {
$.parent.*end
if $.parent;
$.end-closure.(self)
if $.end-closure;
}
}
# this is used to mask out the base-uri for the application
role Action::Root does Action::Chained {
has URI $.base;
method regex {
return / ^ $.base /;
}
}
# this is an action that is seen as an endpoint
role Action::Public does Action::Chained does Pattern {
has Int $.priority;
}
# the dispatcher catalogs all actions, and is responsible for
# actually trying to invoke them
role Dispatcher {
has %!actions;
has @!public;
has $.regex;
method register-action(Action $a) {
fail 'Duplicated action'
if %!actions.exists($a.private-name);
%!actions{$a.private-name} = $a;
if $a ~~ Action::Public {
@!public = (@!public, $a).sort { .priority };
}
}
# this method freezes the regexes, combining them into a single
# regular expression that will evaluate the request and return the
# desired action.
method compile {
my sub buildspec($act) {
if $act.parent {
my $r = buildspec($act.parent);
return / $<actcap> := ( $<_parent_action_capture> := <$r> <$act.regex> ) { make $act } /;
} else {
return / $<actcap> := <$act.regex> { make $act } /;
}
}
my @subregexes;
for @!public -> $action {
push @subregexes, buildspec($action);
}
$.regex = / $<action> := <@subregexes> /;
}
method dispatch() {
self.compile unless $.regex;
if $*request.uri.path ~~ $.regex {
self.run-action($<action><?>, |$<action><actcap>);
} else {
fail 'No action matched';
}
}
method run-action($action, *@_, *%_) {
my $errors is context<rw>;
try {
$action.*begin;
$action.*execute(|@_, |%_);
CATCH {
$_.handled = 1;
$errors = $_;
}
}
$action.*end;
CONTROL {
when ControlExceptionDetach {
self.run-action(%!actions{$_.path}, |$_.capture);
}
}
}
}
# An application has components and a dispatcher
role Application {
has %.components;
has Dispatcher $.dispatcher handles <register-action dispatch>;
# this is where the several steps performed by catalyst should
# reside, so application-wide plugins can modify
multi method prepare { ... }
multi method finalize { ... }
multi method handle($request? is context = $*request,
$response? is context = $*response) {
my $application is context = self;
self.*prepare;
self.*dispatch;
self.*finalize;
};
}