Last active
December 16, 2015 23:19
-
-
Save brianmhunt/5512916 to your computer and use it in GitHub Desktop.
A way to walk a namespace with a string in Coffeescript/Javascript; requires lodash/underscore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# Deep pluck | |
# ~~~~~~~~~~ | |
# Pull a deeply nested element out based on an array of arguments | |
# | |
# e.g. array['abc'][0] == deepPluck(array, ['abc', 0]) | |
# | |
deepPluck = (obj, array_or_string, _default=undefined) -> | |
if _.isString(array_or_string) | |
keys = array_or_string.split('.') | |
else # it is an array | |
keys = array_or_string | |
result = obj | |
for key in keys | |
if key.endsWith('*') | |
# dereference; i.e. do not unwrap | |
key = key.substring(0, key.length - 1) | |
result = result[key] | |
else | |
# _.result acts like ko.utils.unwrapObservable, as needed, | |
#or calls the given function | |
result = _.result(result, key) | |
if _.isUndefined(result) then return _default | |
return result | |
deepPlant = (obj, array_or_string, value) -> | |
if _.isString(array_or_string) | |
keys = array_or_string.split('.') | |
else # it is an array | |
keys = array_or_string | |
pinpoint = keys.pop() | |
holder = if _.isEmpty(keys) then obj else utils.deepPluck(obj, keys) | |
target = holder[pinpoint] | |
if _.isFunction(target) | |
target(value) | |
else | |
holder[pinpoint] = value | |
return | |
describe('utils/deepPluck', -> | |
obj = a: b: c: d: 1, e: [9, 8] | |
it "should pluck deep values from objects", -> | |
assert.deepEqual(utils.deepPluck(obj, 'a.b.c'), d: 1, e: [9, 8], | |
'a.b.c') | |
assert.equal(utils.deepPluck(obj, 'a.b.c.d'), 1, "a.b.c.d") | |
assert.equal(utils.deepPluck(obj, 'a.b.c.x'), undefined, | |
"a.b.c.x") | |
assert.equal(utils.deepPluck(obj, 'a.b.c.x'), undefined, | |
"a.b.c.x") | |
assert.equal(utils.deepPluck(obj, 'a.b.c.e.1'), 8, "a.b.c.e.1") | |
assert.equal(utils.deepPluck(obj, 'x.r'), undefined, "x.r") | |
assert.equal(utils.deepPluck(obj, 'x'), undefined, | |
"x-undefined") | |
assert.equal(utils.deepPluck(obj, 'x', false), false, | |
"x-false") | |
obj2 = a: (-> 'x'), b: (-> c: 'r') | |
obj2.b.c = 'z' | |
# obj2.b is a function; obj2.b.c is a property of | |
# that fn; obj2.b().c is the value of the object returned | |
# from the fn obj.b | |
it "should not unwrap targets with an asterick (*) suffix", -> | |
assert.equal(utils.deepPluck(obj2, 'a'), 'x', 'a') | |
assert.equal(utils.deepPluck(obj2, 'a*'), obj2.a, 'a*') | |
assert.equal(utils.deepPluck(obj2, 'b.c'), 'r') # obj2.b().c | |
assert.equal(utils.deepPluck(obj2, 'b*.c'), 'z') # obj2.b.c | |
) | |
describe('utils/deepPlant', -> | |
v = undefined | |
obj = a: b: 0, c: (x) -> v = x | |
it "should call a target function with the value", -> | |
utils.deepPlant(obj, 'a.c', 99) | |
assert.equal(v, 99) | |
it "should update a primitive", -> | |
utils.deepPlant(obj, 'a.b', 12) | |
assert.equal(obj.a.b, 12) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment