Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 103 lines (92 sloc) 2.808 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
use Faz::Action;
use Faz::Action::Public;
# the dispatcher catalogs all actions, and is responsible for
# actually trying to invoke them
role Faz::Dispatcher {
  has %!actions;
  has @!public;
  has $!regex;

  method register-action (Faz::Action $a) {
    fail 'Duplicated action'
      if %!actions.exists($a.private-name);
    %!actions{$a.private-name} = $a;
    @!public = @(%!actions.values.grep: { $_ ~~ Faz::Action::Public }).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 {
    warn "Registered Actions ({%!actions.keys.elems}):";
    warn join "\n", %!actions.keys;

    warn "Public Actions ({@!public.elems}):";
    warn join "\n", map { .private-name }, @!public;

    my sub buildspec($act) {
      my &action_capture = $act.regex;
      my &closure = -> $/ {
        make $act;
        my $in = $/.new($/);
        $in.to = $in.from; $in;
      };
      if $act.parent {
        my &parent_action_capture = buildspec($act.parent);
        my $t = token { <parent_action_capture> <action_capture> <?closure> };
        return $t;
      } else {
        my $t = token { <action_capture> <?closure> };
        return $t;
      }
    }

    my @subregexes = map { buildspec($_) }, @!public;

    my &subrx = sub ($/) {
      for @subregexes -> &eachrx {
        my $match = Match.new($/);
        my $result = eachrx($match);
        if $result {
           return $result;
        };
      };
      return Match.new($/);
    };

    warn 'Compiling regexes.';
    $!regex = token { <subrx> };

    # I get a null pmc in isa_pmc() if without this line...
    1;
  }

  method dispatch() {
    unless defined $!regex {
      warn 'Compiling regexes at dispatch time.';
      self.compile;
    }
    if $*request.uri.path ~~ $!regex {
      my $action = $<subrx>.ast;
      warn "Path '{$*request.uri.path}' matched '{$action.private-name}'";
      my %named = %($<subrx><action_capture>);
      my @pos = @($<subrx><action_capture>);
      %named<parent_action_capture> = $<subrx><parent_action_capture>;
      self.run-action($action, |@pos, |%named );
    } else {
      warn "No action matched '{$*request.uri.path}'";
      1;
    }
  }

  method run-action($action, *@pos, *%named) {
    $*action = $action;
    my $errors is context<rw>;
    {
      $action.*begin(|@pos, |%named);
      $action.*execute(|@pos, |%named);
      CATCH {
        say $!;
        $errors = $! if $!;
      }
    }
    $action.*finish(|@pos, |%named);
# TODO: rakudo don't know how to handle control exceptions yet.
# CONTROL {
# when Faz::ControlExceptionDetach {
# self.run-action(%!actions{$_.path}, |$_.capture);
# }
# }
    1;
  }
}
Something went wrong with that request. Please try again.