Switch chaining to the {} and {}= operators

This commit is contained in:
flaviut 2014-05-26 16:13:19 -04:00
commit c7a57dc184

View file

@ -628,29 +628,26 @@ proc len*(n: PJsonNode): int =
of JObject: result = n.fields.len of JObject: result = n.fields.len
else: discard else: discard
proc `[]`*(node: PJsonNode, name: string, default: PJsonNode = nil): PJsonNode = proc `[]`*(node: PJsonNode, name: string): PJsonNode
## Gets a field from a `JObject`. If node is nil, this returns `default` {.raises: [EInvalidValue].} =
## This is to allow for chaining such as the following: ## Gets a field from a `JObject`. If `node` is nil, raises an
## .. code-block Nimrod ## `EInvalidValue` exception. If the value at `name` does not
## foo["field1"]["field2"] ## exist, returns nil
##
## If `field1` is undefined, it will return nil, and the access on `field2` will
## pass through and return `default`. Also returns `default` if the key is not found.
if isNil(node): if isNil(node):
return default raise newException(EInvalidValue, "node may not be nil")
assert(node.kind == JObject) assert(node.kind == JObject)
for key, item in items(node.fields): for key, item in items(node.fields):
if key == name: if key == name:
return item return item
return default return nil
proc `[]`*(node: PJsonNode, index: int, default: PJsonNode = nil): PJsonNode {.raises: [EInvalidIndex].}= proc `[]`*(node: PJsonNode, index: int): PJsonNode
## Gets the node at `index` in an Array.If `node` is nil, this returns `result`, {.raises: [EInvalidIndex, EInvalidValue].} =
## which is by default `nil` to allow for chaining. `EInvalidIndex` is raised if `index` ## Gets the node at `index` in an Array. `EInvalidIndex` is raised if `index`
## is out of bounds ## is out of bounds
if isNil(node):
return default
assert(node.kind == JArray) assert(node.kind == JArray)
if isNil(node):
raise newException(EInvalidValue, "node may not be nil")
if index < 0 or index >= node.elems.len: if index < 0 or index >= node.elems.len:
raise newException(EInvalidIndex, raise newException(EInvalidIndex,
"index " & $index & " is out of range [0, " & $node.elems.len & ")") "index " & $index & " is out of range [0, " & $node.elems.len & ")")
@ -686,6 +683,25 @@ proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) =
return return
obj.fields.add((key, val)) obj.fields.add((key, val))
proc `{}`*(node: PJsonNode, names: varargs[string]): PJsonNode =
## Transverses the node and gets the given value. If any of the
## names does not exist, returns nil
result = node
for name in names:
result = result[name]
if isNil(result):
return nil
proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) =
## Transverses the node and tries to set the value at the given location
## to `value` If any of the names are missing, they are added
var node = node
for i in 0..(names.len-2):
if isNil(node[names[i]]):
node[names[i]] = newJObject()
node = node[names[i]]
node[names[names.len-1]] = value
proc delete*(obj: PJsonNode, key: string) = proc delete*(obj: PJsonNode, key: string) =
## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs. ## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
assert(obj.kind == JObject) assert(obj.kind == JObject)
@ -942,11 +958,9 @@ when isMainModule:
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }""" let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
# nil passthrough # nil passthrough
assert(testJson["doesnt_exist"][1] == nil) assert(testJson{"doesnt_exist", "anything"} == nil)
assert(testJson["doesnt_exist"]["anything"] == nil) testJson{["c", "d"]} = %true
# default param assert(testJson["c"]["d"].bval)
assert(testJson["doesnt_exist",%true].bval)
assert(testJson["doesnt_exist"][1,%true].bval)
# Bounds checking # Bounds checking
try: try: