diff --git a/README.md b/README.md index c9dde29..0a2e01b 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,27 @@ Sentencer.configure({ // the list of adjectives to use. Again, Sentencer comes with one! adjectiveList: [], + // additional lists that generate actions for the template engine to use. + customLists: [ + { + // add action for animal + key: "animal", + values: ["dog", "cat", "elephant"], + // if named, add action for articlize + articlize: "an_animal", + // if named, add action for pluralize + pluralize: "animals" + }, + { + key: "band", + values: ["The Beatles", "The Who", "Styx"], + // no key or empty value, don't articlize + articlize: "", + // no key or empty value, don't pluralize + pluralize: "" + } + ], + // additional actions for the template engine to use. // you can also redefine the preset actions here if you need to. // See the "Add your own actions" section below. @@ -145,6 +166,29 @@ console.log( Sentencer.make("I can count to {{ number(8, 10) }}.") // "I can count to 8." ``` +### Add your own custom lists +When configuring `Sentencer` you can provide your own custom lists, which are converted to "actions". The `key` sets the name of the action and the `values` the list of values where one is selected when the action is called. You can also specify a name for the `articlize` and/or `pluralize` actions. These names are referenced within a sentence template. + +Here is an example of an animal list that includes options to prefix with an article or to make it plural. + +```javascript +var Sentencer = require('sentencer'); + +Sentencer.configure({ + customLists: [ + { + key: "animal", + values: ["dog", "cat", "elephant"], + articlize: "an_animal", + pluralize: "animals" + } + ], +}); + +console.log( Sentencer.make("I saw {{ an_animal }}, 1 {{ animal }}, and 2 {{ animals }}.") +// "I saw an elephant, 1 dog, and 2 cats." +``` + ### Where are the verbs? Verb pluralization, singularization, and tense modification are difficult computer science problems. `Sentencer` doesn't aim to solve those problems, however _present tense_ verb pluralization/singularization is an experimental feature of [`natural`](https://github.com/NaturalNode/natural) and could be integrated if necessary. diff --git a/index.js b/index.js index 79ed92e..2d156a0 100644 --- a/index.js +++ b/index.js @@ -19,25 +19,47 @@ function Sentencer() { return randy.choice(self._nouns); }, a_noun: function() { - return articles.articlize( self.actions.noun() ); + return articles.articlize(self.actions.noun()); }, nouns: function() { - return nounInflector.pluralize( randy.choice(self._nouns) ); + return nounInflector.pluralize(randy.choice(self._nouns)); }, adjective: function() { return randy.choice(self._adjectives); }, an_adjective: function() { - return articles.articlize( self.actions.adjective() ); + return articles.articlize(self.actions.adjective()); } }; + // function definitions + self._func_normal = function(values) { + return randy.choice(values); + } + self._func_articlize = function(name) { + return articles.articlize( self.actions[name]() ); + } + self._func_pluralize = function(values) { + return nounInflector.pluralize( randy.choice(values) ); + } + self.configure = function(options) { // merge actions - self.actions = _.merge(self.actions, options.actions || {}); + self.actions = _.merge(self.actions, options.actions || {}); // overwrite nouns and adjectives if we got some - self._nouns = options.nounList || self._nouns; - self._adjectives = options.adjectiveList || self._adjectives; + self._nouns = options.nounList || self._nouns; + self._adjectives = options.adjectiveList || self._adjectives; + self._customLists = options.customLists || []; + + self._customLists.forEach(item => { + self.actions[item.key] = self._func_normal.bind(null, item.values); + if (item.articlize) { + self.actions[item.articlize] = self._func_articlize.bind(null, item.key); + } + if (item.pluralize) { + self.actions[item.pluralize] = self._func_pluralize.bind(null, item.values); + } + }); }; self.use = function(options) { @@ -70,7 +92,7 @@ Sentencer.prototype.make = function(template) { var actionContents = action.match(/\((.+?)\)/); actionContents = actionContents && actionContents[1]; - if (actionExists && actionContents) { + if(actionExists && actionContents) { try { var args = _.map(actionContents.split(','), maybeCastToNumber); result = self.actions[actionName].apply(null, args); diff --git a/package-lock.json b/package-lock.json index a0eb812..2aaf953 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1106,7 +1106,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -1127,12 +1128,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1147,17 +1150,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -1274,7 +1280,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -1286,6 +1293,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1300,6 +1308,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1307,12 +1316,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -1331,6 +1342,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -1411,7 +1423,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -1423,6 +1436,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -1508,7 +1522,8 @@ "safe-buffer": { "version": "5.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -1544,6 +1559,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1563,6 +1579,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1606,12 +1623,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/tests/main.js b/tests/main.js index 0741485..c8bda71 100644 --- a/tests/main.js +++ b/tests/main.js @@ -65,32 +65,53 @@ describe('Sentencer:', function() { assert(Sentencer.make); }); + it('should merge a new custom list', function() { + Sentencer.configure({ + customLists: [ + { + key: "animal", + values: ["dog", "cat", "elephant"], + articlize: "an_animal", // if named, add action that calls articlize + pluralize: "animals" // if named, add action that calls pluralize + } + ] + }); + + assert(Sentencer.actions.animal); + assert(Sentencer.actions.an_animal); + assert(Sentencer.actions.animals); + + assert.notEqual(["dog", "cat", "elephant"].indexOf(Sentencer.actions.animal()), -1, "missing animal"); + assert.notEqual(["a dog", "a cat", "an elephant"].indexOf(Sentencer.actions.an_animal()), -1, "missing an_animal"); + assert.notEqual(["dogs", "cats", "elephants"].indexOf(Sentencer.actions.animals()), -1, "missing animals"); + }); + }); describe('Templating', function() { describe('# Default Actions', function() { - it('{{ noun }}', function(){ assert(Sentencer.make('{{ noun }}')); }); - it('{{ a_noun }}', function(){ assert(Sentencer.make('{{ a_noun }}')); }); - it('{{ nouns }}', function(){ assert(Sentencer.make('{{ nouns }}')); }); - it('{{ adjective }}', function(){ assert(Sentencer.make('{{ adjective }}')); }); - it('{{ an_adjective }}', function(){ assert(Sentencer.make('{{ an_adjective }}')); }); + it('{{ noun }}', function() { assert(Sentencer.make('{{ noun }}')); }); + it('{{ a_noun }}', function() { assert(Sentencer.make('{{ a_noun }}')); }); + it('{{ nouns }}', function() { assert(Sentencer.make('{{ nouns }}')); }); + it('{{ adjective }}', function() { assert(Sentencer.make('{{ adjective }}')); }); + it('{{ an_adjective }}', function() { assert(Sentencer.make('{{ an_adjective }}')); }); }); describe('# Custom Actions', function() { - it('{{ firstNewAction }}', function(){ + it('{{ firstNewAction }}', function() { assert.equal(Sentencer.make('{{ firstNewAction }}'), 'hello'); }); - it('{{ secondNewAction }}', function(){ + it('{{ secondNewAction }}', function() { assert.equal(Sentencer.make('{{ secondNewAction }}'), 'hello again'); }); - it('should return {{ action }} if it does not exist', function(){ - assert.equal( Sentencer.make('{{ nonexistant thing }}'), '{{ nonexistant thing }}'); + it('should return {{ action }} if it does not exist', function() { + assert.equal(Sentencer.make('{{ nonexistant thing }}'), '{{ nonexistant thing }}'); }); }); @@ -151,6 +172,21 @@ describe('Sentencer:', function() { }); + describe('# Custom Lists', function() { + + it('{{ animal }}', function() { + assert.notEqual(["dog", "cat", "elephant"].indexOf(Sentencer.make('{{ animal }}')), -1, "missing animal"); + }); + + it('{{ an_animal }}', function() { + assert.notEqual(["a dog", "a cat", "an elephant"].indexOf(Sentencer.make('{{ an_animal }}')), -1, "missing an_animal"); + }); + + it('{{ animals }}', function() { + assert.notEqual(["dogs", "cats", "elephants"].indexOf(Sentencer.make('{{ animals }}')), -1, "missing animals"); + }); + + }); }); describe('Test Print', function() {