Got rid of 'part', added 'export'. Also fixed attachment

This commit is contained in:
thosakwe 2016-09-15 15:53:01 -04:00
parent 6d9fa4304c
commit 4cab64f14f
24 changed files with 472 additions and 387 deletions

View file

@ -4,5 +4,4 @@
* More docs * More docs
* Make tutorials, videos * Make tutorials, videos
* Launch! * Launch!
* Get rid of `part` and `part of`, so that we can make as much isomorphic as possible
* Get a nice launch process, so we can pre-compile things before running. Also support a sort of hot-reload * Get a nice launch process, so we can pre-compile things before running. Also support a sort of hot-reload

View file

@ -2,3 +2,4 @@
library angel_framework; library angel_framework;
export 'src/http/http.dart'; export 'src/http/http.dart';
export 'src/defs.dart';

View file

@ -1,4 +1,6 @@
part of angel_framework.http; library angel_framework.extensible;
import 'dart:mirrors';
/// Supports accessing members of a Map as though they were actual members. /// Supports accessing members of a Map as though they were actual members.
class Extensible { class Extensible {

View file

@ -0,0 +1,15 @@
library angel_framework.http.angel_base;
import 'dart:async';
import 'routable.dart';
/// A function that asynchronously generates a view from the given path and data.
typedef Future<String> ViewGenerator(String path, [Map data]);
class AngelBase extends Routable {
/// A function that renders views.
///
/// Called by [ResponseContext]@`render`.
ViewGenerator viewGenerator = (String view,
[Map data]) async => "No view engine has been configured yet.";
}

View file

@ -1,4 +1,4 @@
part of angel_framework.http; library angel_framework.http.angel_http_exception;
class _AngelHttpExceptionBase implements Exception { class _AngelHttpExceptionBase implements Exception {
/// An HTTP status code this exception will throw. /// An HTTP status code this exception will throw.
@ -18,7 +18,7 @@ class _AngelHttpExceptionBase implements Exception {
return "$statusCode: $message"; return "$statusCode: $message";
} }
Map toMap() { Map toJson() {
return { return {
'isError': true, 'isError': true,
'statusCode': statusCode, 'statusCode': statusCode,
@ -26,6 +26,8 @@ class _AngelHttpExceptionBase implements Exception {
'errors': errors 'errors': errors
}; };
} }
Map toMap() => toJson();
} }
/// Basically the same as /// Basically the same as

View file

@ -1,27 +1,22 @@
part of angel_framework.http; library angel_framework.http.controller;
import 'dart:async';
import 'dart:mirrors';
import 'angel_base.dart';
import 'angel_http_exception.dart';
import 'metadata.dart';
import 'request_context.dart';
import 'response_context.dart';
import 'routable.dart';
import 'route.dart';
class Controller { class Controller {
Angel app; AngelBase app;
List middleware = []; List middleware = [];
List<Route> routes = []; List<Route> routes = [];
Map<String, Route> _mappings = {}; Map<String, Route> routeMappings = {};
Expose exposeDecl; Expose exposeDecl;
Future call(Angel app) async {
this.app = app;
Routable routable = new Routable()
..routes.addAll(routes);
app.use(exposeDecl.path, routable);
TypeMirror typeMirror = reflectType(this.runtimeType);
String name = exposeDecl.as;
if (name == null || name.isEmpty)
name = MirrorSystem.getName(typeMirror.simpleName);
app.controllers[name] = this;
}
Controller() { Controller() {
// Load global expose decl // Load global expose decl
ClassMirror classMirror = reflectClass(this.runtimeType); ClassMirror classMirror = reflectClass(this.runtimeType);
@ -91,9 +86,24 @@ class Controller {
if (name == null || name.isEmpty) if (name == null || name.isEmpty)
name = MirrorSystem.getName(key); name = MirrorSystem.getName(key);
_mappings[name] = route; routeMappings[name] = route;
} }
} }
}); });
} }
Future call(AngelBase app) async {
this.app = app;
app.use(exposeDecl.path, generateRoutable());
TypeMirror typeMirror = reflectType(this.runtimeType);
String name = exposeDecl.as;
if (name == null || name.isEmpty)
name = MirrorSystem.getName(typeMirror.simpleName);
app.controllers[name] = this;
}
Routable generateRoutable() => new Routable()..routes.addAll(routes);
} }

