Skip to content

Commit

Permalink
copy Dispatcher from the November repo, continue work here
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilya Belikin committed Apr 1, 2009
1 parent 82035d5 commit 5191b21
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 0 deletions.
45 changes: 45 additions & 0 deletions lib/Dispatcher.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class Dispatcher {
use Dispatcher::Rule;

has @.rules;
has $.default is rw;

multi method add (Dispatcher::Rule $rule) {
die "Only complete rules allowed" unless $rule.?is_complete;
@!rules.push($rule);
}

multi method add (@pattern, Code $code) {
my $rule = Dispatcher::Rule.new( pattern => @pattern, code => $code );
@!rules.push($rule);
}

multi method add (@rules) {
# RAKUDO: rakudo doesn't know return values in for loops yet
my $r;
# RAKUDO: Larry -- "the default parameter to a block is now Object and
# not Any" but this is NIY
for @rules -> Object @pattern, $action {
$r = self.add(@pattern, $action);
}
return $r;
}

method dispatch (@chunks) {
my @matched = @!rules.grep: { .match(@chunks) };

if @matched {
my $result = @matched[*-1].apply;
.clear for @!rules;
return $result;
}
elsif defined $.default {
$.default();
}
else {
return Failure;
}
}
}

# vim:ft=perl6
58 changes: 58 additions & 0 deletions lib/Dispatcher/Rule.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
class Dispatcher::Rule;
has @.pattern;
has @.args;

has Str $.controller is rw;
has Str $.action is rw;

has Code $.code;

method match (@chunks) {
return False if @chunks != @!pattern;
for @chunks Z @!pattern-> $chunk, Object $rule is copy {

my $param;
if $rule ~~ Pair { ($param, $rule) = $rule.kv }

if ~$chunk ~~ $rule {
if $param {
self."$param" = (~$/ || ~$chunk);
} else {
# RAKUDO: /./ ~~ Regex us false, but /./ ~~ Code is true
@!args.push($/ || $chunk) if $rule ~~ Code | Whatever; # should by Regex | Whatever
}
}
else {
self.clear;
return False;
}
}
return True;
}

method apply {
# RAKUDO: die with FixedIntegerArray: index out of bounds! on test 01/3
#$!code(| @!args, controller => $.controller, action => $.action );
# workaround:
if $!controller and $!action {
$!code(| @!args,action => $.action, controller => $.controller );
} elsif $!action {
$!code(| @!args, action => $.action );
} elsif $!controller {
$!code(| @!args, controller => $.controller );
} else {
$!code(| @!args );
}
}

method is_complete {
return ?( @!pattern && $!code );
}

method clear {
@!args = ();
$!controller = undef;
$!action = undef;
}

# vim:ft=perl6
43 changes: 43 additions & 0 deletions t/dispatcher/01-basics.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use v6;

use Test;
plan 8;

use Dispatcher;
ok(1,'We use Dispatcher and we are still alive');

use Dispatcher::Rule;
ok(1,'We use Dispatcher::Rule and we are still alive');

my $d = Dispatcher.new;

dies_ok( { $d.add: Dispatcher::Rule.new },
'.add adds only complete Rule objects' );

$d.add: Dispatcher::Rule.new( :pattern(['']), code => { "Krevedko" } );

is( $d.dispatch(['']),
'Krevedko',
"Pattern ['']"
);

ok( $d.add( ['foo', 'bar'], { "Yay" } ),
'.add(@pattern, $code) -- shortcut for fast add Rule object' );

nok( $d.dispatch(['foo']),
'Dispatcher return False if can`t find matched Rule and do not have default' );


is( $d.dispatch(['foo', 'bar']),
"Yay",
"Dispatch to Rule ['foo', 'bar'])"
);

$d.default = { "Woow" };

is( $d.dispatch(['foo', 'bar', 'baz']),
"Woow",
'Dispatch to default, when have no matched Rule'
);

# vim:ft=perl6
23 changes: 23 additions & 0 deletions t/dispatcher/02-add_rules.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use v6;

use Test;
plan 5;

use Dispatcher;

my $d = Dispatcher.new;

my @rules =
['foo'], { "A" },
[/\d+/], { "B" },
['foo', 'bar'], { "C" },
['her'|'boo'], { "D" };

is($d.add(@rules), 4, "add list of rules, get the number added back");

