Skip to content

Commit

Permalink
Add useFirst method to parse-latin
Browse files Browse the repository at this point in the history
This function acts in the same manner as `use`, with the exception
being it adds `plugins` before all other ware.
  • Loading branch information
wooorm committed Nov 19, 2014
1 parent 95c429c commit 949f37d
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 35 deletions.
121 changes: 86 additions & 35 deletions lib/parse-latin.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,51 +324,102 @@ function pluggable(Constructor, key, callback) {
}

/**
* @param {string} key
* @param {Function|Array.<Function>} plugin
* @this {ParseLatin|Object}
* Factory to inject `plugins`. Takes `callback` for
* the actual inserting.
*
* @param {fucntion(Object, string, Array.<Function>)} callback
* @return {function(string, Array.<Function>)}
*/

parseLatinPrototype.use = function (key, plugin) {
var self,
wareKey;

self = this;

function useFactory(callback) {
/**
* Throw if the method is not pluggable.
* Validate if `plugins` can be inserted. Invokes
* the bound `callback` to do the actual inserting.
*
* @param {string} key - Method to inject on
* @param {Array.<Function>|Function} plugins - One
* or more plugins.
*/

if (!(key in self)) {
throw new Error(
'Illegal Invocation: Unsupported `key` for ' +
'`use(key, plugin)`. Make sure `key` is a ' +
'supported function'
);
}
return function (key, plugins) {
var self,
wareKey;

/**
* Fail silently when no plugin is given.
*/
self = this;

if (!plugin) {
return;
}
/**
* Throw if the method is not pluggable.
*/

wareKey = key + 'Plugins';
if (!(key in self)) {
throw new Error(
'Illegal Invocation: Unsupported `key` for ' +
'`use(key, plugins)`. Make sure `key` is a ' +
'supported function'
);
}

if (typeof plugin === 'function') {
plugin = [plugin];
} else {
plugin = plugin.concat();
}
/**
* Fail silently when no plugins are given.
*/

if (self[wareKey]) {
self[wareKey] = self[wareKey].concat(plugin);
} else {
self[wareKey] = plugin;
}
};
if (!plugins) {
return;
}

wareKey = key + 'Plugins';

/**
* Make sure `plugins` is a list.
*/

if (typeof plugins === 'function') {
plugins = [plugins];
} else {
plugins = plugins.concat();
}

/**
* Make sure `wareKey` exists.
*/

if (!self[wareKey]) {
self[wareKey] = [];
}

/**
* Invoke callback with the ware key and plugins.
*/

callback(self, wareKey, plugins);
};
}

/**
* Inject `plugins` to modifiy the result of the method
* at `key` on the operated on context.
*
* @param {string} key
* @param {Function|Array.<Function>} plugins
* @this {ParseLatin|Object}
*/

parseLatinPrototype.use = useFactory(function (context, key, plugins) {
context[key] = context[key].concat(plugins);
});

/**
* Inject `plugins` to modifiy the result of the method
* at `key` on the operated on context, before any other.
*
* @param {string} key
* @param {Function|Array.<Function>} plugins
* @this {ParseLatin|Object}
*/

parseLatinPrototype.useFirst = useFactory(function (context, key, plugins) {
context[key] = plugins.concat(context[key]);
});

/**
* Create a `WordNode` with its children set to a single
Expand Down
87 changes: 87 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,93 @@ describe('ParseLatin#use(key, plugin)', function () {
});
});

describe('ParseLatin#useFirst(key, plugin)', function () {
it('should throw when a non-pluggable `key` is given', function () {
assert.throws(function () {
ParseLatin.prototype.useFirst('alfred');
}, /Make sure `key` is a supported function/);
});

it('should NOT throw when no plugin is given', function () {
assert.doesNotThrow(function () {
ParseLatin.prototype.useFirst('tokenizeWord');
});
});

it('should add a plugin on the prototype', function () {
var parser;

function thrower() {
throw new Error('prototypal thrower was invoked');
}

ParseLatin.prototype.useFirst('tokenizeWord', thrower);

parser = new ParseLatin();

assert(
ParseLatin.prototype.tokenizeWordPlugins[
ParseLatin.prototype.tokenizeWordPlugins.length - 1
] === thrower
);

assert.throws(function () {
parser.parse('Alfred.');
}, /thrower was invoked/);

/**
* Clean.
*/

ParseLatin.prototype.tokenizeWordPlugins.pop();
});

it('should add a plugin on an instance', function () {
var parser,
wasInvoked;

function first() {
wasInvoked = true;
}

function thrower() {
assert(wasInvoked === true);
throw new Error('instance thrower was invoked');
}

parser = new ParseLatin();

parser.useFirst('tokenizeWord', thrower);

assert(
parser.tokenizeWordPlugins[0] === thrower
);

parser.useFirst('tokenizeWord', first);

assert(
parser.tokenizeWordPlugins[0] === first
);

assert.throws(function () {
parser.parse('Alfred.');
}, /instance thrower was invoked/);

assert(wasInvoked === true);
});

after(function () {
/**
* Internally, `ParseLatin` checks if a
* `plugins` exists for optimalisation.
* We remove the prebiously empty list
* here.
*/

ParseLatin.prototype.tokenizeWordPlugins = null;
});
});

describe('ParseLatin#tokenizeText()', function () {
it('should return a text node', function () {
assert(latin.tokenizeText().type === 'TextNode');
Expand Down

0 comments on commit 949f37d

Please sign in to comment.