diff --git a/letterbox.js b/letterbox.js index 05afc93..ab70b4a 100644 --- a/letterbox.js +++ b/letterbox.js @@ -18,6 +18,9 @@ 'use strict' +var Writable = require('stream').Writable; +var Tracker = require('./tracker.js'); + /** * Construct a new letterbox accepting EDIFACT envelopes. A letterbox is a * Writable stream accepting segment objects. Enveloping is optional, so a @@ -26,22 +29,29 @@ * * @constructs Letterbox */ -var Letterbox = function () { - var letterbox = this; +var Letterbox = function (path) { + var that = this; + + Writable.call(this, { + write: this.accept, + objectMode: true + }); + + this.path = path; this.depth = {}; this.depth.current = 0; this.depth.minimum = 0; this.depth.maximum = 2; - this.next = function () { - letterbox.depth.current -= 1; + this.next = function (segment) { + that.depth.current -= 1; }; } -module.exports = Letterbox; +Letterbox.prototype = Object.create(Writable.prototype); -function open_envelope(name, level) { +function openEnvelope(name, level) { var message = ''; var depth = this.depth.current + 1; @@ -57,7 +67,7 @@ function open_envelope(name, level) { } } -function close_envelope(name, level) { +function closeEnvelope(name, level) { var message = ''; var depth = this.depth.current - 1; @@ -69,24 +79,19 @@ function close_envelope(name, level) { } } -/** - * Accept a segment. - * - * @param {String} segment A segment object. - */ -Letterbox.prototype.write = function (segment) { +Letterbox.prototype.accept = function (segment) { // Most of the time we are tracking segments in a message. To optimize for // this case we start by detecting if we are currently in the middle of a // message. We can do this with only one comparison. if (this.depth.current > this.depth.maximum) { - this.track(segment); + this.tracker.accept(segment.name); } else { switch (segment.name) { case 'UNB': - open_envelope.call(this, 'interchange', 0); + openEnvelope.call(this, 'interchange', 0); break; case 'UNG': - open_envelope.call(this, 'group', 1); + openEnvelope.call(this, 'group', 1); break; case 'UNH': if (this.depth.current < this.depth.minimum) { @@ -94,21 +99,26 @@ Letterbox.prototype.write = function (segment) { } else { this.depth.maximum = this.depth.current; this.depth.current += 1; - this.track(segment); + this.setup(segment); } break; case 'UNE': - close_envelope.call(this, 'group', 1); + closeEnvelope.call(this, 'group', 1); break; case 'UNZ': - close_envelope.call(this, 'interchange', 0); + closeEnvelope.call(this, 'interchange', 0); break; default: throw Error('Did not expect a ' + segment + ' segment'); } } -}; +} -Letterbox.prototype.track = function () {}; +Letterbox.prototype.setup = function (segment) { + this.cork(); + this.tracker = new Tracker(require(this.path + '/' + segment.components[1])); + this.tracker.accept(segment.name); + this.uncork(); +}; module.exports = Letterbox; diff --git a/spec/LetterboxSpec.js b/spec/LetterboxSpec.js index 7096f99..198d0b5 100644 --- a/spec/LetterboxSpec.js +++ b/spec/LetterboxSpec.js @@ -6,31 +6,33 @@ describe('Letterbox', function () { let letterbox; beforeEach(function () { letterbox = new Letterbox(); - spyOn(letterbox, 'track'); + letterbox.tracker = { accept: function () {} }; + spyOn(letterbox, 'setup'); + spyOn(letterbox.tracker, 'accept'); }); it('should accept a message without an envelope', function () { - expect(function () { letterbox.write({ name: 'UNH' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNH' }); }).not.toThrow(); expect(letterbox.depth.maximum).toEqual(0); expect(letterbox.depth.current).toEqual(1); expect(function () { letterbox.next(); }).not.toThrow(); expect(letterbox.depth.current).toEqual(0); }); it('cannot nest interchanges', function () { - expect(function () { letterbox.write({ name: 'UNB' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNB' }); }).not.toThrow(); expect(letterbox.depth.minimum).toEqual(1); expect(letterbox.depth.current).toEqual(1); - expect(function () { letterbox.write({ name: 'UNB' }); }).toThrow(); + expect(function () { letterbox.accept({ name: 'UNB' }); }).toThrow(); }); it('cannot open an interchange after a single message', function () { - expect(function () { letterbox.write({ name: 'UNH' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNH' }); }).not.toThrow(); expect(letterbox.depth.maximum).toEqual(0); expect(letterbox.depth.current).toEqual(1); expect(function () { letterbox.next(); }).not.toThrow(); expect(letterbox.depth.current).toEqual(0); - expect(function () { letterbox.write({ name: 'UNB' }); }).toThrow(); + expect(function () { letterbox.accept({ name: 'UNB' }); }).toThrow(); }); it('cannot open a group without an interchange', function () { - expect(function () { letterbox.write({ name: 'UNG' }); }).toThrow(); + expect(function () { letterbox.accept({ name: 'UNG' }); }).toThrow(); }); for (var name of ['UNB', 'UNZ', 'UNG', 'UNE']) { it('should not validate a ' + name + ' segment while tracking a message', function () { @@ -38,48 +40,48 @@ describe('Letterbox', function () { // table, this test is the equivalence of allowing such a messsage // definition. Prohibiting enveloping segments in messages should be // done by providing a correct segment table, not by algorithm design. - expect(function () { letterbox.write({ name: 'UNH' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNH' }); }).not.toThrow(); expect(letterbox.depth.maximum).toEqual(0); expect(letterbox.depth.current).toEqual(1); - expect(function () { letterbox.write({ name: name }); }).not.toThrow(); - expect(letterbox.track).toHaveBeenCalled(); + expect(function () { letterbox.accept({ name: name }); }).not.toThrow(); + expect(letterbox.tracker.accept).toHaveBeenCalled(); }); } it('should accept a message in an interchange', function () { - expect(function () { letterbox.write({ name: 'UNB' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNB' }); }).not.toThrow(); expect(letterbox.depth.minimum).toEqual(1); expect(letterbox.depth.current).toEqual(1); - expect(function () { letterbox.write({ name: 'UNH' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNH' }); }).not.toThrow(); expect(letterbox.depth.maximum).toEqual(1); expect(letterbox.depth.current).toEqual(2); expect(function () { letterbox.next(); }).not.toThrow(); expect(letterbox.depth.current).toEqual(1); - expect(function () { letterbox.write({ name: 'UNZ' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNZ' }); }).not.toThrow(); expect(letterbox.depth.current).toEqual(0); }); it('should not accept a group after a message', function () { - expect(function () { letterbox.write({ name: 'UNB' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNB' }); }).not.toThrow(); expect(letterbox.depth.minimum).toEqual(1); expect(letterbox.depth.current).toEqual(1); - expect(function () { letterbox.write({ name: 'UNH' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNH' }); }).not.toThrow(); expect(letterbox.depth.maximum).toEqual(1); expect(letterbox.depth.current).toEqual(2); expect(function () { letterbox.next(); }).not.toThrow(); expect(letterbox.depth.current).toEqual(1); - expect(function () { letterbox.write({ name: 'UNG' }); }).toThrow(); + expect(function () { letterbox.accept({ name: 'UNG' }); }).toThrow(); }); it('should not accept a group without an interchange', function () { - expect(function () { letterbox.write({ name: 'UNG' }); }).toThrow(); + expect(function () { letterbox.accept({ name: 'UNG' }); }).toThrow(); }); it('should not accept a message after a group', function () { - expect(function () { letterbox.write({ name: 'UNB' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNB' }); }).not.toThrow(); expect(letterbox.depth.minimum).toEqual(1); expect(letterbox.depth.current).toEqual(1); - expect(function () { letterbox.write({ name: 'UNG' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNG' }); }).not.toThrow(); expect(letterbox.depth.minimum).toEqual(2); expect(letterbox.depth.current).toEqual(2); - expect(function () { letterbox.write({ name: 'UNE' }); }).not.toThrow(); + expect(function () { letterbox.accept({ name: 'UNE' }); }).not.toThrow(); expect(letterbox.depth.current).toEqual(1); - expect(function () { letterbox.write({ name: 'UNH' }); }).toThrow(); + expect(function () { letterbox.accept({ name: 'UNH' }); }).toThrow(); }); });