is($d.dispatch(['foo']), "A", "Dispatch rule ['foo']");
is($d.dispatch(['123']), "B", "Dispatch rule /\\d+/");
is($d.dispatch(['foo', 'bar']), "C", "Dispatch ['foo', 'bar']");
is($d.dispatch(['boo']), "D", "Dispatch ['boo']");

# vim:ft=perl6
26 changes: 26 additions & 0 deletions t/dispatcher/03-whatever.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use v6;
use Test;
plan 5;

use Dispatcher;

my $d = Dispatcher.new( default => { "default" } );

$d.add(
[
[*,], { $^a },
[*,*], { $^a + $^b },
['foo', *], { 'foo/' ~ $^a },
['foo', *, *], { 'foo:' ~ $^a - $^b },
['foo', *, 'bar'], { $^b },
]
);

is( $d.dispatch([42]), 42, 'Pattern *' );
is( $d.dispatch([1, 2]), 3, 'Pattern */* ' );
is( $d.dispatch(['foo', '5']), "foo/5", 'Pattern foo/*' );
is( $d.dispatch(['foo', '5', 1]), "foo:4", 'Pattern foo/*/*' );
is( $d.dispatch(['foo', 'baz', 'bar']), "baz", 'Pattern foo/*/bar' );


# vim:ft=perl6
48 changes: 48 additions & 0 deletions t/dispatcher/04-regexs.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use v6;

use Test;
plan 6;

use Dispatcher;
my $d = Dispatcher.new;
$d.add: [
['foo', /^ \d+ $/], { $^d },
[/^ \w+ $/], { "Yep!" if $^w.WHAT eq 'Match' },
['foo', / \d+ /], { $^d + 10 },
['foo', / \d+ /, 'bar' ], { $^d + 1 },
['summ', / \d+ /, / \d+ / ], { $^a + $^b },
['summ', / \w+ /, 1|2 ], { $^a ~ "oo" }
];


is( $d.dispatch(['foo']),
'Yep!',
"Pattern with regex \w+, put Match in args"
);

is( $d.dispatch(['foo', '50']),
'60',
"Dispatch ['foo', '50'] to last matched Rule"
);

is( $d.dispatch(['foo', 'a50z']),
'60',
'Pattern with regex \d, put Match in args'
);

is( $d.dispatch(['foo', 'item4', 'bar']),
'5',
'Pattern with regexp in the middle (foo/\d+/bar)'
);

is( $d.dispatch(['summ', '2', '3']),
'5',
'Pattern with two regexs'
);

is( $d.dispatch(['summ', 'Z', '2']),
'Zoo',
'Pattern with regexp and junction'
);

# vim:ft=perl6
34 changes: 34 additions & 0 deletions t/dispatcher/05-junctions.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use v6;

use Test;
plan 4;

use Dispatcher;
my $d = Dispatcher.new;

$d.add: [
['foo'|'bar'], { 'First' },
['foo', 'a'|'b'], { 'Second' },
];

is( $d.dispatch(['foo']),
'First',
'Pattern with Junction (foo|bar) foo'
);

is( $d.dispatch(['bar']),
'First',
'Pattern with Junction (foo|bar) bar'
);

is( $d.dispatch(['foo', 'a']),
'Second',
'Pattern with Junction (foo/a|b) a'
);

is( $d.dispatch(['foo', 'b']),
'Second',
'Pattern with Junction (foo/a|b) b'
);

# vim:ft=perl6
30 changes: 30 additions & 0 deletions t/dispatcher/06-set-param.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use v6;

use Test;
plan 4;

use Dispatcher;
my $d = Dispatcher.new;

$d.add: [
[:controller(*), :action(*) ], { 'c:' ~ $:controller ~ ' a:' ~ $:action },
[:controller(*), / \d / ], { $:controller ~ '/' ~ $^a },
[:controller(*), *, * ], { my $c = $:controller; use "$c"; is($^a, $^b, 'Test within Rule') },
];

is( $d.dispatch(['one', 5]),
'one/5',
'Pattern set controller'
);

is( $d.dispatch(['one', 'two']),
'c:one a:two',
'Pattern set controller and action'
);

is( $d.dispatch(['Test', 3, 3]),
1,
'Pattern set controller and action'
);

# vim:ft=perl6

0 comments on commit 5191b21

Please sign in to comment.