View file

@ -1,4 +1,11 @@
part of angel_framework.http; library angel_framework.http;
import 'dart:async';
import 'package:merge_map/merge_map.dart';
import '../util.dart';
import 'metadata.dart';
import 'route.dart';
import 'service.dart';
/// Wraps another service in a service that broadcasts events on actions. /// Wraps another service in a service that broadcasts events on actions.
class HookedService extends Service { class HookedService extends Service {
@ -38,22 +45,22 @@ class HookedService extends Service {
Map restProvider = {'provider': Providers.REST}; Map restProvider = {'provider': Providers.REST};
// Add global middleware if declared on the instance itself // Add global middleware if declared on the instance itself
Middleware before = _getAnnotation(inner, Middleware); Middleware before = getAnnotation(inner, Middleware);
if (before != null) { if (before != null) {
routes.add(new Route("*", "*", before.handlers)); routes.add(new Route("*", "*", before.handlers));
} }
Middleware indexMiddleware = _getAnnotation(inner.index, Middleware); Middleware indexMiddleware = getAnnotation(inner.index, Middleware);
get('/', (req, res) async { get('/', (req, res) async {
return await this.index(mergeMap([req.query, restProvider])); return await this.index(mergeMap([req.query, restProvider]));
}, middleware: (indexMiddleware == null) ? [] : indexMiddleware.handlers); }, middleware: (indexMiddleware == null) ? [] : indexMiddleware.handlers);
Middleware createMiddleware = _getAnnotation(inner.create, Middleware); Middleware createMiddleware = getAnnotation(inner.create, Middleware);
post('/', (req, res) async => await this.create(req.body, restProvider), post('/', (req, res) async => await this.create(req.body, restProvider),
middleware: middleware:
(createMiddleware == null) ? [] : createMiddleware.handlers); (createMiddleware == null) ? [] : createMiddleware.handlers);
Middleware readMiddleware = _getAnnotation(inner.read, Middleware); Middleware readMiddleware = getAnnotation(inner.read, Middleware);
get( get(
'/:id', '/:id',
@ -61,7 +68,7 @@ class HookedService extends Service {
.read(req.params['id'], mergeMap([req.query, restProvider])), .read(req.params['id'], mergeMap([req.query, restProvider])),
middleware: (readMiddleware == null) ? [] : readMiddleware.handlers); middleware: (readMiddleware == null) ? [] : readMiddleware.handlers);
Middleware modifyMiddleware = _getAnnotation(inner.modify, Middleware); Middleware modifyMiddleware = getAnnotation(inner.modify, Middleware);
patch( patch(
'/:id', '/:id',
(req, res) async => (req, res) async =>
@ -69,7 +76,7 @@ class HookedService extends Service {
middleware: middleware:
(modifyMiddleware == null) ? [] : modifyMiddleware.handlers); (modifyMiddleware == null) ? [] : modifyMiddleware.handlers);
Middleware updateMiddleware = _getAnnotation(inner.update, Middleware); Middleware updateMiddleware = getAnnotation(inner.update, Middleware);
post( post(
'/:id', '/:id',
(req, res) async => (req, res) async =>
@ -77,7 +84,7 @@ class HookedService extends Service {
middleware: middleware:
(updateMiddleware == null) ? [] : updateMiddleware.handlers); (updateMiddleware == null) ? [] : updateMiddleware.handlers);
Middleware removeMiddleware = _getAnnotation(inner.remove, Middleware); Middleware removeMiddleware = getAnnotation(inner.remove, Middleware);
delete( delete(
'/:id', '/:id',
(req, res) async => await this (req, res) async => await this

View file

@ -1,27 +1,16 @@
/// HTTP logic /// Various libraries useful for creating highly-extensible servers.
library angel_framework.http; library angel_framework.http;
import 'dart:async'; export 'angel_base.dart';
import 'dart:convert'; export 'angel_http_exception.dart';
import 'dart:io'; export 'controller.dart';
import 'dart:math'; export 'hooked_service.dart';
import 'dart:mirrors'; export 'metadata.dart';
import 'package:body_parser/body_parser.dart'; export 'memory_service.dart';
import 'package:json_god/json_god.dart' as god; export 'request_context.dart';
import 'package:merge_map/merge_map.dart'; export 'response_context.dart';
import 'package:mime/mime.dart'; export 'routable.dart';
import '../../defs.dart'; export 'route.dart';
export 'server.dart';
part 'controller.dart'; export 'service.dart';
part 'extensible.dart';
part 'errors.dart';
part 'metadata/metadata.dart';
part 'request_context.dart';
part 'response_context.dart';
part 'route.dart';
part 'routable.dart';
part 'server.dart';
part 'service.dart';
part 'service_hooked.dart';
part 'services/memory.dart';

View file

@ -1,4 +1,12 @@
part of angel_framework.http; library angel_framework.http.memory_service;
import 'dart:async';
import 'dart:mirrors';
import 'package:json_god/json_god.dart' as god;
import 'package:merge_map/merge_map.dart';
import '../defs.dart';
import 'angel_http_exception.dart';
import 'service.dart';
/// An in-memory [Service]. /// An in-memory [Service].
class MemoryService<T> extends Service { class MemoryService<T> extends Service {

View file

@ -1,4 +1,4 @@
part of angel_framework.http; library angel_framework.http.metadata;
/// Annotation to map middleware onto a handler. /// Annotation to map middleware onto a handler.
class Middleware { class Middleware {

View file

@ -1,18 +1,15 @@
part of angel_framework.http; library angel_framework.http.request_context;
import 'dart:async';
/// A function that intercepts a request and determines whether handling of it should continue. import 'dart:io';
typedef Future<bool> RequestMiddleware(RequestContext req, ResponseContext res); import 'package:body_parser/body_parser.dart';
import '../../src/extensible.dart';
/// A function that receives an incoming [RequestContext] and responds to it. import 'angel_base.dart';
typedef Future RequestHandler(RequestContext req, ResponseContext res); import 'route.dart';
/// A function that handles an [HttpRequest].
typedef Future RawRequestHandler(HttpRequest request);
/// A convenience wrapper around an incoming HTTP request. /// A convenience wrapper around an incoming HTTP request.
class RequestContext extends Extensible { class RequestContext extends Extensible {
/// The [Angel] instance that is responding to this request. /// The [Angel] instance that is responding to this request.
Angel app; AngelBase app;
/// Any cookies sent with this request. /// Any cookies sent with this request.
List<Cookie> get cookies => underlyingRequest.cookies; List<Cookie> get cookies => underlyingRequest.cookies;
@ -66,7 +63,7 @@ class RequestContext extends Extensible {
/// Magically transforms an [HttpRequest] into a RequestContext. /// Magically transforms an [HttpRequest] into a RequestContext.
static Future<RequestContext> from(HttpRequest request, static Future<RequestContext> from(HttpRequest request,
Map parameters, Angel app, Route sourceRoute) async { Map parameters, AngelBase app, Route sourceRoute) async {
RequestContext context = new RequestContext(); RequestContext context = new RequestContext();
context.app = app; context.app = app;

View file

@ -1,12 +1,19 @@
part of angel_framework.http; library angel_framework.http.response_context;
/// A function that asynchronously generates a view from the given path and data. import 'dart:async';
typedef Future<String> ViewGenerator(String path, [Map data]); import 'dart:convert';
import 'dart:io';
import 'package:json_god/json_god.dart' as god;
import 'package:mime/mime.dart';
import '../extensible.dart';
import 'angel_base.dart';
import 'controller.dart';
import 'route.dart';
/// A convenience wrapper around an outgoing HTTP request. /// A convenience wrapper around an outgoing HTTP request.
class ResponseContext extends Extensible { class ResponseContext extends Extensible {
/// The [Angel] instance that is sending a response. /// The [Angel] instance that is sending a response.
Angel app; AngelBase app;
/// Can we still write to this response? /// Can we still write to this response?
bool isOpen = true; bool isOpen = true;
@ -32,8 +39,7 @@ class ResponseContext extends Extensible {
/// Sends a download as a response. /// Sends a download as a response.
download(File file, {String filename}) { download(File file, {String filename}) {
header("Content-Disposition", header("Content-Disposition", 'attachment; filename="${filename ?? file.path}"');
'Content-Disposition: attachment; filename="${filename ?? file.path}"');
header(HttpHeaders.CONTENT_TYPE, lookupMimeType(file.path)); header(HttpHeaders.CONTENT_TYPE, lookupMimeType(file.path));
header(HttpHeaders.CONTENT_LENGTH, file.lengthSync().toString()); header(HttpHeaders.CONTENT_LENGTH, file.lengthSync().toString());
responseData.add(file.readAsBytesSync()); responseData.add(file.readAsBytesSync());
@ -116,7 +122,7 @@ class ResponseContext extends Extensible {
if (controller == null) if (controller == null)
throw new Exception("Could not find a controller named '${split[0]}'"); throw new Exception("Could not find a controller named '${split[0]}'");
Route matched = controller._mappings[split[1]]; Route matched = controller.routeMappings[split[1]];
if (matched == null) if (matched == null)
throw new Exception("Controller '${split[0]}' does not contain any action named '${split[1]}'"); throw new Exception("Controller '${split[0]}' does not contain any action named '${split[1]}'");
@ -147,7 +153,7 @@ class ResponseContext extends Extensible {
/// Magically transforms an [HttpResponse] object into a ResponseContext. /// Magically transforms an [HttpResponse] object into a ResponseContext.
static Future<ResponseContext> from static Future<ResponseContext> from
(HttpResponse response, Angel app) async (HttpResponse response, AngelBase app) async
{ {
ResponseContext context = new ResponseContext(response); ResponseContext context = new ResponseContext(response);
context.app = app; context.app = app;

View file

@ -1,30 +1,29 @@
part of angel_framework.http; library angel_framework.http.routable;
import 'dart:async';
import 'dart:io';
import 'dart:mirrors';
import '../extensible.dart';
import '../util.dart';
import 'angel_base.dart';
import 'controller.dart';
import 'hooked_service.dart';
import 'metadata.dart';
import 'request_context.dart';
import 'response_context.dart';
import 'route.dart';
import 'service.dart';
typedef Route RouteAssigner(Pattern path, handler, {List middleware}); typedef Route RouteAssigner(Pattern path, handler, {List middleware});
_matchingAnnotation(List<InstanceMirror> metadata, Type T) { /// A function that intercepts a request and determines whether handling of it should continue.
for (InstanceMirror metaDatum in metadata) { typedef Future<bool> RequestMiddleware(RequestContext req, ResponseContext res);
if (metaDatum.hasReflectee) {
var reflectee = metaDatum.reflectee;
if (reflectee.runtimeType == T) {
return reflectee;
}
}
}
return null;
}
_getAnnotation(obj, Type T) { /// A function that receives an incoming [RequestContext] and responds to it.
if (obj is Function || obj is Future) { typedef Future RequestHandler(RequestContext req, ResponseContext res);
MethodMirror methodMirror = (reflect(obj) as ClosureMirror).function;
return _matchingAnnotation(methodMirror.metadata, T);
} else {
ClassMirror classMirror = reflectClass(obj.runtimeType);
return _matchingAnnotation(classMirror.metadata, T);
}
return null; /// A function that handles an [HttpRequest].
} typedef Future RawRequestHandler(HttpRequest request);
/// A routable server that can handle dynamic requests. /// A routable server that can handle dynamic requests.
class Routable extends Extensible { class Routable extends Extensible {
@ -75,7 +74,7 @@ class Routable extends Extensible {
// If we need to hook this service, do it here. It has to be first, or // If we need to hook this service, do it here. It has to be first, or
// else all routes will point to the old service. // else all routes will point to the old service.
if (_routable is Service) { if (_routable is Service) {
Hooked hookedDeclaration = _getAnnotation(_routable, Hooked); Hooked hookedDeclaration = getAnnotation(_routable, Hooked);
Service service = (hookedDeclaration != null || hooked) Service service = (hookedDeclaration != null || hooked)
? new HookedService(_routable) ? new HookedService(_routable)
: _routable; : _routable;
@ -84,7 +83,7 @@ class Routable extends Extensible {
_routable = service; _routable = service;
} }
if (_routable is Angel) { if (_routable is AngelBase) {
all(path, (RequestContext req, ResponseContext res) async { all(path, (RequestContext req, ResponseContext res) async {
req.app = _routable; req.app = _routable;
res.app = _routable; res.app = _routable;
@ -135,7 +134,7 @@ class Routable extends Extensible {
List handlers = []; List handlers = [];
// Merge @Middleware declaration, if any // Merge @Middleware declaration, if any
Middleware middlewareDeclaration = _getAnnotation( Middleware middlewareDeclaration = getAnnotation(
handler, Middleware); handler, Middleware);
if (middlewareDeclaration != null) { if (middlewareDeclaration != null) {
handlers.addAll(middlewareDeclaration.handlers); handlers.addAll(middlewareDeclaration.handlers);

View file

@ -1,4 +1,4 @@
part of angel_framework.http; library angel_framework.http.route;
/// Represents an endpoint open for connection via the Internet. /// Represents an endpoint open for connection via the Internet.
class Route { class Route {

View file

@ -1,4 +1,17 @@
part of angel_framework.http; library angel_framework.http.server;
import 'dart:async';
import 'dart:io';
import 'dart:math' show Random;
import 'package:json_god/json_god.dart' as god;
import 'angel_base.dart';
import 'angel_http_exception.dart';
import 'controller.dart';
import 'request_context.dart';
import 'response_context.dart';
import 'routable.dart';
import 'route.dart';
import 'service.dart';
/// A function that binds an [Angel] server to an Internet address and port. /// A function that binds an [Angel] server to an Internet address and port.
typedef Future<HttpServer> ServerGenerator(InternetAddress address, int port); typedef Future<HttpServer> ServerGenerator(InternetAddress address, int port);
@ -7,11 +20,11 @@ typedef Future<HttpServer> ServerGenerator(InternetAddress address, int port);
typedef Future AngelErrorHandler(AngelHttpException err, RequestContext req, typedef Future AngelErrorHandler(AngelHttpException err, RequestContext req,
ResponseContext res); ResponseContext res);
/// A function that configures an [Angel] server in some way. /// A function that configures an [AngelBase] server in some way.
typedef Future AngelConfigurer(Angel app); typedef Future AngelConfigurer(AngelBase app);
/// A powerful real-time/REST/MVC server class. /// A powerful real-time/REST/MVC server class.
class Angel extends Routable { class Angel extends AngelBase {
var _beforeProcessed = new StreamController<HttpRequest>(); var _beforeProcessed = new StreamController<HttpRequest>();
var _afterProcessed = new StreamController<HttpRequest>(); var _afterProcessed = new StreamController<HttpRequest>();
var _onController = new StreamController<Controller>.broadcast(); var _onController = new StreamController<Controller>.broadcast();
@ -44,12 +57,6 @@ class Angel extends Routable {
res.end(); res.end();
}; };
/// A function that renders views.
///
/// Called by [ResponseContext]@`render`.
ViewGenerator viewGenerator = (String view,
[Map data]) async => "No view engine has been configured yet.";
/// [RequestMiddleware] to be run before all requests. /// [RequestMiddleware] to be run before all requests.
List before = []; List before = [];

View file

@ -1,4 +1,14 @@
part of angel_framework.http; library angel_framework.http.service;
import 'dart:async';
import 'package:merge_map/merge_map.dart';
import '../defs.dart';
import '../util.dart';
import 'angel_base.dart';
import 'angel_http_exception.dart';
import 'metadata.dart';
import 'routable.dart';
import 'route.dart';
/// Indicates how the service was accessed. /// Indicates how the service was accessed.
/// ///
@ -25,7 +35,7 @@ class Providers {
/// Heavily inspired by FeathersJS. <3 /// Heavily inspired by FeathersJS. <3
class Service extends Routable { class Service extends Routable {
/// The [Angel] app powering this service. /// The [Angel] app powering this service.
Angel app; AngelBase app;
/// Retrieves all resources. /// Retrieves all resources.
Future<List> index([Map params]) { Future<List> index([Map params]) {
@ -61,22 +71,22 @@ class Service extends Routable {
Map restProvider = {'provider': Providers.REST}; Map restProvider = {'provider': Providers.REST};
// Add global middleware if declared on the instance itself // Add global middleware if declared on the instance itself
Middleware before = _getAnnotation(this, Middleware); Middleware before = getAnnotation(this, Middleware);
if (before != null) { if (before != null) {
routes.add(new Route("*", "*", before.handlers)); routes.add(new Route("*", "*", before.handlers));
} }
Middleware indexMiddleware = _getAnnotation(this.index, Middleware); Middleware indexMiddleware = getAnnotation(this.index, Middleware);
get('/', (req, res) async { get('/', (req, res) async {
return await this.index(mergeMap([req.query, restProvider])); return await this.index(mergeMap([req.query, restProvider]));
}, middleware: (indexMiddleware == null) ? [] : indexMiddleware.handlers); }, middleware: (indexMiddleware == null) ? [] : indexMiddleware.handlers);
Middleware createMiddleware = _getAnnotation(this.create, Middleware); Middleware createMiddleware = getAnnotation(this.create, Middleware);
post('/', (req, res) async => await this.create(req.body, restProvider), post('/', (req, res) async => await this.create(req.body, restProvider),
middleware: middleware:
(createMiddleware == null) ? [] : createMiddleware.handlers); (createMiddleware == null) ? [] : createMiddleware.handlers);
Middleware readMiddleware = _getAnnotation(this.read, Middleware); Middleware readMiddleware = getAnnotation(this.read, Middleware);
get( get(
'/:id', '/:id',
@ -84,7 +94,7 @@ class Service extends Routable {
.read(req.params['id'], mergeMap([req.query, restProvider])), .read(req.params['id'], mergeMap([req.query, restProvider])),
middleware: (readMiddleware == null) ? [] : readMiddleware.handlers); middleware: (readMiddleware == null) ? [] : readMiddleware.handlers);
Middleware modifyMiddleware = _getAnnotation(this.modify, Middleware); Middleware modifyMiddleware = getAnnotation(this.modify, Middleware);
patch( patch(
'/:id', '/:id',
(req, res) async => (req, res) async =>
@ -92,7 +102,7 @@ class Service extends Routable {
middleware: middleware:
(modifyMiddleware == null) ? [] : modifyMiddleware.handlers); (modifyMiddleware == null) ? [] : modifyMiddleware.handlers);
Middleware updateMiddleware = _getAnnotation(this.update, Middleware); Middleware updateMiddleware = getAnnotation(this.update, Middleware);
post( post(
'/:id', '/:id',
(req, res) async => (req, res) async =>
@ -100,7 +110,7 @@ class Service extends Routable {
middleware: middleware:
(updateMiddleware == null) ? [] : updateMiddleware.handlers); (updateMiddleware == null) ? [] : updateMiddleware.handlers);
Middleware removeMiddleware = _getAnnotation(this.remove, Middleware); Middleware removeMiddleware = getAnnotation(this.remove, Middleware);
delete( delete(
'/:id', '/:id',
(req, res) async => await this (req, res) async => await this

26
lib/src/util.dart Normal file
View file

@ -0,0 +1,26 @@
import 'dart:async';
import 'dart:mirrors';
matchingAnnotation(List<InstanceMirror> metadata, Type T) {
for (InstanceMirror metaDatum in metadata) {
if (metaDatum.hasReflectee) {
var reflectee = metaDatum.reflectee;
if (reflectee.runtimeType == T) {
return reflectee;
}
}
}
return null;
}
getAnnotation(obj, Type T) {
if (obj is Function || obj is Future) {
MethodMirror methodMirror = (reflect(obj) as ClosureMirror).function;
return matchingAnnotation(methodMirror.metadata, T);
} else {
ClassMirror classMirror = reflectClass(obj.runtimeType);
return matchingAnnotation(classMirror.metadata, T);
}
return null;
}

12
test/all_tests.dart Normal file
View file

@ -0,0 +1,12 @@
import 'package:test/test.dart';
import 'controller.dart' as controller;
import 'hooked.dart' as hooked;
import 'routing.dart' as routing;
import 'services.dart' as services;
main() {
group('controller', controller.main);
group('hooked', hooked.main);
group('routing', routing.main);
group('services', services.main);
}

View file

@ -1,6 +1,8 @@
library angel_framework.test.common; library angel_framework.test.common;
class Todo { import 'package:angel_framework/src/defs.dart';
class Todo extends MemoryModel {
String text; String text;
String over; String over;

View file

@ -19,13 +19,13 @@ class TodoController extends Controller {
} }
@Expose("/namedRoute/:foo", as: "foo") @Expose("/namedRoute/:foo", as: "foo")
Future<String> someRandomRoute(RequestContext req, ResponseContext res) async { Future<String> someRandomRoute(RequestContext req,
ResponseContext res) async {
return "${req.params['foo']}!"; return "${req.params['foo']}!";
} }
} }
main() { main() {
group("controller", () {
Angel app = new Angel(); Angel app = new Angel();
HttpServer server; HttpServer server;
InternetAddress host = InternetAddress.LOOPBACK_IP_V4; InternetAddress host = InternetAddress.LOOPBACK_IP_V4;
@ -58,13 +58,15 @@ main() {
}); });
test("middleware", () async { test("middleware", () async {
var rgx = new RegExp("^Hello, world!");
var response = await client.get("$url/todos/0"); var response = await client.get("$url/todos/0");
print(response.body); print(response.body);
expect(response.body.indexOf("Hello, "), equals(0)); expect(response.body.indexOf("Hello, "), equals(0));
Map todo = JSON.decode(response.body.substring(7)); Map todo = JSON.decode(response.body.replaceAll(rgx, ""));
expect(todo.keys.length, equals(2)); print("Todo: $todo");
expect(todo.keys.length, equals(3));
expect(todo['text'], equals("Hello")); expect(todo['text'], equals("Hello"));
expect(todo['over'], equals("world")); expect(todo['over'], equals("world"));
}); });
@ -75,5 +77,4 @@ main() {
expect(response.body, equals("Hello, \"world!\"")); expect(response.body, equals("Hello, \"world!\""));
}); });
});
} }

View file

@ -5,7 +5,6 @@ import 'package:test/test.dart';
import 'common.dart'; import 'common.dart';
main() { main() {
group('Hooked', () {
Map headers = { Map headers = {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -77,5 +76,4 @@ main() {
List result = god.deserialize(response.body); List result = god.deserialize(response.body);
expect(result[0]["angel"], equals("framework")); expect(result[0]["angel"], equals("framework"));
}); });
});
} }

View file

@ -19,7 +19,6 @@ class QueryService extends Service {
} }
main() { main() {
group('routing', () {
Angel angel; Angel angel;
Angel nested; Angel nested;
Angel todos; Angel todos;
@ -31,12 +30,10 @@ main() {
nested = new Angel(); nested = new Angel();
todos = new Angel(); todos = new Angel();
angel angel..registerMiddleware('interceptor', (req, res) async {
..registerMiddleware('interceptor', (req, res) async {
res.write('Middleware'); res.write('Middleware');
return false; return false;
}) })..registerMiddleware('intercept_service',
..registerMiddleware('intercept_service',
(RequestContext req, res) async { (RequestContext req, res) async {
print("Intercepting a service!"); print("Intercepting a service!");
return true; return true;
@ -158,5 +155,4 @@ main() {
print(response.body); print(response.body);
expect(response.body, equals("Middleware")); expect(response.body, equals("Middleware"));
}); });
});
} }

View file

@ -1,4 +1,4 @@
import 'package:angel_framework/defs.dart'; import 'package:angel_framework/src/defs.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:json_god/json_god.dart' as god; import 'package:json_god/json_god.dart' as god;
@ -10,7 +10,6 @@ class Todo extends MemoryModel {
} }
main() { main() {
group('Services', () {
Map headers = { Map headers = {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -114,5 +113,4 @@ main() {
.length, equals(0)); .length, equals(0));
}); });
}); });
});
} }