Skip to content

Commit 8ee77a3

Browse files
committed
Move _.omitPath to object.builders per comment by @joshuacc in #177
Also reimplements the function as suggested by @joshuacc. More tests pass in this way, but still not all. This is somewhat inconsistent; arguably, _.omitWhen, _.pickWhen and _.selectKeys belong in object.builders, too.
1 parent 2ac384a commit 8ee77a3

File tree

6 files changed

+52
-87
lines changed

6 files changed

+52
-87
lines changed

docs/underscore.object.builders.js.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ _.frequencies(citations);
2626

2727
Returns a new object resulting from merging the passed objects. Objects
2828
are processed in order, so each will override properties of the same
29-
name occurring in earlier arguments.
29+
name occurring in earlier arguments.
3030

3131
Returns `null` if called without arguments.
3232

@@ -148,3 +148,28 @@ obj === imperialObj;
148148
```
149149

150150
--------------------------------------------------------------------------------
151+
152+
#### omitPath
153+
154+
**Signature:** `_.omitPath(obj:Object, ks:String|Array)`
155+
156+
Returns a copy of `obj` excluding the value represented by the `ks` path.
157+
Path may be given as an array or as a dot-separated string.
158+
If the path contains an array, the value of the path will be removed from all the array elements.
159+
160+
```javascript
161+
var test = {
162+
foo: true,
163+
bar: false,
164+
baz: 42,
165+
dada: {
166+
carlos: {
167+
pepe: 9
168+
},
169+
pedro: 'pedro'
170+
}
171+
};
172+
173+
_.omitPath(test, 'dada.carlos.pepe');
174+
// => {foo: true, bar: false, baz: 42, dada: {carlos: {}, pedro: 'pedro'}}
175+
```

docs/underscore.object.selectors.js.md

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -220,28 +220,3 @@ var philosopherCities = {
220220
_.selectKeys(philosopherCities, ["Plato", "Plotinus"]);
221221
// => { Plato: "Athens", Plotinus: "Rome" }
222222
```
223-
224-
#### omitPath
225-
226-
**Signature:** `_.omitPath(obj:Object, ks:String|Array)`
227-
228-
Returns a copy of `obj` excluding the value represented by the `ks` path.
229-
Path may be given as an array or as a dot-separated string.
230-
If the path contains an array, the value of the path will be removed from all the array elements.
231-
232-
```javascript
233-
var test = {
234-
foo: true,
235-
bar: false,
236-
baz: 42,
237-
dada: {
238-
carlos: {
239-
pepe: 9
240-
},
241-
pedro: 'pedro'
242-
}
243-
};
244-
245-
_.omitPath(test, 'dada.carlos.pepe');
246-
// => {foo: true, bar: false, baz: 42, dada: {carlos: {}, pedro: 'pedro'}}
247-
```

test/object.builders.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ $(document).ready(function() {
5252

5353
assert.deepEqual(_.setPath(obj, 9, ['a', 'b', 'c']), {a: {b: {c: 9, d: 108}}}, '');
5454
assert.deepEqual(_.setPath(ary, 9, [1, 1, 0]), ['a', ['b', [9, 'd'], 'e']], '');
55-
assert.deepEqual(_.setPath(nest, 9, [1, 'b', 1]), [1, {a: 2, b: [3,9], c: 5}, 6], '');
55+
assert.deepEqual(_.setPath(nest, 9, [1, 'b', 1]), [1, {a: 2, b: [3,9], c: 5}, 6], '');
5656

5757
assert.deepEqual(_.setPath(obj, 9, 'a'), {a: 9}, '');
5858
assert.deepEqual(_.setPath(ary, 9, 1), ['a', 9], '');
@@ -69,7 +69,7 @@ $(document).ready(function() {
6969

7070
assert.deepEqual(_.updatePath(obj, _.always(9), ['a', 'b', 'c']), {a: {b: {c: 9, d: 108}}}, '');
7171
assert.deepEqual(_.updatePath(ary, _.always(9), [1, 1, 0]), ['a', ['b', [9, 'd'], 'e']], '');
72-
assert.deepEqual(_.updatePath(nest, _.always(9), [1, 'b', 1]), [1, {a: 2, b: [3,9], c: 5}, 6], '');
72+
assert.deepEqual(_.updatePath(nest, _.always(9), [1, 'b', 1]), [1, {a: 2, b: [3,9], c: 5}, 6], '');
7373

7474
assert.deepEqual(_.updatePath(obj, _.always(9), 'a'), {a: 9}, '');
7575
assert.deepEqual(_.updatePath(ary, _.always(9), 1), ['a', 9], '');
@@ -79,4 +79,18 @@ $(document).ready(function() {
7979
assert.deepEqual(nest, [1, {a: 2, b: [3,4], c: 5}, 6], 'should not modify the original nested structure');
8080
});
8181

82+
QUnit.test("omitPath", function(assert){
83+
var a = {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}}, name: 'aa'}, {file: '..', name: 'bb'}]}};
84+
85+
assert.deepEqual(_.omitPath(a, 'dada.carlos.pepe'), {foo: true, bar: false, baz: 42, dada: {carlos: {}, pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}} , name: 'aa'}, {file: '..', name: 'bb'}]}}, "should return an object without the value that represent the path");
86+
assert.deepEqual(_.omitPath(a, 'dada.carlos'), {foo: true, bar: false, baz: 42, dada: {pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}} , name: 'aa'}, {file: '..', name: 'bb'}]}}, "should return an object without the value that represent the path");
87+
assert.deepEqual(_.omitPath(a, ''), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}} , name: 'aa'}, {file: '..', name: 'bb'}]}}, "should return the whole object because the path is empty");
88+
89+
assert.deepEqual(_.omitPath(a, 'dada.list.file'), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{name: 'aa', more: {other: { a: 1, b: 2}}}, {name: 'bb'}]}}, "should return an object without the value in each object of the list");
90+
assert.deepEqual(_.omitPath(a, 'dada.list.name'), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}}}, {file: '..'}]}}, "should return an object without the value in each object of the list");
91+
92+
assert.deepEqual(_.omitPath(a, 'dada.list'), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro'}}, "should return an object without the list");
93+
94+
assert.deepEqual(_.omitPath(a, 'dada.list.more.other.a'), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{file: '..', more: {other: { b: 2}} , name: 'aa'}, {file: '..', name: 'bb'}]}}, "should return an object without the value inside the values of the list");
95+
});
8296
});

