Skip to content

Commit

Permalink
- Fixed init and tail
Browse files Browse the repository at this point in the history
- Added `getAt`, `head`, `last`
- Some minor improvements in tests and documentation
  • Loading branch information
ascartabelli committed Mar 23, 2016
1 parent a6f2712 commit 332886f
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 23 deletions.
95 changes: 91 additions & 4 deletions src/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ function difference (array) {
* @memberof module:lamb
* @category Array
* @function
* @see {@link module:lamb.dropN|dropN}
* @see {@link module:lamb.take|take}, {@link module:lamb.takeN|takeN}
* @see {@link module:lamb.takeWhile|takeWhile}, {@link module:lamb.dropWhile|dropWhile}
* @param {ArrayLike} arrayLike
* @param {Number} n
* @returns {Array}
Expand All @@ -97,6 +100,9 @@ var drop = binary(slice);
* @memberof module:lamb
* @category Array
* @function
* @see {@link module:lamb.drop|drop}
* @see {@link module:lamb.take|take}, {@link module:lamb.takeN|takeN}
* @see {@link module:lamb.takeWhile|takeWhile}, {@link module:lamb.dropWhile|dropWhile}
* @param {Number} n
* @returns {Function}
*/
Expand All @@ -113,6 +119,9 @@ var dropN = _curry(drop, 2, true);
*
* @memberof module:lamb
* @category Array
* @see {@link module:lamb.takeWhile|takeWhile}
* @see {@link module:lamb.drop|drop}, {@link module:lamb.dropN|dropN}
* @see {@link module:lamb.take|take}, {@link module:lamb.takeN|takeN}
* @param {ListIteratorCallback} predicate
* @param {Object} [predicateContext]
* @returns {Function}
Expand Down Expand Up @@ -271,6 +280,35 @@ function flatten (array) {
return _flatten(array, []);
}

/**
* Retrieves the element at the given index in an array-like object.<br/>
* Like {@link module:lamb.slice|slice} the index can be negative.<br/>
* If the index isn't supplied, or if its value it's out of the array-like bounds,
* the function will return <code>undefined</code>.
* @example
* var getFifthElement = _.getAt(4);
*
* getFifthElement([1, 2, 3, 4, 5]) // => 5
* getFifthElement("foo bar") // => "b"
* getFifthElement([]) // => undefined
* getFifthElement("foo") // => undefined
*
* @example <caption>Using negative indexes</caption>
* _.getAt(-2)([1, 2, 3]) // => 2
* _.getAt(-3)("foo") // => "f"
*
* @memberof module:lamb
* @category Array
* @see {@link module:lamb.head|head} and {@link module:lamb.last|last} for common use cases shortcuts.
* @param {Number} index
* @returns {Function}
*/
function getAt (index) {
return function (arrayLike) {
return arrayLike[index < 0 ? index + arrayLike.length : index];
};
}

/**
* Transforms an array-like object into a lookup table using the provided iteratee as a grouping
* criterion to generate keys and values.
Expand Down Expand Up @@ -385,6 +423,23 @@ function groupBy (iteratee, iterateeContext) {
return partial(group, _, iteratee, iterateeContext);
}

/**
* Retrieves the first element of an array-like object.<br/>
* Just a common use case of {@link module:lamb.getAt|getAt} exposed for convenience.
* @example
* _.head([1, 2, 3]) // => 1
* _.head("hello") // => "h"
* _.head([]) // => undefined
*
* @memberof module:lamb
* @category Array
* @function
* @see {@link module:lamb.last|last}
* @param {ArrayLike} arrayLike
* @returns {*}
*/
var head = getAt(0);

/**
* Returns a copy of the given array-like object without the last element.
* @example
Expand All @@ -394,12 +449,13 @@ function groupBy (iteratee, iterateeContext) {
*
* @memberOf module:lamb
* @category Array
* @function
* @see {@link module:lamb.tail|tail}
* @see {@link module:lamb.head|head}, {@link module:lamb.last|last}
* @param {ArrayLike} arrayLike
* @returns {Array}
*/
function init (arrayLike) {
return slice(arrayLike, 0, arrayLike.length - 1);
}
var init = partial(slice, _, 0, -1);

/**
* Returns an array of every item present in all given arrays.<br/>
Expand Down Expand Up @@ -458,6 +514,23 @@ function isIn (arrayLike, value, fromIndex) {
return result;
}

/**
* Retrieves the last element of an array-like object.<br/>
* Just a common use case of {@link module:lamb.getAt|getAt} exposed for convenience.
* @example
* _.last([1, 2, 3]) // => 3
* _.last("hello") // => "o"
* _.last([]) // => undefined
*
* @memberof module:lamb
* @category Array
* @function
* @see {@link module:lamb.head|head}
* @param {ArrayLike} arrayLike
* @returns {*}
*/
var last = getAt(-1);

/**
* Generates an array with the values passed as arguments.
* @example
Expand Down Expand Up @@ -633,10 +706,12 @@ function shallowFlatten (array) {
* @memberOf module:lamb
* @category Array
* @function
* @see {@link module:lamb.init|init}
* @see {@link module:lamb.head|head}, {@link module:lamb.last|last}
* @param {ArrayLike} arrayLike
* @returns {Array}
*/
var tail = binary(partial(slice, _, 1));
var tail = partial(slice, _, 1, void 0);

/**
* Retrieves the first <code>n</code> elements from an array or array-like object.
Expand All @@ -652,6 +727,9 @@ var tail = binary(partial(slice, _, 1));
* @memberof module:lamb
* @category Array
* @function
* @see {@link module:lamb.takeN|takeN}
* @see {@link module:lamb.drop|drop}, {@link module:lamb.dropN|dropN}
* @see {@link module:lamb.takeWhile|takeWhile}, {@link module:lamb.dropWhile|dropWhile}
* @param {ArrayLike} arrayLike
* @param {Number} n
* @returns {Array}
Expand All @@ -670,6 +748,9 @@ var take = partial(slice, _, 0, _);
* @memberof module:lamb
* @category Array
* @function
* @see {@link module:lamb.take|take}
* @see {@link module:lamb.drop|drop}, {@link module:lamb.dropN|dropN}
* @see {@link module:lamb.takeWhile|takeWhile}, {@link module:lamb.dropWhile|dropWhile}
* @param {Number} n
* @returns {Function}
*/
Expand All @@ -686,6 +767,9 @@ var takeN = _curry(take, 2, true);
*
* @memberof module:lamb
* @category Array
* @see {@link module:lamb.dropWhile|dropWhile}
* @see {@link module:lamb.take|take}, {@link module:lamb.takeN|takeN}
* @see {@link module:lamb.drop|drop}, {@link module:lamb.dropN|dropN}
* @param {ListIteratorCallback} predicate
* @param {Object} predicateContext
* @returns {Function}
Expand Down Expand Up @@ -843,11 +927,14 @@ lamb.findIndex = findIndex;
lamb.flatMap = flatMap;
lamb.flatMapWith = flatMapWith;
lamb.flatten = flatten;
lamb.getAt = getAt;
lamb.group = group;
lamb.groupBy = groupBy;
lamb.head = head;
lamb.init = init;
lamb.intersection = intersection;
lamb.isIn = isIn;
lamb.last = last;
lamb.list = list;
lamb.mapWith = mapWith;
lamb.partition = partition;
Expand Down
16 changes: 8 additions & 8 deletions src/sort.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,8 @@ function _sorter (reader, isDescending, comparer) {
*
* @memberof module:lamb
* @category Array
* @see {@link module:lamb.sort|sort}
* @see {@link module:lamb.sorter|sorter}
* @see {@link module:lamb.sorterDesc|sorterDesc}
* @see {@link module:lamb.sortWith|sortWith}
* @see {@link module:lamb.sort|sort}, {@link module:lamb.sortWith|sortWith}
* @see {@link module:lamb.sorter|sorter}, {@link module:lamb.sorterDesc|sorterDesc}
* @param {Array} array
* @param {*} element
* @param {...(Sorter|Function)} [sorter={@link module:lamb.sorter|sorter()}] - The sorting criteria used to sort the array.
Expand Down Expand Up @@ -198,6 +196,8 @@ function insert (array, element) {
*
* @memberof module:lamb
* @category Array
* @see {@link module:lamb.sortWith|sortWith}
* @see {@link module:lamb.sorter|sorter}, {@link module:lamb.sorterDesc|sorterDesc}
* @param {ArrayLike} arrayLike
* @param {...(Sorter|Function)} [sorter={@link module:lamb.sorter|sorter()}]
* @returns {Array}
Expand Down Expand Up @@ -232,9 +232,8 @@ function sort (arrayLike) {
* @category Array
* @function
* @see {@link module:lamb.insert|insert}
* @see {@link module:lamb.sort|sort}
* @see {@link module:lamb.sort|sort}, {@link module:lamb.sortWith|sortWith}
* @see {@link module:lamb.sorterDesc|sorterDesc}
* @see {@link module:lamb.sortWith|sortWith}
* @param {Function} [reader={@link module:lamb.identity|identity}] A function meant to generate a simple value from a complex one. The function should evaluate the array element and supply the value to be passed to the comparer.
* @param {Function} [comparer] An optional custom comparer function.
* @returns {Sorter}
Expand All @@ -249,9 +248,8 @@ var sorter = partial(_sorter, _, false, _);
* @category Array
* @function
* @see {@link module:lamb.insert|insert}
* @see {@link module:lamb.sort|sort}
* @see {@link module:lamb.sort|sort}, {@link module:lamb.sortWith|sortWith}
* @see {@link module:lamb.sorter|sorter}
* @see {@link module:lamb.sortWith|sortWith}
* @param {Function} [reader={@link module:lamb.identity|identity}] A function meant to generate a simple value from a complex one. The function should evaluate the array element and supply the value to be passed to the comparer.
* @param {Function} [comparer] An optional custom comparer function.
* @returns {Sorter}
Expand All @@ -274,6 +272,8 @@ var sorterDesc = partial(_sorter, _, true, _);
*
* @memberof module:lamb
* @category Array
* @see {@link module:lamb.sort|sort}
* @see {@link module:lamb.sorter|sorter}, {@link module:lamb.sorterDesc|sorterDesc}
* @param {...(Sorter|Function)} [sorter={@link module:lamb.sorter|sorter()}]
* @returns {Function}
*/
Expand Down
49 changes: 47 additions & 2 deletions test/spec/arraySpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ describe("lamb.array", function () {
});

it("should return `undefined` if there is no element satisfying the predicate", function () {
expect(lamb.find(persons, lamb.hasKeyValue("age", 41))).toBe(void 0);
expect(lamb.find(persons, lamb.hasKeyValue("age", 41))).toBeUndefined();
});
});

Expand Down Expand Up @@ -244,6 +244,51 @@ describe("lamb.array", function () {
});
});

