feat(facade): added support for observables
This commit is contained in:
parent
43f4374944
commit
9b3b3d325f
|
@ -50,6 +50,8 @@ var _HTML_DEFAULT_SCRIPTS_JS = [
|
||||||
{src: 'node_modules/zone.js/long-stack-trace-zone.js', mimeType: 'text/javascript', copy: true},
|
{src: 'node_modules/zone.js/long-stack-trace-zone.js', mimeType: 'text/javascript', copy: true},
|
||||||
{src: 'node_modules/systemjs/dist/system.src.js', mimeType: 'text/javascript', copy: true},
|
{src: 'node_modules/systemjs/dist/system.src.js', mimeType: 'text/javascript', copy: true},
|
||||||
{src: 'node_modules/systemjs/lib/extension-register.js', mimeType: 'text/javascript', copy: true},
|
{src: 'node_modules/systemjs/lib/extension-register.js', mimeType: 'text/javascript', copy: true},
|
||||||
|
{src: 'node_modules/systemjs/lib/extension-cjs.js', mimeType: 'text/javascript', copy: true},
|
||||||
|
{src: 'node_modules/rx/dist/rx.all.js', mimeType: 'text/javascript', copy: true},
|
||||||
{src: 'tools/build/snippets/runtime_paths.js', mimeType: 'text/javascript', copy: true},
|
{src: 'tools/build/snippets/runtime_paths.js', mimeType: 'text/javascript', copy: true},
|
||||||
{
|
{
|
||||||
inline: 'System.import(\'$MODULENAME$\').then(function(m) { m.main(); }, console.error.bind(console))',
|
inline: 'System.import(\'$MODULENAME$\').then(function(m) { m.main(); }, console.error.bind(console))',
|
||||||
|
|
|
@ -18,6 +18,8 @@ module.exports = function(config) {
|
||||||
// Including systemjs because it defines `__eval`, which produces correct stack traces.
|
// Including systemjs because it defines `__eval`, which produces correct stack traces.
|
||||||
'node_modules/systemjs/dist/system.src.js',
|
'node_modules/systemjs/dist/system.src.js',
|
||||||
'node_modules/systemjs/lib/extension-register.js',
|
'node_modules/systemjs/lib/extension-register.js',
|
||||||
|
'node_modules/systemjs/lib/extension-cjs.js',
|
||||||
|
'node_modules/rx/dist/rx.all.js',
|
||||||
'node_modules/zone.js/zone.js',
|
'node_modules/zone.js/zone.js',
|
||||||
'node_modules/zone.js/long-stack-trace-zone.js',
|
'node_modules/zone.js/long-stack-trace-zone.js',
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"traceur": "<%= packageJson.dependencies.traceur %>",
|
"traceur": "<%= packageJson.dependencies.traceur %>",
|
||||||
"rtts_assert": "<%= packageJson.version %>",
|
"rtts_assert": "<%= packageJson.version %>",
|
||||||
|
"rx": "<%= packageJson.dependencies['rx'] %>",
|
||||||
"zone.js": "<%= packageJson.dependencies['zone.js'] %>"
|
"zone.js": "<%= packageJson.dependencies['zone.js'] %>"
|
||||||
},
|
},
|
||||||
"devDependencies": <%= JSON.stringify(packageJson.devDependencies) %>
|
"devDependencies": <%= JSON.stringify(packageJson.devDependencies) %>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
library angular.core.facade.async;
|
library angular.core.facade.async;
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
export 'dart:async' show Future;
|
export 'dart:async' show Future, Stream, StreamController, StreamSubscription;
|
||||||
|
|
||||||
class PromiseWrapper {
|
class PromiseWrapper {
|
||||||
static Future resolve(obj) => new Future.value(obj);
|
static Future resolve(obj) => new Future.value(obj);
|
||||||
|
@ -32,6 +32,32 @@ class PromiseWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ObservableWrapper {
|
||||||
|
static StreamSubscription subscribe(Stream s, Function onNext, [onError, onComplete]) {
|
||||||
|
return s.listen(onNext, onError: onError, onDone: onComplete, cancelOnError: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static StreamController createController() {
|
||||||
|
return new StreamController.broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream createObservable(StreamController controller) {
|
||||||
|
return controller.stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callNext(StreamController controller, value) {
|
||||||
|
controller.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callThrow(StreamController controller, error) {
|
||||||
|
controller.addError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void callReturn(StreamController controller) {
|
||||||
|
controller.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _Completer {
|
class _Completer {
|
||||||
final Completer c;
|
final Completer c;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {int, global} from 'angular2/src/facade/lang';
|
import {int, global, isPresent} from 'angular2/src/facade/lang';
|
||||||
import {List} from 'angular2/src/facade/collection';
|
import {List} from 'angular2/src/facade/collection';
|
||||||
|
import Rx from 'rx/dist/rx.all';
|
||||||
|
|
||||||
export var Promise = global.Promise;
|
export var Promise = global.Promise;
|
||||||
|
|
||||||
|
@ -51,3 +52,47 @@ export class PromiseWrapper {
|
||||||
return maybePromise instanceof Promise;
|
return maybePromise instanceof Promise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use Rx.Observable but provides an adapter to make it work as specified here:
|
||||||
|
* https://github.com/jhusain/observable-spec
|
||||||
|
*
|
||||||
|
* Once a reference implementation of the spec is available, switch to it.
|
||||||
|
*/
|
||||||
|
export var Observable = Rx.Observable;
|
||||||
|
export var ObservableController = Rx.Subject;
|
||||||
|
|
||||||
|
export class ObservableWrapper {
|
||||||
|
static createController():Rx.Subject {
|
||||||
|
return new Rx.Subject();
|
||||||
|
}
|
||||||
|
|
||||||
|
static createObservable(subject:Rx.Subject):Observable {
|
||||||
|
return subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
static subscribe(observable:Observable, generatorOrOnNext, onThrow = null, onReturn = null) {
|
||||||
|
if (isPresent(generatorOrOnNext.next)) {
|
||||||
|
return observable.observeOn(Rx.Scheduler.timeout).subscribe(
|
||||||
|
(value) => generatorOrOnNext.next(value),
|
||||||
|
(error) => generatorOrOnNext.throw(error),
|
||||||
|
() => generatorOrOnNext.return()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return observable.observeOn(Rx.Scheduler.timeout).subscribe(generatorOrOnNext, onThrow, onReturn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static callNext(subject:Rx.Subject, value:any) {
|
||||||
|
subject.onNext(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static callThrow(subject:Rx.Subject, error:any) {
|
||||||
|
subject.onError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static callReturn(subject:Rx.Subject) {
|
||||||
|
subject.onCompleted();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el,
|
||||||
|
SpyObject, AsyncTestCompleter, inject, IS_DARTIUM} from 'angular2/test_lib';
|
||||||
|
|
||||||
|
import {ObservableWrapper, Observable, ObservableController, PromiseWrapper} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe('Observable', () => {
|
||||||
|
var obs:Observable;
|
||||||
|
var controller:ObservableController;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
controller = ObservableWrapper.createController();
|
||||||
|
obs = ObservableWrapper.createObservable(controller);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call the next callback", inject([AsyncTestCompleter], (async) => {
|
||||||
|
ObservableWrapper.subscribe(obs, (value) => {
|
||||||
|
expect(value).toEqual(99);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
ObservableWrapper.callNext(controller, 99);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should call the throw callback", inject([AsyncTestCompleter], (async) => {
|
||||||
|
ObservableWrapper.subscribe(obs, (_) => {}, (error) => {
|
||||||
|
expect(error).toEqual("Boom");
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
ObservableWrapper.callThrow(controller, "Boom");
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should call the return callback", inject([AsyncTestCompleter], (async) => {
|
||||||
|
ObservableWrapper.subscribe(obs, (_) => {}, (_) => {}, () => {
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
ObservableWrapper.callReturn(controller);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should subscribe to the wrapper asynchronously", () => {
|
||||||
|
var called = false;
|
||||||
|
ObservableWrapper.subscribe(obs, (value) => {
|
||||||
|
called = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
ObservableWrapper.callNext(controller, 99);
|
||||||
|
expect(called).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!IS_DARTIUM) {
|
||||||
|
// See here: https://github.com/jhusain/observable-spec
|
||||||
|
describe("Generator", () => {
|
||||||
|
var generator;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
generator = new SpyObject();
|
||||||
|
generator.spy("next");
|
||||||
|
generator.spy("throw");
|
||||||
|
generator.spy("return");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call next on the given generator", inject([AsyncTestCompleter], (async) => {
|
||||||
|
generator.spy("next").andCallFake((value) => {
|
||||||
|
expect(value).toEqual(99);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
ObservableWrapper.subscribe(obs, generator);
|
||||||
|
ObservableWrapper.callNext(controller, 99);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should call throw on the given generator", inject([AsyncTestCompleter], (async) => {
|
||||||
|
generator.spy("throw").andCallFake((error) => {
|
||||||
|
expect(error).toEqual("Boom");
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
ObservableWrapper.subscribe(obs, generator);
|
||||||
|
ObservableWrapper.callThrow(controller, "Boom");
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should call return on the given generator", inject([AsyncTestCompleter], (async) => {
|
||||||
|
generator.spy("return").andCallFake(() => {
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
ObservableWrapper.subscribe(obs, generator);
|
||||||
|
ObservableWrapper.callReturn(controller);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: vsavkin: add tests cases
|
||||||
|
//should call dispose on the subscription if generator returns {done:true}
|
||||||
|
//should call dispose on the subscription on throw
|
||||||
|
//should call dispose on the subscription on return
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//make sure rx observables are async
|
|
@ -27,6 +27,7 @@
|
||||||
"es6-module-loader": "^0.9.2",
|
"es6-module-loader": "^0.9.2",
|
||||||
"systemjs": "^0.9.1",
|
"systemjs": "^0.9.1",
|
||||||
"traceur": "0.0.82",
|
"traceur": "0.0.82",
|
||||||
|
"rx": "2.4.6",
|
||||||
"which": "~1",
|
"which": "~1",
|
||||||
"zone.js": "0.4.0",
|
"zone.js": "0.4.0",
|
||||||
"googleapis": "1.0.x",
|
"googleapis": "1.0.x",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Use "register" extension from systemjs.
|
// Use "register" extension from systemjs.
|
||||||
// That's what Traceur outputs: `System.register()`.
|
// That's what Traceur outputs: `System.register()`.
|
||||||
register(System);
|
register(System);
|
||||||
|
cjs(System);
|
||||||
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50;
|
||||||
|
|
||||||
|
@ -14,7 +15,8 @@ System.baseURL = '/base/modules/';
|
||||||
// So that we can import packages like `core/foo`, instead of `core/src/foo`.
|
// So that we can import packages like `core/foo`, instead of `core/src/foo`.
|
||||||
System.paths = {
|
System.paths = {
|
||||||
'*': './*.js',
|
'*': './*.js',
|
||||||
'transpiler/*': '../tools/transpiler/*.js'
|
'transpiler/*': '../tools/transpiler/*.js',
|
||||||
|
'rx/*': '../node_modules/rx/*.js'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import all the specs, execute their `main()` method and kick off Karma (Jasmine).
|
// Import all the specs, execute their `main()` method and kick off Karma (Jasmine).
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
System.paths = {
|
System.paths = {
|
||||||
'*': '/*.js'
|
'*': '/*.js',
|
||||||
|
'rx/dist/*': '*.js'
|
||||||
};
|
};
|
||||||
register(System);
|
register(System);
|
||||||
|
cjs(System);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ export var typeMapping = {
|
||||||
'string': 'String',
|
'string': 'String',
|
||||||
'any': 'dynamic',
|
'any': 'dynamic',
|
||||||
'Promise': 'Future',
|
'Promise': 'Future',
|
||||||
|
'Observable': 'Stream',
|
||||||
|
'ObservableController': 'StreamController',
|
||||||
'Date': 'DateTime',
|
'Date': 'DateTime',
|
||||||
'StringMap': 'Map'
|
'StringMap': 'Map'
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue