Skip to content

Commit

Permalink
- Added updateAt
Browse files Browse the repository at this point in the history
- Added missing test for `updateIn` and `updateKey`
  • Loading branch information
ascartabelli committed Apr 19, 2016
1 parent 8a1d77d commit 416e156
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 14 deletions.
53 changes: 44 additions & 9 deletions src/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ function _flatten (array, output) {
return output;
}

function _getPositiveIndex (index, len) {
return clamp(index, -len, len - 1) === Math.floor(index) ? index < 0 ? index + len : index : void 0;
}

function _groupWith (makeValue, startValue) {
return function (arrayLike, iteratee, iterateeContext) {
return reduce(arrayLike, function (result, element, idx) {
Expand All @@ -33,6 +37,17 @@ function _groupWith (makeValue, startValue) {
};
}

function _setIndex (arrayLike, index, value, updater) {
var result = slice(arrayLike);
var idx = _getPositiveIndex(index, arrayLike.length);

if (!isUndefined(idx)) {
result[idx] = updater ? updater(arrayLike[idx]) : value;
}

return result;
}

/**
* Builds a predicate to check if an array-like object contains the given value.<br/>
* Please note that the equality test is made with {@link module:lamb.isSVZ|isSVZ}; so you can
Expand Down Expand Up @@ -373,7 +388,8 @@ function flatten (array) {
*/
function getAt (index) {
return function (arrayLike) {
return Math.floor(index) === index ? arrayLike[index < 0 ? index + arrayLike.length : index] : void 0;
var idx = _getPositiveIndex(index, arrayLike.length);
return isUndefined(idx) ? idx : arrayLike[idx];
};
}

Expand Down Expand Up @@ -866,14 +882,7 @@ function reverse (arrayLike) {
*/
function setAt (index, value) {
return function (arrayLike) {
var result = slice(arrayLike);
var len = arrayLike.length;

if (clamp(index, -len, len - 1) === Math.floor(index)) {
result[index + (index < 0 ? len : 0)] = value;
}

return result;
return _setIndex(arrayLike, index, value);
};
}

Expand Down Expand Up @@ -1081,6 +1090,31 @@ function uniques (arrayLike, iteratee, iterateeContext) {
return result;
}

/**
* Builds a function that creates a copy of an array-like object with the given index changed
* by applying the provided function to its value.<br/>
* If the index is not an integer or if it's out of bounds, the function will return a copy of the original array.<br/>
* Negative indexes are allowed.
* @example
* var arr = ["a", "b", "c"];
* var toUpperCase = _.invoker("toUpperCase");
*
* _.updateAt(1, toUpperCase)(arr) // => ["a", "B", "c"]
* _.updateAt(-1, toUpperCase)(arr) // => ["a", "b", "C"]
* _.updateAt(10, toUpperCase)(arr) // => ["a", "b", "c"]
*
* @memberof module:lamb
* @category Array
* @param {Number} index
* @param {Function} updater
* @returns {Function}
*/
function updateAt (index, updater) {
return function (arrayLike) {
return _setIndex(arrayLike, index, null, updater);
};
}

/**
* Builds a list of arrays out of the given array-like objects by pairing items with the same index.<br/>
* The received array-like objects will be truncated to the shortest length.<br/>
Expand Down Expand Up @@ -1154,5 +1188,6 @@ lamb.takeWhile = takeWhile;
lamb.transpose = transpose;
lamb.union = union;
lamb.uniques = uniques;
lamb.updateAt = updateAt;
lamb.zip = zip;
lamb.zipWithIndex = zipWithIndex;
80 changes: 75 additions & 5 deletions test/spec/arraySpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -588,16 +588,20 @@ describe("lamb.array", function () {

describe("setAt", function () {
var arr = [1, 2, 3, 4, 5];
var arrCopy = [1, 2, 3, 4, 5];
var s = "hello";

afterEach(function () {
expect(arr).toEqual(arrCopy);
});

it("should allow to set a value in a copy of the given array-like object", function () {
var newArr = lamb.setAt(2, 99)(arr);
var newArr2 = lamb.setAt(4, 99)(arr);
var newS = lamb.setAt(0, "c")(s);

expect(newArr).toEqual([1, 2, 99, 4, 5]);
expect(newArr2).toEqual([1, 2, 3, 4, 99]);
expect(arr).toEqual([1, 2, 3, 4, 5]);
expect(newS).toEqual(["c", "e", "l", "l", "o"]);
});

Expand All @@ -607,7 +611,6 @@ describe("lamb.array", function () {

expect(newArr).toEqual([1, 2, 3, 4, 99]);
expect(newArr2).toEqual([99, 2, 3, 4, 5]);
expect(arr).toEqual([1, 2, 3, 4, 5]);
});

it("should return an array copy of the array-like if the index is not an integer", function () {
Expand All @@ -626,8 +629,6 @@ describe("lamb.array", function () {
expect(value).toEqual(arr);
expect(value).not.toBe(arr);
});

expect(arr).toEqual([1, 2, 3, 4, 5]);
});

it("should return an array copy of the array-like if the index is out of bounds", function () {
Expand All @@ -637,7 +638,6 @@ describe("lamb.array", function () {

expect(newArr).toEqual([1, 2, 3, 4, 5]);
expect(newArr2).toEqual([1, 2, 3, 4, 5]);
expect(arr).toEqual([1, 2, 3, 4, 5]);
expect(newArr).not.toBe(arr);
expect(newArr2).not.toBe(arr);
expect(newS).toEqual(["h", "e", "l", "l", "o"]);
Expand Down Expand Up @@ -776,6 +776,76 @@ describe("lamb.array", function () {
});
});

describe("updateAt", function () {
var arr = [1, 2, 3, 4, 5];
var arrCopy = [1, 2, 3, 4, 5];
var s = "hello";
var inc = function (n) { return n + 1; };
var incSpy = jasmine.createSpy("inc").and.callFake(inc);
var fn99 = lamb.always(99);

afterEach(function () {
expect(arr).toEqual(arrCopy);
incSpy.calls.reset();
});

it("should allow to update a value in a copy of the given array-like object with the provided function", function () {
expect(lamb.updateAt(2, incSpy)(arr)).toEqual([1, 2, 4, 4, 5]);
expect(incSpy.calls.count()).toBe(1);
expect(incSpy.calls.argsFor(0).length).toBe(1);
expect(incSpy.calls.argsFor(0)[0]).toBe(3);
expect(lamb.updateAt(0, lamb.always("c"))(s)).toEqual(["c", "e", "l", "l", "o"]);
});

it("should allow negative indexes", function () {
var newArr = lamb.updateAt(-1, fn99)(arr);
var newArr2 = lamb.updateAt(-5, fn99)(arr);

expect(newArr).toEqual([1, 2, 3, 4, 99]);
expect(newArr2).toEqual([99, 2, 3, 4, 5]);
});

it("should return an array copy of the array-like if the index is not an integer", function () {
[
lamb.updateAt(NaN, fn99)(arr),
lamb.updateAt(null, fn99)(arr),
lamb.updateAt(void 0, fn99)(arr),
lamb.updateAt({}, fn99)(arr),
lamb.updateAt([], fn99)(arr),
lamb.updateAt([2], fn99)(arr),
lamb.updateAt("a", fn99)(arr),
lamb.updateAt("2", fn99)(arr),
lamb.updateAt("2.5", fn99)(arr),
lamb.updateAt(2.5, fn99)(arr)
].forEach(function (value) {
expect(value).toEqual(arr);
expect(value).not.toBe(arr);
});
});

it("should return an array copy of the array-like if the index is out of bounds", function () {
var newArr = lamb.updateAt(5, fn99)(arr);
var newArr2 = lamb.updateAt(-6, fn99)(arr);
var newS = lamb.updateAt(10, fn99)(s);

expect(newArr).toEqual([1, 2, 3, 4, 5]);
expect(newArr2).toEqual([1, 2, 3, 4, 5]);
expect(newArr).not.toBe(arr);
expect(newArr2).not.toBe(arr);
expect(newS).toEqual(["h", "e", "l", "l", "o"]);
});

it("should check the existence of the destination index before trying to apply the received function to it", function () {
var toUpperCase = lamb.invoker("toUpperCase");
expect(lamb.updateAt(10, toUpperCase)(s)).toEqual(["h", "e", "l", "l", "o"]);
});

it("should throw an exception if no array-object is supplied", function () {
var fn = lamb.updateAt(0, fn99);
expect(fn).toThrow();
});
});

describe("transpose / zip", function () {
var a1 = [1, 2, 3, 4];
var a2 = [5, 6, 7];
Expand Down
8 changes: 8 additions & 0 deletions test/spec/objectSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,14 @@ describe("lamb.object", function () {
expect(newObjB).not.toBe(foo);
});

it("should check the validity of the destination key before trying to apply the received function to it", function () {
var o = {a: 1};
var toUpperCase = lamb.invoker("toUpperCase");

expect(lamb.updateIn(o, "z", toUpperCase)).toEqual({a: 1});
expect(lamb.updateKey("z", toUpperCase)(o)).toEqual({a: 1});
});

it("should consider values other than objects or array-like objects as empty objects", function () {
wannabeEmptyObjects.map(function (value) {
expect(lamb.updateIn(value, "a", lamb.always(99))).toEqual({});
Expand Down

0 comments on commit 416e156

Please sign in to comment.