describe("getAt / head / last", function () {
var arr = [1, 2, 3, 4];
var s = "abcd";

it("should retrieve the element at the given index in an array-like object", function () {
var getThird = lamb.getAt(2);

expect(getThird(arr)).toBe(3);
expect(getThird(s)).toBe("c");
expect(lamb.head(arr)).toBe(1);
expect(lamb.head(s)).toBe("a");
expect(lamb.last(arr)).toBe(4);
expect(lamb.last(s)).toBe("d");
});

it("should allow negative indexes", function () {
expect(lamb.getAt(-2)(arr)).toBe(3);
expect(lamb.getAt(-2)(s)).toBe("c");
});

it("should throw an error in no array-like object is supplied", function () {
expect(lamb.getAt(2)).toThrow();
expect(lamb.head).toThrow();
expect(lamb.last).toThrow();
});

it("should return undefined if no index is supplied or if the index is out of bound", function () {
expect(lamb.getAt()(arr)).toBeUndefined();
expect(lamb.getAt(-6)(arr)).toBeUndefined();
expect(lamb.getAt(66)(arr)).toBeUndefined();
expect(lamb.getAt(NaN)(arr)).toBeUndefined();
expect(lamb.getAt(null)(arr)).toBeUndefined();
expect(lamb.getAt(void 0)(arr)).toBeUndefined();
expect(lamb.getAt({})(arr)).toBeUndefined();
expect(lamb.getAt("a")(arr)).toBeUndefined();
expect(lamb.head([])).toBeUndefined();
expect(lamb.last([])).toBeUndefined();
});

it("should not tell anyone, but strings holding numbers are accepted as indexes", function () {
expect(lamb.getAt("1")(arr)).toBe(2);
expect(lamb.getAt("2")(s)).toBe("c");
});
});

