Skip to content

Instantly share code, notes, and snippets.

@brianmhunt
Last active December 16, 2015 23:19
Show Gist options
  • Save brianmhunt/5512916 to your computer and use it in GitHub Desktop.
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
#
# 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