Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(using): using is now just a function #3365

Merged
merged 2 commits into from Mar 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 8 additions & 11 deletions spec/observables/using-spec.ts
@@ -1,15 +1,12 @@
import { expect } from 'chai';
import * as Rx from '../../src/internal/Rx';
import { using, range, Subscription } from '../../src';

const Observable = Rx.Observable;
const Subscription = Rx.Subscription;

describe('Observable.using', () => {
describe('using', () => {
it('should dispose of the resource when the subscription is disposed', (done) => {
let disposed = false;
const source = Observable.using(
const source = using(
() => new Subscription(() => disposed = true),
(resource) => Observable.range(0, 3)
(resource) => range(0, 3)
)
.take(2);

Expand All @@ -26,7 +23,7 @@ describe('Observable.using', () => {
const expected = 42;

let disposed = false;
const e1 = Observable.using(
const e1 = using(
() => new Subscription(() => disposed = true),
(resource) => new Promise((resolve: any) => { resolve(expected); }));

Expand All @@ -43,7 +40,7 @@ describe('Observable.using', () => {
const expected = 42;

let disposed = false;
const e1 = Observable.using(
const e1 = using(
() => new Subscription(() => disposed = true),
(resource) => new Promise((resolve: any, reject: any) => { reject(expected); }));

Expand All @@ -61,7 +58,7 @@ describe('Observable.using', () => {
const expectedError = 'expected';
const error = 'error';

const source = Observable.using(
const source = using(
() => {
throw expectedError;
},
Expand All @@ -84,7 +81,7 @@ describe('Observable.using', () => {
const error = 'error';
let disposed = false;

const source = Observable.using(
const source = using(
() => new Subscription(() => disposed = true),
(resource) => {
throw error;
Expand Down
87 changes: 0 additions & 87 deletions src/internal/observable/UsingObservable.ts

This file was deleted.

64 changes: 62 additions & 2 deletions src/internal/observable/using.ts
@@ -1,3 +1,63 @@
import { UsingObservable } from './UsingObservable';
import { Observable } from '../Observable';
import { Unsubscribable, ObservableInput } from '../types';
import { from } from './from'; // from from from! LAWL
import { EMPTY } from './empty';

export const using = UsingObservable.create;
/**
* Creates an Observable that uses a resource which will be disposed at the same time as the Observable.
*
* <span class="informal">Use it when you catch yourself cleaning up after an Observable.</span>
*
* `using` is a factory operator, which accepts two functions. First function returns a disposable resource.
* It can be an arbitrary object that implements `unsubscribe` method. Second function will be injected with
* that object and should return an Observable. That Observable can use resource object during its execution.
* Both functions passed to `using` will be called every time someone subscribes - neither an Observable nor
* resource object will be shared in any way between subscriptions.
*
* When Observable returned by `using` is subscribed, Observable returned from the second function will be subscribed
* as well. All its notifications (nexted values, completion and error events) will be emitted unchanged by the output
* Observable. If however someone unsubscribes from the Observable or source Observable completes or errors by itself,
* the `unsubscribe` method on resource object will be called. This can be used to do any necessary clean up, which
* otherwise would have to be handled by hand. Note that complete or error notifications are not emitted when someone
* cancels subscription to an Observable via `unsubscribe`, so `using` can be used as a hook, allowing you to make
* sure that all resources which need to exist during an Observable execution will be disposed at appropriate time.
*
* @see {@link defer}
*
* @param {function(): ISubscription} resourceFactory A function which creates any resource object
* that implements `unsubscribe` method.
* @param {function(resource: ISubscription): Observable<T>} observableFactory A function which
* creates an Observable, that can use injected resource object.
* @return {Observable<T>} An Observable that behaves the same as Observable returned by `observableFactory`, but
* which - when completed, errored or unsubscribed - will also call `unsubscribe` on created resource object.
*/
export function using<T>(resourceFactory: () => Unsubscribable | void,
observableFactory: (resource: Unsubscribable | void) => ObservableInput<T> | void): Observable<T> {
return new Observable<T>(subscriber => {
let resource: Unsubscribable | void;

try {
resource = resourceFactory();
} catch (err) {
subscriber.error(err);
return undefined;
}

let result: ObservableInput<T> | void;
try {
result = observableFactory(resource);
} catch (err) {
subscriber.error(err);
return undefined;
}

const source = result ? from(result) : EMPTY;
const subscription = source.subscribe(subscriber);
return () => {
subscription.unsubscribe();
if (resource) {
resource.unsubscribe();
}
};
});
}