describe("group / groupBy", function () {
var persons = [
{"name": "Jane", "surname": "Doe", "age": 12, "city": "New York"},
Expand Down Expand Up @@ -478,7 +523,7 @@ describe("lamb.array", function () {

expect(lamb.tail(arr)).toEqual([2, 3, 4, 5]);
expect(arr.length).toBe(5);
expect(lamb.tail("hello")).toEqual(["e", "l", "l", "o"]);
expect(lamb.tail("shell")).toEqual(["h", "e", "l", "l"]);
});

it("should return an empty array when called with an empty array or an array holding only one element", function () {
Expand Down
4 changes: 2 additions & 2 deletions test/spec/functionSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ describe("lamb.function", function () {

expect(callOnSomeString("slice", 1, 3)).toBe("oo");
expect(callOnSomeString("toUpperCase")).toBe("FOO BAR");
expect(callOnSomeString("foo")).toBe(void 0);
expect(callOnSomeString("foo")).toBeUndefined();
});
});

Expand All @@ -224,7 +224,7 @@ describe("lamb.function", function () {
expect(someArray.slice.calls.count()).toBe(1);
expect(someArray.slice.calls.first().object).toBe(someArray);
expect(slice(someString, 1, 3)).toBe("oo");
expect(slice(1)).toBe(void 0);
expect(slice(1)).toBeUndefined();
});
});

Expand Down
4 changes: 2 additions & 2 deletions test/spec/logicSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe("lamb.logic", function () {

expect(filterAdapter([1, 2, 3, 4, 5, 6], isEven)).toEqual([2, 4, 6]);
expect(filterAdapter("123456", isEven)).toBe("246");
expect(filterAdapter({}, isEven)).toBe(void 0);
expect(filterAdapter({}, isEven)).toBeUndefined();

var filterWithDefault = lamb.adapter(filterAdapter, lamb.always("Not implemented"));
expect(filterWithDefault([1, 2, 3, 4, 5, 6], isEven)).toEqual([2, 4, 6]);
Expand Down Expand Up @@ -57,7 +57,7 @@ describe("lamb.logic", function () {

expect(halveIfGreaterThan5(3)).toBe(3);
expect(halveIfGreaterThan5(10)).toBe(5);
expect(lamb.condition(isGreaterThan5, halve)(3)).toBe(void 0);
expect(lamb.condition(isGreaterThan5, halve)(3)).toBeUndefined();
});
});

Expand Down
10 changes: 5 additions & 5 deletions test/spec/objectSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe("lamb.object", function () {
});

it("should return undefined for a unknown property in an existent object", function () {
expect(lamb.getWithPath(obj, "b.a.z")).not.toBeDefined();
expect(lamb.getWithPath(obj, "b.a.z")).toBeUndefined();
});

it("should throw an error if a non existent object is requested in the path", function () {
Expand Down Expand Up @@ -240,7 +240,7 @@ describe("lamb.object", function () {
var newObj = lamb.merge(foo, bar);

expect(newObj).toEqual({a: 1, b: 2, c: 3, d: 4});
expect(newObj.z).not.toBeDefined();
expect(newObj.z).toBeUndefined();
});

it("should handle key homonymy by giving to each source precedence over the previous ones", function (){
Expand All @@ -253,9 +253,9 @@ describe("lamb.object", function () {
var newObj = lamb.mergeOwn(foo, bar);

expect(newObj).toEqual({c: 3, d: 4});
expect(newObj.a).not.toBeDefined();
expect(newObj.b).not.toBeDefined();
expect(newObj.z).not.toBeDefined();
expect(newObj.a).toBeUndefined();
expect(newObj.b).toBeUndefined();
expect(newObj.z).toBeUndefined();
});

it("should handle key homonymy by giving to each source precedence over the previous ones", function (){
Expand Down

0 comments on commit 332886f

Please sign in to comment.