Skip to content

Commit

Permalink
Merge pull request #3365 from benlesh/refactor-using
Browse files Browse the repository at this point in the history
refactor(using): using is now just a function
  • Loading branch information
benlesh authored Mar 8, 2018
2 parents 35bb058 + 7f48ff0 commit 2507518
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 100 deletions.
19 changes: 8 additions & 11 deletions spec/observables/using-spec.ts
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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();
}
};
});
}

0 comments on commit 2507518

Please sign in to comment.