test/object.selectors.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -107,19 +107,4 @@ $(document).ready(function() {
107107

108108
assert.deepEqual(_.omitWhen(a, _.isEmpty), {baz: "something", quux: ['a']}, "should return an object with kvs that return a falsey value for the given predicate");
109109
});
110-
111-
QUnit.test("omitPath", function(assert){
112-
var a = {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}}, name: 'aa'}, {file: '..', name: 'bb'}]}};
113-
114-
assert.deepEqual(_.omitPath(a, 'dada.carlos.pepe'), {foo: true, bar: false, baz: 42, dada: {carlos: {}, pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}} , name: 'aa'}, {file: '..', name: 'bb'}]}}, "should return an object without the value that represent the path");
115-
assert.deepEqual(_.omitPath(a, 'dada.carlos'), {foo: true, bar: false, baz: 42, dada: {pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}} , name: 'aa'}, {file: '..', name: 'bb'}]}}, "should return an object without the value that represent the path");
116-
assert.deepEqual(_.omitPath(a, ''), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}} , name: 'aa'}, {file: '..', name: 'bb'}]}}, "should return the whole object because the path is empty");
117-
118-
assert.deepEqual(_.omitPath(a, 'dada.list.file'), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{name: 'aa', more: {other: { a: 1, b: 2}}}, {name: 'bb'}]}}, "should return an object without the value in each object of the list");
119-
assert.deepEqual(_.omitPath(a, 'dada.list.name'), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{file: '..', more: {other: { a: 1, b: 2}}}, {file: '..'}]}}, "should return an object without the value in each object of the list");
120-
121-
assert.deepEqual(_.omitPath(a, 'dada.list'), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro'}}, "should return an object without the list");
122-
123-
assert.deepEqual(_.omitPath(a, 'dada.list.more.other.a'), {foo: true, bar: false, baz: 42, dada: {carlos: { pepe: 9 }, pedro: 'pedro', list: [{file: '..', more: {other: { b: 2}} , name: 'aa'}, {file: '..', name: 'bb'}]}}, "should return an object without the value inside the values of the list");
124-
});
125110
});

underscore.object.builders.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@
106106
return ret;
107107
},
108108

109+
// Returns an object excluding the value represented by the path
110+
omitPath: function(obj, ks, copy){
111+
if (!obj) return copy;
112+
if (typeof ks == "string") ks = ks.split(".");
113+
if (!copy) copy = obj = _.snapshot(obj);
114+
if (ks.length > 1) return _.omitPath(obj[ks[0]], _.tail(ks), copy);
115+
delete obj[ks[0]];
116+
return copy;
117+
},
118+
109119
// Sets the value at any depth in a nested object based on the
110120
// path described by the keys given.
111121
setPath: function(obj, value, ks, defaultValue) {

underscore.object.selectors.js

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -121,50 +121,6 @@
121121

122122
omitWhen: function(obj, pred) {
123123
return _.pickWhen(obj, function(e) { return !pred(e); });
124-
},
125-
126-
// Returns an object excluding the value represented by the path
127-
omitPath: function(obj, ks){
128-
if (typeof ks == "string") ks = ks.split(".");
129-
130-
// If we have reached an undefined property
131-
// then stop executing and return undefined
132-
if (obj === undefined) return void 0;
133-
134-
// If the path array has no more elements, we've reached
135-
// the intended property and return its value
136-
if (ks.length === 0) return obj;
137-
138-
// If we still have elements in the path array and the current
139-
// value is null, stop executing and return undefined
140-
if (obj === null) return void 0;
141-
142-
var copy = {};
143-
144-
var deepFunc = function (obj, path){
145-
if (!path)
146-
path = [];
147-
_.each(obj, function(value, key) {
148-
if (_.isObject(value)){
149-
if (_.difference(ks, _.union(path, key)).length !== 0){
150-
if (_.isArray(value)){
151-
_.getPath(copy, path)[key] = [];
152-
}else{
153-
_.getPath(copy, path)[key] = {};
154-
}
155-
path.push(key);
156-
deepFunc(value, path);
157-
path.pop(key);
158-
}
159-
}else{
160-
if (_.difference(ks, _.union(path, key)).length !== 0)
161-
_.getPath(copy, path)[key] = value;
162-
}
163-
});
164-
};
165-
deepFunc(obj);
166-
167-
return copy;
168124
}
169125

170126
});

0 commit comments

Comments
 (0)