diff --git a/.idea/runConfigurations/All_Route_Tests.xml b/.idea/runConfigurations/All_Route_Tests.xml
new file mode 100644
index 00000000..cc751b12
--- /dev/null
+++ b/.idea/runConfigurations/All_Route_Tests.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/All_Router_Tests.xml b/.idea/runConfigurations/All_Router_Tests.xml
new file mode 100644
index 00000000..a1920311
--- /dev/null
+++ b/.idea/runConfigurations/All_Router_Tests.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Fallback.xml b/.idea/runConfigurations/Fallback.xml
new file mode 100644
index 00000000..4e88d8db
--- /dev/null
+++ b/.idea/runConfigurations/Fallback.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/No_Params.xml b/.idea/runConfigurations/No_Params.xml
new file mode 100644
index 00000000..b1e8cfdf
--- /dev/null
+++ b/.idea/runConfigurations/No_Params.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Parse_Params.xml b/.idea/runConfigurations/Parse_Params.xml
new file mode 100644
index 00000000..b5ef0380
--- /dev/null
+++ b/.idea/runConfigurations/Parse_Params.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/With_Params.xml b/.idea/runConfigurations/With_Params.xml
new file mode 100644
index 00000000..1d95c2c7
--- /dev/null
+++ b/.idea/runConfigurations/With_Params.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index c5ca5c37..95659a0f 100644
--- a/README.md
+++ b/README.md
@@ -112,8 +112,6 @@ To prevent this for a given anchor, do any of the following:
* Set `rel="external"`
# Route State
-Routes can have state via the `Extensible` class, which is a simple proxy over a `Map`.
-This does not require reflection, and can be used in all Dart environments.
```dart
main() {
@@ -122,7 +120,7 @@ main() {
router.onRoute.listen((route) {
if (route == null)
throw 404;
- else route.state.foo = 'bar';
+ else route.state['foo'] = 'bar';
});
}
```
diff --git a/lib/src/extensible.dart b/lib/src/extensible.dart
index a96ec806..1dd58a26 100644
--- a/lib/src/extensible.dart
+++ b/lib/src/extensible.dart
@@ -11,6 +11,9 @@ class Extensible {
/// Useful for configuration and extension.
Map properties = {};
+ operator [](key) => properties[key];
+ operator []=(key, value) => properties[key] = value;
+
noSuchMethod(Invocation invocation) {
if (invocation.memberName != null) {
String name = _sym.firstMatch(invocation.memberName.toString()).group(1);
@@ -20,9 +23,6 @@ class Extensible {
invocation.namedArguments);
} else if (invocation.isGetter) {
return properties[name];
- } else if (invocation.isSetter) {
- return properties[name.replaceAll(_equ, '')] =
- invocation.positionalArguments.first;
}
}
diff --git a/lib/src/route.dart b/lib/src/route.dart
index 4287a8a8..38301c8d 100644
--- a/lib/src/route.dart
+++ b/lib/src/route.dart
@@ -185,9 +185,10 @@ class Route {
Map parseParameters(String requestPath) {
Map result = {};
- Iterable values = _parseParameters(requestPath.replaceAll(_straySlashes, ''));
- Iterable matches = _param.allMatches(
- _pathified.replaceAll(new RegExp('\/'), r'\/'));
+ Iterable values =
+ _parseParameters(requestPath.replaceAll(_straySlashes, ''));
+ Iterable matches =
+ _param.allMatches(_pathified.replaceAll(new RegExp('\/'), r'\/'));
for (int i = 0; i < matches.length; i++) {
Match match = matches.elementAt(i);
String paramName = match.group(1);
@@ -204,14 +205,13 @@ class Route {
_parseParameters(String requestPath) sync* {
Match routeMatch = matcher.firstMatch(requestPath);
- for (int i = 1; i <= routeMatch.groupCount; i++)
- yield routeMatch.group(i);
+ for (int i = 1; i <= routeMatch.groupCount; i++) yield routeMatch.group(i);
}
Route resolve(String path, [bool filter(Route route)]) {
final _filter = filter ?? (_) => true;
- if (path.isEmpty || path == '.' && _filter(this)) {
+ if ((path.isEmpty || path == '.') && _filter(this)) {
return this;
} else if (path.replaceAll(_straySlashes, '').isEmpty) {
for (Route route in children) {
@@ -234,18 +234,24 @@ class Route {
path[1] != '/' &&
absoluteParent != null) {
return absoluteParent.resolve(path.substring(1), _filter);
+ } else if (matcher.hasMatch(path.replaceAll(_straySlashes, '')) ||
+ _resolver.hasMatch(path.replaceAll(_straySlashes, ''))) {
+ return this;
} else {
- final segments = path.split('/');
+ final segments = path.split('/').where((str) => str.isNotEmpty).toList();
if (segments[0] == '..') {
if (parent != null)
return parent.resolve(segments.skip(1).join('/'), _filter);
else
throw new RoutingException.orphan();
+ } else if (segments[0] == '.') {
+ return resolve(segments.skip(1).join('/'), _filter);
}
for (Route route in children) {
final subPath = '${this.path}/${segments[0]}';
+ print('Subpath for $path on ${this.path} = $subPath');
if (route.match(subPath) != null ||
route._resolver.firstMatch(subPath) != null) {
@@ -259,6 +265,8 @@ class Route {
// Try to match the whole route, if nothing else works
for (Route route in children) {
+ print(
+ 'Full path is $path, path is ${route.path}, matcher: ${route.matcher.pattern}, resolver: ${route._resolver.pattern}');
if ((route.match(path) != null ||
route._resolver.firstMatch(path) != null) &&
_filter(route))
diff --git a/test/index.html b/test/index.html
new file mode 100644
index 00000000..d1cbd0f0
--- /dev/null
+++ b/test/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+ Tests
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/route/with_params.dart b/test/route/with_params.dart
index 603f7714..1a8d0609 100644
--- a/test/route/with_params.dart
+++ b/test/route/with_params.dart
@@ -1,3 +1,64 @@
-main() {
+import 'package:angel_route/angel_route.dart';
+import 'package:test/test.dart';
-}
\ No newline at end of file
+main() {
+ final base = new Route('foo');
+ final foo = base.child(':id([0-9]+)', handlers: ['bar']);
+ final bar = foo.child('/bar');
+ final baz = bar.child('//////baz//////', handlers: ['hello', 'world']);
+
+ test('matching', () {
+ expect(foo.children.length, equals(1));
+ expect(foo.handlers.length, equals(1));
+ expect(foo.handlerSequence.length, equals(1));
+ expect(foo.path, equals('foo/:id'));
+ expect(foo.match('/foo/2'), isNotNull);
+ expect(foo.match('/foo/aaa'), isNull);
+ expect(foo.match('/bar'), isNull);
+ expect(foo.match('/foolish'), isNull);
+ expect(foo.parent, equals(base));
+ expect(foo.absoluteParent, equals(base));
+
+ expect(bar.path, equals('foo/:id/bar'));
+ expect(bar.children.length, equals(1));
+ expect(bar.handlers, isEmpty);
+ expect(bar.handlerSequence.length, equals(1));
+ expect(bar.match('/foo/2/bar'), isNotNull);
+ expect(bar.match('/bar'), isNull);
+ expect(bar.match('/foo/a/bar'), isNull);
+ expect(bar.parent, equals(foo));
+ expect(baz.absoluteParent, equals(base));
+
+ expect(baz.children, isEmpty);
+ expect(baz.handlers.length, equals(2));
+ expect(baz.handlerSequence.length, equals(3));
+ expect(baz.path, equals('foo/:id/bar/baz'));
+ expect(baz.match('/foo/2A/bar/baz'), isNull);
+ expect(baz.match('/foo/2/bar/baz'), isNotNull);
+ expect(baz.match('/foo/1337/bar/baz'), isNotNull);
+ expect(baz.match('/foo/bat/baz'), isNull);
+ expect(baz.match('/foo/bar/baz/1'), isNull);
+ expect(baz.parent, equals(bar));
+ expect(baz.absoluteParent, equals(base));
+ });
+
+ test('hierarchy', () {
+ expect(foo.resolve('/foo/2'), equals(foo));
+
+ expect(foo.resolve('/foo/2/bar'), equals(bar));
+ expect(foo.resolve('/foo/bar'), isNull);
+ expect(foo.resolve('foo/1337/bar/baz'), equals(baz));
+
+ expect(bar.resolve('..'), equals(foo));
+ expect(bar.resolve('/bar/baz'), equals(baz));
+ expect(bar.resolve('../bar'), equals(bar));
+
+ expect(baz.resolve('..'), equals(bar));
+ expect(baz.resolve('../..'), equals(foo));
+ expect(baz.resolve('../baz'), equals(baz));
+ expect(baz.resolve('../../bar'), equals(bar));
+ expect(baz.resolve('../../bar/baz'), equals(baz));
+ expect(baz.resolve('/bar'), equals(bar));
+ expect(baz.resolve('/bar/baz'), equals(baz));
+ });
+}
diff --git a/test/router/all_tests.dart b/test/router/all_tests.dart
index aef587e4..fa157791 100644
--- a/test/router/all_tests.dart
+++ b/test/router/all_tests.dart
@@ -1,5 +1,6 @@
import 'package:angel_route/angel_route.dart';
import 'package:test/test.dart';
+import 'fallback.dart' as fallback;
final ABC = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
@@ -21,10 +22,12 @@ main() {
router.dumpTree();
test('extensible', () {
- router.two = 2;
- expect(router.properties['two'], equals(2));
+ router['two'] = 2;
+ expect(router.two, equals(2));
});
+ group('fallback', fallback.main);
+
test('hierarchy', () {
expect(lower.absoluteParent, equals(router.root));
expect(lower.parent.path, equals('letter/:id'));
diff --git a/test/router/fallback.dart b/test/router/fallback.dart
new file mode 100644
index 00000000..d6cd5472
--- /dev/null
+++ b/test/router/fallback.dart
@@ -0,0 +1,20 @@
+import 'package:angel_route/angel_route.dart';
+import 'package:test/test.dart';
+
+bool checkPost(Route route) => route.method == "POST";
+
+main() {
+ final router = new Router();
+
+ final userById = router.group('/user', (router) {
+ router.get('/:id', (id) => 'User $id');
+ }).resolve(':id');
+
+ final fallback = router.get('*', () => 'fallback');
+
+ test('resolve', () {
+ expect(router.resolve('/foo'), equals(fallback));
+ expect(router.resolve('/user/:id'), equals(userById));
+ expect(router.resolve('/user/:id', checkPost), isNull);
+ });
+}