Skip to content

Commit

Permalink
feat(rxjs-core): add mixInSubscriptionManager()
Browse files Browse the repository at this point in the history
  • Loading branch information
ersimont committed Nov 27, 2020
1 parent f39a6b9 commit c173fa5
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 29 deletions.
5 changes: 5 additions & 0 deletions projects/integration/src/app/api-tests/rxjs-core.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
mapAndCacheArrayElements,
mapAndCacheObjectElements,
mapToLatestFrom,
mixInSubscriptionManager,
skipAfter,
SubscriptionManager,
withHistory,
Expand Down Expand Up @@ -60,6 +61,10 @@ describe('rxjs-core', () => {
expect(mapToLatestFrom).toBeDefined();
});

it('has mixInSubscriptionManager', () => {
expect(mixInSubscriptionManager).toBeDefined();
});

it('has skipAfter', () => {
expect(skipAfter).toBeDefined();
});
Expand Down
1 change: 1 addition & 0 deletions projects/ng-core/src/typing-tests/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"baseUrl": "../lib",
"experimentalDecorators": true,
"paths": {
"@s-libs/js-core": ["../../../../dist/js-core"],
"@s-libs/micro-dash": ["../../../../dist/micro-dash"],
"@s-libs/rxjs-core": ["../../../../dist/rxjs-core"]
}
Expand Down
5 changes: 4 additions & 1 deletion projects/rxjs-core/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export * from './operators';
export { createOperatorFunction } from './create-operator-function';
export { logToReduxDevtoolsExtension } from './devtools/log-to-redux-devtools-extension';
export { SubscriptionManager } from './subscription-manager';
export {
mixInSubscriptionManager,
SubscriptionManager,
} from './subscription-manager';
28 changes: 27 additions & 1 deletion projects/rxjs-core/src/lib/subscription-manager.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { expectSingleCallAndReset } from '@s-libs/ng-dev';
import { of, Subject, throwError } from 'rxjs';
import { SubscriptionManager } from './subscription-manager';
import {
mixInSubscriptionManager,
SubscriptionManager,
} from './subscription-manager';

describe('SubscriptionManager', () => {
let next: jasmine.Spy;
Expand Down Expand Up @@ -132,3 +136,25 @@ describe('SubscriptionManager', () => {
});
});
});

describe('mixInSubscriptionManager()', () => {
it('add SubscriptionManager abilities to a subclass', () => {
class DateManager extends mixInSubscriptionManager(Date) {}
const spy = jasmine.createSpy();
const subject = new Subject();
const dateManager = new DateManager();

dateManager.subscribeTo(subject, spy);
subject.next('value');

expectSingleCallAndReset(spy, 'value');
});

it('retains the abilities of the other superclass', () => {
class DateManager extends mixInSubscriptionManager(Date) {}

const dateManager = new DateManager('2020-11-27');

expect(dateManager.getFullYear()).toBe(2020);
});
});
67 changes: 40 additions & 27 deletions projects/rxjs-core/src/lib/subscription-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
import { Constructor } from '@s-libs/js-core';
import { Observable, Subscription, Unsubscribable } from 'rxjs';

/**
* Mixes in {@link SubscriptionManager} as an additional superclass.
*
* ```ts
* class MySubclass extends mixInSubscriptionManager(MyOtherSuperclass) {
* subscribeAndManage(observable: Observable<any>) {
* this.subscribeTo(observable);
* }
* }
* ```
*/
// tslint:disable-next-line:typedef
export function mixInSubscriptionManager<B extends Constructor>(Base: B) {
return class extends Base implements Unsubscribable {
#subscriptions = new Subscription();

subscribeTo<T>(
observable: Observable<T>,
next?: (value: T) => void,
error?: (error: any) => void,
complete?: () => void,
): void {
this.#subscriptions.add(
observable.subscribe(
next?.bind(this),
error?.bind(this),
complete?.bind(this),
),
);
}

unsubscribe(): void {
this.#subscriptions.unsubscribe();
this.#subscriptions = new Subscription();
}
};
}

/**
* Tracks all subscriptions to easily unsubscribe from them all during cleanup. Also binds callbacks to `this` for convenient use as a superclass, e.g.:
*
Expand All @@ -19,30 +58,4 @@ import { Observable, Subscription, Unsubscribable } from 'rxjs';
* }
* ```
*/
export class SubscriptionManager implements Unsubscribable {
private subscriptions = new Subscription();

subscribeTo<T>(
observable: Observable<T>,
next?: (value: T) => void,
error?: (error: any) => void,
complete?: () => void,
): void {
this.subscriptions.add(
observable.subscribe(
this.bind(next),
this.bind(error),
this.bind(complete),
),
);
}

unsubscribe(): void {
this.subscriptions.unsubscribe();
this.subscriptions = new Subscription();
}

private bind<T extends (val?: any) => void>(fn?: T): T | undefined {
return fn?.bind(this);
}
}
export class SubscriptionManager extends mixInSubscriptionManager(Object) {}

0 comments on commit c173fa5

Please sign in to comment.