diff --git a/lib/relevancy.js b/lib/relevancy.js index 38df6ce..4f4e480 100644 --- a/lib/relevancy.js +++ b/lib/relevancy.js @@ -1,5 +1,5 @@ /** - * relevancy.js v0.1.0dev + * relevancy.js v0.2 **/ (function(){ @@ -8,8 +8,8 @@ toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty; - S.sort = function relevancySort(array, subject) { - return S.defaultSorter.sort(array, subject); + S.sort = function relevancySort(array, subject, subWeightOperation) { + return S.defaultSorter.sort(array, subject, subWeightOperation); }; S.weight = function relevancyWeight(a, b) { @@ -27,12 +27,12 @@ this._array = array; this._bounds = config.bounds || ['\\s']; - this._subArrayWeightOperation = config.subArrayWeightOperation && + this._subWeightOperation = config.subWeightOperation && ( - typeof config.subArrayWeightOperation == 'function' ? - config.subArrayWeightOperation : - S.Sorter.subArrayWeightOperations[config.subArrayWeightOperation] - ) || S.Sorter.subArrayWeightOperations.max; + typeof config.subWeightOperation == 'function' ? + config.subWeightOperation : + S.Sorter.subWeightOperations[config.subWeightOperation] + ) || S.Sorter.subWeightOperations.max; this._weights = { matchInSubjectLength: 1, @@ -55,19 +55,23 @@ } - var subArrayWeightOperations = S.Sorter.subArrayWeightOperations = { - max: function(subArray, subjectRegex, subject, isRegexSearch) { + var subWeightOperation = S.Sorter.subWeightOperations = { + arrayMax: function(sub, calc) { // Return maxmium weight found in array - for (var max, l = subArray.length; l--;) { + for (var max, l = sub.length; l--;) { max = Math.max( max || 0, - this._calcWeight(subArray[l], subjectRegex, subject, isRegexSearch) + calc(sub[l]) ); } return max; } }; + // max deprecated, but still here so we don't break anything: + // TODO: remove + subWeightOperation.max = subWeightOperation.arrayMax; + Sorter.prototype = S.Sorter.prototype = { _generateSubjectRegex: function(subject) { @@ -99,37 +103,38 @@ this._array = array; return this; }, - sort: function(array, subject) { - return this.setArray(array).sortBy(subject); + sort: function(array, subject, subWeightOperation) { + return this.setArray(array).sortBy(subject, subWeightOperation); }, - sortBy: function(subject) { + sortBy: function(subject, subWeightOperation) { if (!subject) return this._array; + subWeightOperation = subWeightOperation || this._subWeightOperation + var array = this._array.slice(0), me = this, isRegexSearch = S._isRegExp(subject), + fixedCalcWeight = function(str) { + return me._calcWeight(str, regex, subject, isRegexSearch); + }, regex = isRegexSearch ? RegExp(subject.source, 'ig') : this._generateSubjectRegex(subject); return array.sort(function(a, b){ - var aIsArray = S._isArray(a), - bIsArray = S._isArray(b), - l, max, aWeight, bWeight; + var l, max, aWeight, bWeight; - if (aIsArray) { - aWeight = me._subArrayWeightOperation(a, regex, subject, isRegexSearch); + if (a === Object(a)) { + aWeight = subWeightOperation(a, fixedCalcWeight); } else { - a = String(a); aWeight = me._calcWeight(a, regex, subject, isRegexSearch); } - if (bIsArray) { - bWeight = me._subArrayWeightOperation(b, regex, subject, isRegexSearch); + if (b === Object(b)) { + bWeight = subWeightOperation(b, fixedCalcWeight); } else { - b = String(b); bWeight = me._calcWeight(b, regex, subject, isRegexSearch); } @@ -146,6 +151,8 @@ }, _calcWeight: function(value, regex, subject, isRegexSearch) { + value = String(value); + if (value === subject) return 1; if (value.toLowerCase() === subject.toLowerCase()) return .9; diff --git a/package.json b/package.json index 2ca8780..27b4c6c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "relevancy", "description": "Unidirectional string relevancy", - "version": "0.1.0", + "version": "0.2.0", "author": "James Padolsey https://github.com/padolsey", "bugs" : { "url" : "http://github.com/padolsey/relevancy.js/issues" diff --git a/readme.md b/readme.md index 8b4bcd2..fec9137 100644 --- a/readme.md +++ b/readme.md @@ -21,7 +21,7 @@ Hopefully, relevancy.js can rectify this with its not-so-complex weighting algor ## Intro -**[Version: 0.1.0dev]** +**[Version: 0.2.0]** relevancy.js contains a basic sorting/weighting algorithm that can be used to weight a short string relative to another short string. It can gage the relevancy between two strings, but only in a unidirectional manner (`"Lon"` is more *relevant* to `"London"` than `"London"` is to `"Lon"`). This was intentional as its main use-case is autocompletion -- i.e. matching partial typed words against large data lists. @@ -112,6 +112,13 @@ mySorter.sortBy('thingToFind'); mySorter.sort(arrayToSearch, 'thingToFind'); ``` +## Changelog + + * **0.2** + * `subArrayWeightOperation` option renamed to `subWeightOperation` (because it's used for regular sub-objects as well as arrays) + * Arguments passed to `subWeightOperation` are now simplified and only include the sub-item and a `calc` function which you call to determine the actual weight. The resulting weight should be returned from your custom `subWeightOperation` function. + * `subWeightOperation` option added to `sort` method. See [issue #1](https://github.com/padolsey/relevancy.js/issues/1). + ## Todo * Tidy up diff --git a/test/test.js b/test/test.js index 58748aa..e8bf08b 100644 --- a/test/test.js +++ b/test/test.js @@ -211,7 +211,7 @@ test('max [default]', function(){ }); -test('custom', function(){ +test('custom - sub arrays', function(){ var unsorted = [ ['a', 'aa', 'aa'], @@ -219,9 +219,9 @@ test('custom', function(){ ['b', 'aa', 'aa...'] ], sorted = relevancy.Sorter({ - subArrayWeightOperation: function(subArray, subjectRegex, subject, isRegexSearch) { + subWeightOperation: function(subArray, calc) { // First item only - return this._calcWeight(subArray[0], subjectRegex, subject, isRegexSearch); + return calc(subArray[0]); } }).sort(unsorted, 'aa'); @@ -236,6 +236,49 @@ test('custom', function(){ }); +test('custom - sub objects', function(){ + var unsorted = [ + {name: 'John'}, + {name: 'Janet'}, + {name: 'Linda'}, + {name: 'Chris'}, + {name: 'Amber'} + ], + sorted = relevancy.Sorter({ + subWeightOperation: function(sub, calc) { + return calc(sub.name); + } + }).sort(unsorted, 'an'); + + deepEqual( + sorted, + [ + unsorted[1], + unsorted[4], + unsorted[2], + unsorted[0], + unsorted[3] + ] + ); + + // Alternative sig: + sorted = relevancy.sort(unsorted, 'an', function(sub, calc) { + return calc(sub.name); + }); + + deepEqual( + sorted, + [ + unsorted[1], + unsorted[4], + unsorted[2], + unsorted[0], + unsorted[3] + ] + ); + +}); + module('Misc. configs'); test('Basic names - Custom secondary comparator (retain index)', function(){