From da1018276220043515dfd9de4a091fe922780b7e Mon Sep 17 00:00:00 2001 From: morungos Date: Wed, 8 Apr 2015 20:50:39 -0400 Subject: [PATCH 01/11] Change the constructor to allow options to be passed instead of a simple string directory --- README.md | 22 ++++++++++++++-------- src/wordnet.coffee | 30 ++++++++++++++++++------------ 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 795916b..aaf9d22 100644 --- a/README.md +++ b/README.md @@ -40,16 +40,22 @@ npm install wndb-with-exceptions --save API --- -### new WordNet([directory]) +### new WordNet([options | string]) -The constructor returns a new object to access a WordNet database at the specified -directory. If no directory is passed, the module uses `require` to locate -`wndb-with-exceptions`, so if you don't want to deploy your own WordNet, all you -need to do is add `wndb-with-exceptions` as an application dependency and not -pass a directory to the constructor. +The constructor returns a new object to access a WordNet database. The passed +options configure the interface. The following options are available: -The original WordNet data files can always be manually downloaded and installed -anywhere from http://wordnet.princeton.edu/wordnet/download. + * __dataDir__ -- specifies the location of the Wordnet directory. + + If this option isn't passed, the module uses `require` to locate + `wndb-with-exceptions`, so if you don't want to deploy your own WordNet, all you + need to do is add `wndb-with-exceptions` as an application dependency and not + pass a directory to the constructor. + The original WordNet data files can always be manually downloaded and installed + anywhere from http://wordnet.princeton.edu/wordnet/download. + + As a shortcut, if you pass a string directly to the constructor, it's interpreted + as a Wordnet directory, and all other options default in sensible ways. ### lookup(word, callback) diff --git a/src/wordnet.coffee b/src/wordnet.coffee index 76efc73..2f93bf9 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -38,27 +38,33 @@ require('es6-shim') class WordNet - constructor: (dataDir) -> + constructor: (options) -> - if !dataDir + ## For compatibility, if the options are a string, it's just the Wordnet path + if typeof options == 'string' + options = {dataDir: options} + else + options ?= {} + + if ! options.dataDir? try WNdb = require('wndb-with-exceptions') catch e console.error("Please 'npm install wndb-with-exceptions' before using WordNet module or specify a dict directory.") throw e - dataDir = WNdb.path + options.dataDir = WNdb.path - @path = dataDir + @path = options.dataDir - @nounIndex = new IndexFile(dataDir, 'noun') - @verbIndex = new IndexFile(dataDir, 'verb') - @adjIndex = new IndexFile(dataDir, 'adj') - @advIndex = new IndexFile(dataDir, 'adv') + @nounIndex = new IndexFile(@path, 'noun') + @verbIndex = new IndexFile(@path, 'verb') + @adjIndex = new IndexFile(@path, 'adj') + @advIndex = new IndexFile(@path, 'adv') - @nounData = new DataFile(dataDir, 'noun') - @verbData = new DataFile(dataDir, 'verb') - @adjData = new DataFile(dataDir, 'adj') - @advData = new DataFile(dataDir, 'adv') + @nounData = new DataFile(@path, 'noun') + @verbData = new DataFile(@path, 'verb') + @adjData = new DataFile(@path, 'adj') + @advData = new DataFile(@path, 'adv') @allFiles = [ {index: @nounIndex, data: @nounData, pos: 'n'} From 7e2c72e29886ef99a29fdb6bca654ef5f0775615 Mon Sep 17 00:00:00 2001 From: morungos Date: Wed, 8 Apr 2015 21:05:59 -0400 Subject: [PATCH 02/11] Initialize an LRU cache object from the options --- README.md | 9 +++++++++ package.json | 3 ++- src/wordnet.coffee | 30 ++++++++++++++++++++++++------ test/wordnet_cache_test.coffee | 22 ++++++++++++++++++++++ 4 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 test/wordnet_cache_test.coffee diff --git a/README.md b/README.md index aaf9d22..3cf2182 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,15 @@ options configure the interface. The following options are available: As a shortcut, if you pass a string directly to the constructor, it's interpreted as a Wordnet directory, and all other options default in sensible ways. + * __cache__ -- adds an LRU cache to the Wordnet access. + + If the option is false, no cache is set; and if it is true, then a cache (using + `lru-cache` with a default size of 2000 items) is set. In addition, the cache can be + an object. If that object has a `get` method then it's used as a cache directly, and + if it doesn't, it's assumed to be a configuration object which will be used to + configure a new `lru-cache`. + + ### lookup(word, callback) Here's an example of looking up definitions for the word, "node". diff --git a/package.json b/package.json index ce82777..f40b59b 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "dependencies": { "async": "^0.9.0", "bluebird": "^2.6.0", - "es6-shim": "^0.22.1" + "es6-shim": "^0.22.1", + "lru-cache": "^2.5.0" } } diff --git a/src/wordnet.coffee b/src/wordnet.coffee index 2f93bf9..c5bd694 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -26,13 +26,15 @@ ## (5) - move to use wndb-with-exceptions instead of WNdb, to provide morphological exceptions ## (6) - significant improvements in testing -IndexFile = require('./index_file') -DataFile = require('./data_file') +IndexFile = require './index_file' +DataFile = require './data_file' -async = require('async') -Promise = require('bluebird') -path = require('path') -fs = require('fs') +async = require 'async' +Promise = require 'bluebird' +path = require 'path' +fs = require 'fs' + +LRU = require 'lru-cache' require('es6-shim') @@ -46,6 +48,7 @@ class WordNet else options ?= {} + if ! options.dataDir? try WNdb = require('wndb-with-exceptions') @@ -54,6 +57,21 @@ class WordNet throw e options.dataDir = WNdb.path + + if ! options.cache + @cache = null + else + if options.cache == true + options.cache = { + max: 2000 + } + + if typeof options.cache == 'object' and typeof options.cache.get == 'function' + @cache = options.cache + else + @cache = LRU options.cache + + @path = options.dataDir @nounIndex = new IndexFile(@path, 'noun') diff --git a/test/wordnet_cache_test.coffee b/test/wordnet_cache_test.coffee new file mode 100644 index 0000000..c69b47e --- /dev/null +++ b/test/wordnet_cache_test.coffee @@ -0,0 +1,22 @@ +chai = require('chai') +chai.use(require('chai-as-promised')) +should = chai.should() + +async = require('async') + +Wordnet = require('../lib/wordnet') + +describe 'wordnet with cache enabled', () -> + + wordnet = undefined + + beforeEach (done) -> + wordnet = new Wordnet({cache: true}) + done() + + describe 'get', () -> + it 'should succeed', (done) -> + wordnet.get 3827107, 'n', (results) -> + should.exist(results) + results.should.have.property('gloss', '(computer science) any computer that is hooked up to a computer network ') + done() From b8f223cf4a1fb5ee9ea44aecda7807862671370b Mon Sep 17 00:00:00 2001 From: morungos Date: Wed, 8 Apr 2015 21:40:01 -0400 Subject: [PATCH 03/11] Slightly clunky but working cache use --- src/wordnet.coffee | 13 +++++++++++-- test/wordnet_cache_test.coffee | 7 +++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/wordnet.coffee b/src/wordnet.coffee index c5bd694..42b9442 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -92,8 +92,17 @@ class WordNet ] get: (synsetOffset, pos, callback) -> - dataFile = @getDataFile(pos) - dataFile.get synsetOffset, callback + wordnet = @ + query = undefined + if @cache + query = "get:#{synsetOffset}:#{pos}" + hit = wordnet.cache.get query + return callback(hit) if hit? + + dataFile = wordnet.getDataFile(pos) + dataFile.get synsetOffset, (result) -> + wordnet.cache.set query, result if query + callback(result) getAsync: (synsetOffset, pos) -> wordnet = @ diff --git a/test/wordnet_cache_test.coffee b/test/wordnet_cache_test.coffee index c69b47e..9f90847 100644 --- a/test/wordnet_cache_test.coffee +++ b/test/wordnet_cache_test.coffee @@ -20,3 +20,10 @@ describe 'wordnet with cache enabled', () -> should.exist(results) results.should.have.property('gloss', '(computer science) any computer that is hooked up to a computer network ') done() + + it 'should return the exact same value for a second query', (done) -> + wordnet.get 3827107, 'n', (results) -> + should.exist(results) + wordnet.get 3827107, 'n', (results2) -> + (results == results2).should.be.true + done() From 8aa02d204737f949048631d9ba11d1baa09074ab Mon Sep 17 00:00:00 2001 From: morungos Date: Wed, 8 Apr 2015 21:41:32 -0400 Subject: [PATCH 04/11] A small but nice simplification --- src/wordnet.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wordnet.coffee b/src/wordnet.coffee index 42b9442..2168f20 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -96,8 +96,7 @@ class WordNet query = undefined if @cache query = "get:#{synsetOffset}:#{pos}" - hit = wordnet.cache.get query - return callback(hit) if hit? + return callback(hit) if hit = wordnet.cache.get query dataFile = wordnet.getDataFile(pos) dataFile.get synsetOffset, (result) -> From 73a82242a495f6a94437964447cb89950e86f003 Mon Sep 17 00:00:00 2001 From: morungos Date: Thu, 9 Apr 2015 19:01:30 -0400 Subject: [PATCH 05/11] Add caching to the lookup method --- src/wordnet.coffee | 10 +++++++++- test/wordnet_cache_test.coffee | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/wordnet.coffee b/src/wordnet.coffee index 2168f20..74a899b 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -111,11 +111,19 @@ class WordNet lookup: (input, callback) -> wordnet = @ + query = undefined [word, pos] = input.split('#') lword = word.toLowerCase().replace(/\s+/g, '_') + if @cache + queryPos = pos or 'undefined' + query = "lookup:#{lword}:#{queryPos}" + return callback(hit) if hit = wordnet.cache.get query + selectedFiles = if ! pos then wordnet.allFiles else wordnet.allFiles.filter (file) -> file.pos == pos - wordnet.lookupFromFiles selectedFiles, [], lword, callback + wordnet.lookupFromFiles selectedFiles, [], lword, (results) -> + wordnet.cache.set query, results if query + callback(results) lookupAsync: (input, callback) -> wordnet = @ diff --git a/test/wordnet_cache_test.coffee b/test/wordnet_cache_test.coffee index 9f90847..6fe5dd4 100644 --- a/test/wordnet_cache_test.coffee +++ b/test/wordnet_cache_test.coffee @@ -27,3 +27,18 @@ describe 'wordnet with cache enabled', () -> wordnet.get 3827107, 'n', (results2) -> (results == results2).should.be.true done() + + describe 'lookup', () -> + it 'should succeed for node', (done) -> + wordnet.lookup 'node', (results) -> + should.exist(results) + results.should.be.an.instanceOf(Array) + results[0].should.have.property('synsetOffset', 3827107) + done() + + it 'should return the exact same value for a second query', (done) -> + wordnet.lookup 'node', (results) -> + should.exist(results) + wordnet.lookup 'node', (results2) -> + (results == results2).should.be.true + done() From 299124e79303e4d18c83305b819494bb9be3bebb Mon Sep 17 00:00:00 2001 From: morungos Date: Thu, 9 Apr 2015 19:02:35 -0400 Subject: [PATCH 06/11] Simplified the cache key calculation --- src/wordnet.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wordnet.coffee b/src/wordnet.coffee index 74a899b..75a005c 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -116,8 +116,7 @@ class WordNet lword = word.toLowerCase().replace(/\s+/g, '_') if @cache - queryPos = pos or 'undefined' - query = "lookup:#{lword}:#{queryPos}" + query = "lookup:#{input}" return callback(hit) if hit = wordnet.cache.get query selectedFiles = if ! pos then wordnet.allFiles else wordnet.allFiles.filter (file) -> file.pos == pos From 9fcc1c6e08b184b7d34cb2bd7d9415065ee4bc71 Mon Sep 17 00:00:00 2001 From: morungos Date: Thu, 9 Apr 2015 19:05:28 -0400 Subject: [PATCH 07/11] Added cache to findSense --- src/wordnet.coffee | 8 +++++++- test/wordnet_cache_test.coffee | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/wordnet.coffee b/src/wordnet.coffee index 75a005c..3876267 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -134,6 +134,10 @@ class WordNet wordnet = @ [word, pos, senseNumber] = input.split('#') + if @cache + query = "findSense:#{input}" + return callback(hit) if hit = wordnet.cache.get query + sense = parseInt(senseNumber) if Number.isNaN(sense) throw new Error("Sense number should be an integer") @@ -143,7 +147,9 @@ class WordNet lword = word.toLowerCase().replace(/\s+/g, '_') selectedFiles = wordnet.allFiles.filter (file) -> file.pos == pos wordnet.lookupFromFiles selectedFiles, [], lword, (response) -> - callback(response[sense - 1]) + result = response[sense - 1] + wordnet.cache.set query, result if query + callback(result) findSenseAsync: (input) -> wordnet = @ diff --git a/test/wordnet_cache_test.coffee b/test/wordnet_cache_test.coffee index 6fe5dd4..e73b58a 100644 --- a/test/wordnet_cache_test.coffee +++ b/test/wordnet_cache_test.coffee @@ -42,3 +42,19 @@ describe 'wordnet with cache enabled', () -> wordnet.lookup 'node', (results2) -> (results == results2).should.be.true done() + + describe 'findSense', () -> + + it 'should succeed for lie#v#1', (done) -> + wordnet.findSense 'lie#v#1', (results) -> + should.exist(results) + results.should.have.property('lemma', 'lie_down') + results.should.have.property('pos', 'v') + done() + + it 'should return the exact same value for a second query', (done) -> + wordnet.findSense 'lie#v#1', (results) -> + should.exist(results) + wordnet.findSense 'lie#v#1', (results2) -> + (results == results2).should.be.true + done() From b2269a9c30c7c6fdbded83120e342094085a2c4a Mon Sep 17 00:00:00 2001 From: morungos Date: Thu, 9 Apr 2015 19:07:48 -0400 Subject: [PATCH 08/11] More simplifications -- note the scope of the query variable allows this --- src/wordnet.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wordnet.coffee b/src/wordnet.coffee index 3876267..6fb487f 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -93,7 +93,7 @@ class WordNet get: (synsetOffset, pos, callback) -> wordnet = @ - query = undefined + if @cache query = "get:#{synsetOffset}:#{pos}" return callback(hit) if hit = wordnet.cache.get query @@ -111,7 +111,6 @@ class WordNet lookup: (input, callback) -> wordnet = @ - query = undefined [word, pos] = input.split('#') lword = word.toLowerCase().replace(/\s+/g, '_') From 9146a7332a4107529c512dd5dd8e5994af0ff8c6 Mon Sep 17 00:00:00 2001 From: morungos Date: Thu, 9 Apr 2015 19:46:45 -0400 Subject: [PATCH 09/11] And completed now, with adding validForms caching --- lib/wordnet.js | 124 +++++++++++++++++++++++++++------ src/wordnet.coffee | 13 +++- test/wordnet_cache_test.coffee | 34 +++++++++ 3 files changed, 148 insertions(+), 23 deletions(-) diff --git a/lib/wordnet.js b/lib/wordnet.js index 4cca0bf..2f27ae8 100644 --- a/lib/wordnet.js +++ b/lib/wordnet.js @@ -1,4 +1,4 @@ -var DataFile, IndexFile, Promise, WordNet, async, fs, path, +var DataFile, IndexFile, LRU, Promise, WordNet, async, fs, path, __slice = [].slice; IndexFile = require('./index_file'); @@ -13,14 +13,25 @@ path = require('path'); fs = require('fs'); +LRU = require('lru-cache'); + require('es6-shim'); WordNet = (function() { var exceptions, forms, tokenDetach, unique, _forms, _loadExceptions, _validForms, _validFormsWithExceptions; - function WordNet(dataDir) { + function WordNet(options) { var WNdb, e; - if (!dataDir) { + if (typeof options === 'string') { + options = { + dataDir: options + }; + } else { + if (options == null) { + options = {}; + } + } + if (options.dataDir == null) { try { WNdb = require('wndb-with-exceptions'); } catch (_error) { @@ -28,17 +39,31 @@ WordNet = (function() { console.error("Please 'npm install wndb-with-exceptions' before using WordNet module or specify a dict directory."); throw e; } - dataDir = WNdb.path; + options.dataDir = WNdb.path; } - this.path = dataDir; - this.nounIndex = new IndexFile(dataDir, 'noun'); - this.verbIndex = new IndexFile(dataDir, 'verb'); - this.adjIndex = new IndexFile(dataDir, 'adj'); - this.advIndex = new IndexFile(dataDir, 'adv'); - this.nounData = new DataFile(dataDir, 'noun'); - this.verbData = new DataFile(dataDir, 'verb'); - this.adjData = new DataFile(dataDir, 'adj'); - this.advData = new DataFile(dataDir, 'adv'); + if (!options.cache) { + this.cache = null; + } else { + if (options.cache === true) { + options.cache = { + max: 2000 + }; + } + if (typeof options.cache === 'object' && typeof options.cache.get === 'function') { + this.cache = options.cache; + } else { + this.cache = LRU(options.cache); + } + } + this.path = options.dataDir; + this.nounIndex = new IndexFile(this.path, 'noun'); + this.verbIndex = new IndexFile(this.path, 'verb'); + this.adjIndex = new IndexFile(this.path, 'adj'); + this.advIndex = new IndexFile(this.path, 'adv'); + this.nounData = new DataFile(this.path, 'noun'); + this.verbData = new DataFile(this.path, 'verb'); + this.adjData = new DataFile(this.path, 'adj'); + this.advData = new DataFile(this.path, 'adv'); this.allFiles = [ { index: this.nounIndex, @@ -61,9 +86,21 @@ WordNet = (function() { } WordNet.prototype.get = function(synsetOffset, pos, callback) { - var dataFile; - dataFile = this.getDataFile(pos); - return dataFile.get(synsetOffset, callback); + var dataFile, hit, query, wordnet; + wordnet = this; + if (this.cache) { + query = "get:" + synsetOffset + ":" + pos; + if (hit = wordnet.cache.get(query)) { + return callback(hit); + } + } + dataFile = wordnet.getDataFile(pos); + return dataFile.get(synsetOffset, function(result) { + if (query) { + wordnet.cache.set(query, result); + } + return callback(result); + }); }; WordNet.prototype.getAsync = function(synsetOffset, pos) { @@ -77,14 +114,25 @@ WordNet = (function() { }; WordNet.prototype.lookup = function(input, callback) { - var lword, pos, selectedFiles, word, wordnet, _ref; + var hit, lword, pos, query, selectedFiles, word, wordnet, _ref; wordnet = this; _ref = input.split('#'), word = _ref[0], pos = _ref[1]; lword = word.toLowerCase().replace(/\s+/g, '_'); + if (this.cache) { + query = "lookup:" + input; + if (hit = wordnet.cache.get(query)) { + return callback(hit); + } + } selectedFiles = !pos ? wordnet.allFiles : wordnet.allFiles.filter(function(file) { return file.pos === pos; }); - return wordnet.lookupFromFiles(selectedFiles, [], lword, callback); + return wordnet.lookupFromFiles(selectedFiles, [], lword, function(results) { + if (query) { + wordnet.cache.set(query, results); + } + return callback(results); + }); }; WordNet.prototype.lookupAsync = function(input, callback) { @@ -98,9 +146,15 @@ WordNet = (function() { }; WordNet.prototype.findSense = function(input, callback) { - var lword, pos, selectedFiles, sense, senseNumber, word, wordnet, _ref; + var hit, lword, pos, query, selectedFiles, sense, senseNumber, word, wordnet, _ref; wordnet = this; _ref = input.split('#'), word = _ref[0], pos = _ref[1], senseNumber = _ref[2]; + if (this.cache) { + query = "findSense:" + input; + if (hit = wordnet.cache.get(query)) { + return callback(hit); + } + } sense = parseInt(senseNumber); if (Number.isNaN(sense)) { throw new Error("Sense number should be an integer"); @@ -112,7 +166,12 @@ WordNet = (function() { return file.pos === pos; }); return wordnet.lookupFromFiles(selectedFiles, [], lword, function(response) { - return callback(response[sense - 1]); + var result; + result = response[sense - 1]; + if (query) { + wordnet.cache.set(query, result); + } + return callback(result); }); }; @@ -127,9 +186,15 @@ WordNet = (function() { }; WordNet.prototype.querySense = function(input, callback) { - var pos, word, wordnet, _ref; + var hit, pos, query, word, wordnet, _ref; wordnet = this; _ref = input.split('#'), word = _ref[0], pos = _ref[1]; + if (this.cache) { + query = "querySense:" + input; + if (hit = wordnet.cache.get(query)) { + return callback(hit); + } + } return wordnet.lookup(input, function(results) { var i, sense, senseCounts, senses; senseCounts = {}; @@ -149,6 +214,9 @@ WordNet = (function() { } return _results; })(); + if (query) { + wordnet.cache.set(query, senses); + } return callback(senses); }); }; @@ -502,7 +570,19 @@ WordNet = (function() { }; WordNet.prototype.validForms = function(string, callback) { - return _validFormsWithExceptions(this, string, callback); + var hit, query; + if (this.cache) { + query = "validForms:" + string; + if (hit = wordnet.cache.get(query)) { + return callback(hit); + } + } + return _validFormsWithExceptions(this, string, function(result) { + if (query) { + wordnet.cache.set(query, result); + } + return callback(result); + }); }; WordNet.prototype.validFormsAsync = function(string) { diff --git a/src/wordnet.coffee b/src/wordnet.coffee index 6fb487f..ad9a9d9 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -160,6 +160,10 @@ class WordNet wordnet = @ [word, pos] = input.split('#') + if @cache + query = "querySense:#{input}" + return callback(hit) if hit = wordnet.cache.get query + wordnet.lookup input, (results) -> senseCounts = {} senses = for sense, i in results @@ -168,6 +172,7 @@ class WordNet senseCounts[pos] ?= 1 word + "#" + pos + "#" + senseCounts[pos]++ + wordnet.cache.set query, senses if query callback(senses) querySenseAsync: (input) -> @@ -433,7 +438,13 @@ class WordNet validForms: (string, callback) -> - _validFormsWithExceptions @, string, callback + if @cache + query = "validForms:#{string}" + return callback(hit) if hit = wordnet.cache.get query + + _validFormsWithExceptions @, string, (result) -> + wordnet.cache.set query, result if query + callback(result) validFormsAsync: (string) -> new Promise (resolve, reject) => diff --git a/test/wordnet_cache_test.coffee b/test/wordnet_cache_test.coffee index e73b58a..7650333 100644 --- a/test/wordnet_cache_test.coffee +++ b/test/wordnet_cache_test.coffee @@ -28,6 +28,7 @@ describe 'wordnet with cache enabled', () -> (results == results2).should.be.true done() + describe 'lookup', () -> it 'should succeed for node', (done) -> wordnet.lookup 'node', (results) -> @@ -43,6 +44,7 @@ describe 'wordnet with cache enabled', () -> (results == results2).should.be.true done() + describe 'findSense', () -> it 'should succeed for lie#v#1', (done) -> @@ -58,3 +60,35 @@ describe 'wordnet with cache enabled', () -> wordnet.findSense 'lie#v#1', (results2) -> (results == results2).should.be.true done() + + + describe 'querySense', () -> + it 'should succeed for node', (done) -> + wordnet.querySense 'node', (results) -> + should.exist(results) + results.should.be.an.instanceOf(Array) + results.should.have.length(8) + done() + + it 'should return the exact same value for a second query', (done) -> + wordnet.querySense 'node', (results) -> + should.exist(results) + wordnet.querySense 'node', (results2) -> + (results == results2).should.be.true + done() + + + describe 'validForms', () -> + + it 'should succeed for axes#n', (done) -> + wordnet.validFormsAsync 'axes#n' + .should.eventually.exist + .should.eventually.eql(['ax#n', 'axis#n']) + .notify(done) + + it 'should return the exact same value for a second query', (done) -> + wordnet.validFormsAsync 'axes#n' + should.exist(results) + wordnet.validFormsAsync 'axes#n' + (results == results2).should.be.true + done() From af7536196033904ed7be0fcc81e6b349441005a2 Mon Sep 17 00:00:00 2001 From: morungos Date: Thu, 9 Apr 2015 19:53:20 -0400 Subject: [PATCH 10/11] Updated change log and version --- CHANGES.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index b3741ee..48e0e5e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,12 @@ Release history =============== +Version 0.1.8 +------------- + + * Added an optional LRU cache + + Version 0.1.7 ------------- diff --git a/package.json b/package.json index f40b59b..a58aa3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-wordnet", - "version": "0.1.7", + "version": "0.1.8", "description": "Node.js interface for Wordnet", "main": "lib/wordnet.js", "scripts": { From 0cda7455ac60f09c3505205e318ca1e1493649fe Mon Sep 17 00:00:00 2001 From: morungos Date: Thu, 9 Apr 2015 19:56:12 -0400 Subject: [PATCH 11/11] Whoops. Late issues in the validForms caching and tests --- lib/wordnet.js | 3 ++- src/wordnet.coffee | 2 ++ test/wordnet_cache_test.coffee | 12 ++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/wordnet.js b/lib/wordnet.js index 2f27ae8..fb03cf5 100644 --- a/lib/wordnet.js +++ b/lib/wordnet.js @@ -570,7 +570,8 @@ WordNet = (function() { }; WordNet.prototype.validForms = function(string, callback) { - var hit, query; + var hit, query, wordnet; + wordnet = this; if (this.cache) { query = "validForms:" + string; if (hit = wordnet.cache.get(query)) { diff --git a/src/wordnet.coffee b/src/wordnet.coffee index ad9a9d9..9f6013e 100644 --- a/src/wordnet.coffee +++ b/src/wordnet.coffee @@ -438,6 +438,8 @@ class WordNet validForms: (string, callback) -> + wordnet = @ + if @cache query = "validForms:#{string}" return callback(hit) if hit = wordnet.cache.get query diff --git a/test/wordnet_cache_test.coffee b/test/wordnet_cache_test.coffee index 7650333..5235259 100644 --- a/test/wordnet_cache_test.coffee +++ b/test/wordnet_cache_test.coffee @@ -81,14 +81,14 @@ describe 'wordnet with cache enabled', () -> describe 'validForms', () -> it 'should succeed for axes#n', (done) -> - wordnet.validFormsAsync 'axes#n' - .should.eventually.exist - .should.eventually.eql(['ax#n', 'axis#n']) - .notify(done) + wordnet.validForms 'axes#n', (results) -> + should.exist(results) + results.should.eql(['ax#n', 'axis#n']) + done() it 'should return the exact same value for a second query', (done) -> - wordnet.validFormsAsync 'axes#n' + wordnet.validForms 'axes#n', (results) -> should.exist(results) - wordnet.validFormsAsync 'axes#n' + wordnet.validForms 'axes#n', (results2) -> (results == results2).should.be.true done()