##// END OF EJS Templates
fixed format-compile bug while formatting strings with new line symbols....
cin -
r15:d5a3d3ab9fd7 propose cancellat...
parent child
Show More
@@ -0,0 +1,39
1 import { IObservable, ICancellation, IDestroyable } from "@implab/core/interfaces";
2 import * as TraceEvent from '@implab/core/log/TraceEvent';
3 import { Cancellation } from "@implab/core/Cancellation";
4 import * as TraceSource from "@implab/core/log/TraceSource";
5 import * as tape from 'tape';
6 import { argumentNotNull } from "@implab/core/safe";
7
8 export class TapeWriter implements IDestroyable {
9 readonly _tape: tape.Test
10
11 _subscriptions = new Array<IDestroyable>();
12
13 constructor(tape: tape.Test) {
14 argumentNotNull(tape, "tape");
15 this._tape = tape;
16 }
17
18 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
19 let subscription = source.on(this.writeEvent.bind(this));
20 if (ct.isSupported()) {
21 ct.register(subscription.destroy.bind(subscription));
22 }
23 this._subscriptions.push(subscription);
24 }
25
26 writeEvent(next: TraceEvent) {
27 if (next.level >= TraceSource.LogLevel) {
28 this._tape.comment("LOG " + next.arg);
29 } else if(next.level >= TraceSource.WarnLevel) {
30 this._tape.comment("WARN " + next.arg);
31 } else {
32 this._tape.comment("ERROR " + next.arg);
33 }
34 }
35
36 destroy() {
37 this._subscriptions.forEach(x => x.destroy());
38 }
39 } No newline at end of file
@@ -133,7 +133,7
133 },
133 },
134 "minimist": {
134 "minimist": {
135 "version": "0.0.5",
135 "version": "0.0.5",
136 "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
136 "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.5.tgz",
137 "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=",
137 "integrity": "sha1-16oye87PUY+RBqxrjwA/o7zqhWY=",
138 "dev": true
138 "dev": true
139 },
139 },
@@ -319,9 +319,9
319 }
319 }
320 },
320 },
321 "requirejs": {
321 "requirejs": {
322 "version": "2.3.6",
322 "version": "2.3.5",
323 "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
323 "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.5.tgz",
324 "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
324 "integrity": "sha512-svnO+aNcR/an9Dpi44C7KSAy5fFGLtmPbaaCeQaklUz8BQhS64tWWIIlvEA5jrWICzlO/X9KSzSeXFnZdBu8nw==",
325 "dev": true
325 "dev": true
326 },
326 },
327 "resolve": {
327 "resolve": {
@@ -413,9 +413,9
413 }
413 }
414 },
414 },
415 "typescript": {
415 "typescript": {
416 "version": "3.0.3",
416 "version": "2.9.2",
417 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.3.tgz",
417 "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
418 "integrity": "sha512-kk80vLW9iGtjMnIv11qyxLqZm20UklzuR2tL0QAnDIygIUIemcZMxlMWudl9OOt76H3ntVzcTiddQ1/pAAJMYg==",
418 "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
419 "dev": true
419 "dev": true
420 },
420 },
421 "wrappy": {
421 "wrappy": {
@@ -18,13 +18,13 define(
18 var espaceString = function(s) {
18 var espaceString = function(s) {
19 if (!s)
19 if (!s)
20 return s;
20 return s;
21 return "'" + s.replace(/('|\\)/g, "\\$1") + "'";
21 return "'" + s.replace(/('|\\)/g, "\\$1").replace("\n","\\n") + "'";
22 };
22 };
23
23
24 var encode = function(s) {
24 var encode = function(s) {
25 if (!s)
25 if (!s)
26 return s;
26 return s;
27 return s.replace(/\\{|\\}|&|\\:/g, function(m) {
27 return s.replace(/\\{|\\}|&|\\:|\n/g, function(m) {
28 return map[m] || m;
28 return map[m] || m;
29 });
29 });
30 };
30 };
@@ -4,79 +4,162 import { argumentNotNull } from '../safe
4
4
5
5
6 interface Handler<T> {
6 interface Handler<T> {
7 (x:T) : void
7 (x: T): void
8 }
8 }
9
9
10 interface Initializer<T> {
10 interface Initializer<T> {
11 (notify: Handler<T>) : (() => void) | void;
11 (notify: Handler<T>, error?: (e: any) => void, complete?: () => void): (() => void) | void;
12 }
12 }
13
13
14 // TODO: think about to move this interfaces.ts and make it public
15 interface IObserver<T> {
16 next(event: T): void
17
18 error(e: any): void
19
20 complete(): void
21 }
14
22
15 class Observable<T> implements IObservable<T>, IDestroyable {
23 class Observable<T> implements IObservable<T>, IDestroyable {
16 private _once = new Array<Handler<T>>();
24 private _once = new Array<IObserver<T>>();
25
26 private _observers = new Array<IObserver<T>>();
17
27
18 private readonly _observers = new Array<Handler<T>>();
28 private _cleanup: (() => void) | void;
19
29
20 private readonly _cleanup : (() => void) | void;
30 private _complete: boolean
31
32 private _error: any
21
33
22 constructor(func?: Initializer<T>) {
34 constructor(func?: Initializer<T>) {
23 this._cleanup = func && func(this._notify.bind(this));
35 this._cleanup = func && func(
36 this._notifyNext.bind(this),
37 this._notifyError.bind(this),
38 this._notifyCompleted.bind(this)
39 );
24 }
40 }
25
41
26 on(observer: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
42 /**
27 argumentNotNull(observer, "observer");
43 * Registers handlers for the current observable object.
28
44 *
29 this._observers.push(observer);
45 * @param next the handler for events
46 * @param error the handler for a error
47 * @param complete the handler for a completion
48 * @returns {IDestroyable} the handler for the current subscription, this
49 * handler can be used to unsubscribe from events.
50 *
51 */
52 on(next: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
53 argumentNotNull(next, "next");
30
54
31 let me = this;
55 let me = this;
32 return {
56
57 let observer: IObserver<T> & IDestroyable = {
58 next: next,
59
60 error(e: any) {
61 if (error)
62 error(e);
63 },
64
65 complete() {
66 if (complete)
67 complete();
68 },
69
33 destroy() {
70 destroy() {
34 me._removeObserver(observer);
71 me._removeObserver(this);
35 }
72 }
36 }
73 }
74
75 this._addObserver(observer);
76
77
78 return observer;
79 }
80
81 private _addObserver(observer: IObserver<T>) {
82 if (this._complete) {
83 try {
84 if (this._error)
85 observer.error(this._error);
86 else
87 observer.complete();
88 } catch (e) {
89 this.onObserverException(e);
90 }
91 } else {
92 this._observers.push(observer);
93 }
37 }
94 }
38
95
96 /**
97 * Waits for the next event. This method can't be used to read messages
98 * as a sequence since it can skip some messages between calls.
99 *
100 * @param ct a cancellation token
101 */
39 next(ct: ICancellation = Cancellation.none): Promise<T> {
102 next(ct: ICancellation = Cancellation.none): Promise<T> {
40 return new Promise<T>((resolve, reject) => {
103 return new Promise<T>((resolve, reject) => {
41 this._once.push(resolve);
104 let observer: IObserver<T> = {
42 if (ct.isSupported()) {
105 next: resolve,
106 error: reject,
107 complete: () => reject("No more events are available")
108 };
109
110 if (this._addOnce(observer) && ct.isSupported()) {
43 ct.register((e) => {
111 ct.register((e) => {
44 this._removeOnce(resolve);
112 this._removeOnce(observer);
45 reject(e);
113 reject(e);
46 });
114 });
47 }
115 }
48 });
116 });
49 }
117 }
50
118
119 private _addOnce(observer: IObserver<T>) {
120 if (this._complete) {
121 try {
122 if (this._error)
123 observer.error(this._error);
124 else
125 observer.complete();
126 } catch (e) {
127 this.onObserverException(e);
128 }
129 return false;
130 }
131
132 this._once.push(observer);
133 return true;
134 }
135
51 destroy() {
136 destroy() {
52 if(this._cleanup)
137 if (this._complete)
53 this._cleanup.call(null);
138 this._notifyCompleted();
139
140 let cleanup = this._cleanup;
141 if (cleanup) {
142 this._cleanup = null;
143 cleanup();
144 }
54 }
145 }
55
146
56 protected onObserverException(e: any) {
147 protected onObserverException(e: any) {
57 }
148 }
58
149
59 private _removeOnce(d: Handler<T>) {
150 private _removeOnce(d: IObserver<T>) {
60 let i = this._once.indexOf(d);
151 let i = this._once.indexOf(d);
61 if (i >= 0)
152 if (i >= 0)
62 this._once.splice(i);
153 this._once.splice(i);
63 }
154 }
64
155
65 private _removeObserver(d: Handler<T>) {
156 private _removeObserver(d: IObserver<T>) {
66 let i = this._observers.indexOf(d);
157 let i = this._observers.indexOf(d);
67 if (i >= 0)
158 if (i >= 0)
68 this._observers.splice(i);
159 this._observers.splice(i);
69 }
160 }
70
161
71 protected _notify(evt: T) {
162 private _notify(guard: (observer: IObserver<T>) => void) {
72 let guard = (observer: Handler<T>) => {
73 try {
74 observer(evt);
75 } catch (e) {
76 this.onObserverException(e);
77 }
78 }
79
80 if (this._once.length) {
163 if (this._once.length) {
81 for (let i = 0; i < this._once.length; i++)
164 for (let i = 0; i < this._once.length; i++)
82 guard(this._once[i]);
165 guard(this._once[i]);
@@ -86,6 +169,44 class Observable<T> implements IObservab
86 for (let i = 0; i < this._observers.length; i++)
169 for (let i = 0; i < this._observers.length; i++)
87 guard(this._observers[i]);
170 guard(this._observers[i]);
88 }
171 }
172
173 protected _notifyNext(evt: T) {
174 let guard = (observer: IObserver<T>) => {
175 try {
176 observer.next(evt);
177 } catch (e) {
178 this.onObserverException(e);
179 }
180 }
181
182 this._notify(guard);
183 }
184
185 protected _notifyError(e: any) {
186 let guard = (observer: IObserver<T>) => {
187 try {
188 observer.error(e);
189 } catch (e) {
190 this.onObserverException(e);
191 }
192 }
193
194 this._notify(guard);
195 this._observers = [];
196 }
197
198 protected _notifyCompleted() {
199 let guard = (observer: IObserver<T>) => {
200 try {
201 observer.complete();
202 } catch (e) {
203 this.onObserverException(e);
204 }
205 }
206
207 this._notify(guard);
208 this._observers = [];
209 }
89 }
210 }
90
211
91 namespace Observable {
212 namespace Observable {
@@ -67,7 +67,7 class TraceSource extends Observable<Tra
67 }
67 }
68
68
69 protected emit(level: number, arg: any) {
69 protected emit(level: number, arg: any) {
70 this._notify(new TraceEvent(this, level, arg));
70 this._notifyNext(new TraceEvent(this, level, arg));
71 }
71 }
72
72
73 isDebugEnabled() {
73 isDebugEnabled() {
@@ -1,25 +1,31
1 import { IObservable } from "../../interfaces";
1 import { IObservable, IDestroyable, ICancellation } from "../../interfaces";
2 import * as TraceEvent from '../TraceEvent';
2 import * as TraceEvent from '../TraceEvent';
3 import { ICancellation } from "../../interfaces";
4 import { Cancellation } from "../../Cancellation";
3 import { Cancellation } from "../../Cancellation";
5 import * as TraceSource from "../TraceSource";
4 import * as TraceSource from "../TraceSource";
6
5
7 class ConsoleWriter {
6 class ConsoleWriter implements IDestroyable {
8 async write(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
7 readonly _subscriptions = new Array<IDestroyable>();
9 let next;
8
10 while(next = await source.next(ct)) {
9 writeEvents(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
11 this._writeEvent(next);
10 var subscription = source.on(this.writeEvent.bind(this));
11 if (ct.isSupported()) {
12 ct.register(subscription.destroy.bind(subscription));
13 }
14 this._subscriptions.push(subscription);
15 }
16
17 writeEvent(next: TraceEvent) {
18 if (next.level >= TraceSource.LogLevel) {
19 console.log(next.source.id.toString(), next.arg);
20 } else if(next.level >= TraceSource.WarnLevel) {
21 console.warn(next.source.id.toString(), next.arg);
22 } else {
23 console.error(next.source.id.toString(), next.arg);
12 }
24 }
13 }
25 }
14
26
15 private _writeEvent(next: TraceEvent) {
27 destroy() {
16 if (next.level >= TraceSource.LogLevel) {
28 this._subscriptions.forEach(x => x.destroy());
17 console.log(next.source.toString(), next.arg);
18 } else if(next.level >= TraceSource.WarnLevel) {
19 console.warn(next.source.toString(), next.arg);
20 } else {
21 console.error(next.source.toString(), next.arg);
22 }
23 }
29 }
24 }
30 }
25
31
@@ -1,6 +1,7
1 import * as TraceSource from '@implab/core/log/TraceSource'
1 import * as TraceSource from '@implab/core/log/TraceSource'
2 import * as tape from 'tape';
2 import * as tape from 'tape';
3 import * as ConsoleWriter from '@implab/core/log/writers/ConsoleWriter';
3 import * as ConsoleWriter from '@implab/core/log/writers/ConsoleWriter';
4 import { TapeWriter } from './TestTraits';
4
5
5 const sourceId = 'test/TraceSourceTests';
6 const sourceId = 'test/TraceSourceTests';
6
7
@@ -44,19 +45,26 tape('trace event', t => {
44 h.destroy();
45 h.destroy();
45 });
46 });
46
47
47 tape('console writer', async t => {
48 tape('tape comment writer', async t => {
48 let writer = new ConsoleWriter();
49 let writer = new TapeWriter(t);
50
51 TraceSource.on(ts => {
52 writer.writeEvents(ts);
53 });
49
54
50 let trace = TraceSource.get(sourceId);
55 let trace = TraceSource.get(sourceId);
51 trace.level = TraceSource.DebugLevel;
56 trace.level = TraceSource.DebugLevel;
52
57
53 let p = writer.write(trace);
54
55 trace.log("Hello, {0}!", 'World');
58 trace.log("Hello, {0}!", 'World');
59 trace.log("Multi\n line");
56 trace.warn("Look at me!");
60 trace.warn("Look at me!");
57 trace.error("DIE!");
61 trace.error("DIE!");
58
62
59 console.log("DONE");
63 writer.destroy();
64
65 trace.log("You shouldn't see it!");
66
67 t.comment("DONE");
60
68
61 t.end();
69 t.end();
62 }); No newline at end of file
70 });
General Comments 0
You need to be logged in to leave comments. Login now