mirror of
https://gitlab.com/vindarel/ciel.git
synced 2026-01-21 12:02:43 -08:00
add cl-json-pointer with shorter functions
This commit is contained in:
parent
890c4a8a55
commit
b33d99e4d2
6 changed files with 176 additions and 6 deletions
4
ciel.asd
4
ciel.asd
|
|
@ -39,7 +39,8 @@
|
|||
:closer-mop
|
||||
:cl-ansi-text
|
||||
:cl-csv
|
||||
:shasht
|
||||
:shasht ;; json
|
||||
:cl-json-pointer
|
||||
:dissect
|
||||
:fset
|
||||
:generic-cl
|
||||
|
|
@ -131,6 +132,7 @@
|
|||
:components ((:module "src"
|
||||
:components
|
||||
((:file "packages")
|
||||
(:file "json-pointer-minus")
|
||||
(:file "ciel")))
|
||||
(:module "src/more-docstrings"
|
||||
:components
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ It's Common Lisp, batteries included.
|
|||
|
||||
It comes in 3 forms:
|
||||
|
||||
- a binary, to run CIEL **scripts**.
|
||||
- a binary, to run CIEL **scripts**: fast start-up times, standalone binary, built-in utilities.
|
||||
- a simple full-featured **REPL** for the terminal.
|
||||
- a **Lisp library**.
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
var footer = [
|
||||
'<hr/>',
|
||||
'<footer style="text-align: right;">',
|
||||
'<span style=\"color: dimgrey\">CIEL developers 2022. <a href="https://github.com/sponsors/vindarel/">Show your love!</a></span>',
|
||||
'<span style=\"color: dimgrey\">CIEL developers 2023. <a href="https://github.com/sponsors/vindarel/">Show your love!</a></span>',
|
||||
'</footer>'
|
||||
].join('');
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ It's always
|
|||
(access my-structure :elt)
|
||||
```
|
||||
|
||||
for an alist, a hash-table, a struct, an object… Use `accesses` for nested access (specially useful with JSON).
|
||||
for an alist, a hash-table, a struct, an object… Use `accesses` for nested access (specially useful with JSON). See also `json-pointer`.
|
||||
|
||||
### Hash-table utilities (Alexandria and Serapeum)
|
||||
|
||||
|
|
@ -161,9 +161,13 @@ See also:
|
|||
|
||||
### JSON
|
||||
|
||||
We use [shasht](https://github.com/yitzchak/shasht). It has a `json` nickname.
|
||||
We use [shasht](https://github.com/yitzchak/shasht) to read and write JSON. It has a `json` nickname.
|
||||
|
||||
It is one of the newest and one of the best JSON handling libraries.
|
||||
We use [cl-json-pointer](https://github.com/y2q-actionman/cl-json-pointer/) to refer to nested keys with a short syntax. It has a `json-pointer` nickname.
|
||||
|
||||
#### read-json, write-json
|
||||
|
||||
Shasht is one of the newest and one of the best JSON handling libraries.
|
||||
|
||||
To encode an object to a stream (standard output, a string, or another
|
||||
stream), use `write-json`. Its signature is:
|
||||
|
|
@ -342,6 +346,70 @@ There is also a keyword variant `write-json*` which will set the various dynamic
|
|||
variables from supplied keywords and will default to the current dynamic value
|
||||
of each keyword.
|
||||
|
||||
#### JSON pointer
|
||||
|
||||
JSON pointers ([RFC 6901](https://www.rfc-editor.org/rfc/rfc6901)) are especially handy to manipulate nested objects. We can access, set and delete keys and values with short pointers, which are strings.
|
||||
|
||||
Example:
|
||||
|
||||
~~~lisp
|
||||
(defparameter *json-data*
|
||||
"{
|
||||
\"foo\": [\"bar\", \"baz\"]
|
||||
}")
|
||||
|
||||
(let ((obj (json:read-json *json-data*)))
|
||||
(json-pointer:get-by obj "/foo/0"))
|
||||
;; => "bar"
|
||||
~~~
|
||||
|
||||
[cl-json-pointer](https://github.com/y2q-actionman/cl-json-pointer/) has some lengthy function names:
|
||||
|
||||
- `get-by-json-pointer`, `set-by-json-pointer`… especially if we access them with the `json-pointer:` prefix.
|
||||
|
||||
We provide shorten ones:
|
||||
|
||||
- `get-by` `(obj pointer)`
|
||||
- `set-by` `(obj pointer value)`
|
||||
- `update-by` `(place pointer value)`
|
||||
- `add-by` `(obj pointer value)`
|
||||
- `delete-by` `(obj pointer)`
|
||||
- `deletef-by` `(place pointer)`
|
||||
- `remove-by` `(obj pointer)`
|
||||
- `exists-p-by` `(obj pointer)`
|
||||
|
||||
`get-by` traverses OBJ with POINTER and returns three values:
|
||||
|
||||
- the found value (nil if not found),
|
||||
- a generalized boolean saying the existence of the place pointed by POINTER,
|
||||
- and NIL.
|
||||
|
||||
JSON-POINTER functions actually take a dict (hash-table) as first argument.
|
||||
|
||||
Examples:
|
||||
|
||||
~~~lisp
|
||||
(json-pointer:get-by (dict \"a\"
|
||||
(dict \"aa\" 11))
|
||||
\"/a/aa\")
|
||||
;; => 11
|
||||
~~~
|
||||
|
||||
Parse a JSON string with `shasht:read-json` before feeding the result to json-pointer:
|
||||
|
||||
~~~lisp
|
||||
(defvar *json-string* \"{\\\"foo\\\": [\\\"1\\\", \\\"2\\\"]}\")
|
||||
|
||||
(let ((obj (shasht:read-json *json-string*)))
|
||||
(json-pointer:get-by obj \"/foo\"))
|
||||
;; =>
|
||||
#(\"1\" \"2\")
|
||||
T
|
||||
NIL
|
||||
~~~
|
||||
|
||||
A JSON pointer starts with a "/".
|
||||
|
||||
|
||||
## Date and time
|
||||
|
||||
|
|
|
|||
99
src/json-pointer-minus.lisp
Normal file
99
src/json-pointer-minus.lisp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
;;
|
||||
;; JSON-POINTER
|
||||
;;
|
||||
;; cl-json-pointer has lengthy functions: get-by-json-pointer, add-by-json-pointer, etc.
|
||||
;; Let's create shorter ones: get-by etc.
|
||||
;;
|
||||
;; But why doesn't it accept a JSON string as input?!
|
||||
|
||||
(in-package :ciel)
|
||||
|
||||
(setf cl-json-pointer:*json-object-flavor* :shasht)
|
||||
|
||||
(defun json-pointer-get-by (obj pointer &key (flavor cl-json-pointer:*json-object-flavor*))
|
||||
"Traverse OBJ with POINTER and return three values:
|
||||
|
||||
- the found value (`nil' if not found),
|
||||
- a generalized boolean saying the existence of the place pointed by POINTER,
|
||||
- and NIL.
|
||||
|
||||
GET-BY is a shorter name of cl-json-pointer:get-by-json-pointer added by CIEL.
|
||||
|
||||
In CIEL, we use the SHASHT library to handle JSON.
|
||||
SHASHT returns a hash-table.
|
||||
JSON-POINTER functions take a dict (hash-table) as first argument.
|
||||
|
||||
Examples:
|
||||
|
||||
(json-pointer:get-by (dict \"a\"
|
||||
(dict \"aa\" 11))
|
||||
\"/a/aa\")
|
||||
;; => 11
|
||||
|
||||
Parse a JSON string with SHASHT:READ-JSON before feeding the result to json-pointer:
|
||||
|
||||
(defvar *json-string* \"{\\\"foo\\\": [\\\"1\\\", \\\"2\\\"]}\")
|
||||
|
||||
(let ((obj (shasht:read-json *json-string*)))
|
||||
(json-pointer:get-by obj \"/foo\"))
|
||||
;; =>
|
||||
#(\"1\" \"2\")
|
||||
T
|
||||
NIL
|
||||
"
|
||||
(cl-json-pointer:get-by-json-pointer obj pointer :flavor flavor))
|
||||
|
||||
#+(or)
|
||||
(defvar *json-string* "{\"foo\": [\"1\", \"2\"]}")
|
||||
|
||||
(defun json-pointer-set-by (obj pointer value &key (flavor cl-json-pointer:*json-object-flavor*))
|
||||
"Traverse OBJ with POINTER, set VALUE into the pointed place, and return the modified OBJ."
|
||||
(cl-json-pointer:set-by-json-pointer obj pointer value :flavor flavor))
|
||||
|
||||
(defun json-pointer-update-by (place pointer value &key (flavor cl-json-pointer:*json-object-flavor*))
|
||||
"Set the result of SET-BY to the referred PLACE.
|
||||
|
||||
UPDATE-BY is a modify macro for SET-BY (like PUSH or INCF)."
|
||||
(cl-json-pointer:update-by-json-pointer place pointer value :flavor flavor))
|
||||
|
||||
(defun json-pointer-add-by (obj pointer value &key (flavor cl-json-pointer:*json-object-flavor*))
|
||||
"Works as `set-by', except this tries to make a new list when setting to lists."
|
||||
(cl-json-pointer:add-by-json-pointer obj pointer value :flavor flavor))
|
||||
|
||||
(defun json-pointer-delete-by (obj pointer &key (flavor cl-json-pointer:*json-object-flavor*))
|
||||
"Traverse OBJ with POINTER, delete the pointed place, and return the modified OBJ."
|
||||
(cl-json-pointer:delete-by-json-pointer obj pointer :flavor flavor))
|
||||
|
||||
(defun json-pointer-deletef-by (place pointer &key (flavor cl-json-pointer:*json-object-flavor*))
|
||||
"Set the result of DELETE-BY to the referred PLACE.
|
||||
|
||||
This is a modify macro for DELETE-BY (like PUSH or INCF)."
|
||||
(cl-json-pointer:deletef-by-json-pointer place pointer :flavor flavor))
|
||||
|
||||
(defun json-pointer-remove-by (obj pointer &key (flavor cl-json-pointer:*json-object-flavor*))
|
||||
"Like `delete-by', except this tries to make a new list when deleting from lists."
|
||||
(cl-json-pointer:remove-by-json-pointer obj pointer :flavor flavor))
|
||||
|
||||
(defun json-pointer-exists-p-by (obj pointer &key (flavor cl-json-pointer:*json-object-flavor*))
|
||||
"Traverse OBJ with POINTER and return the existence of the place pointed by POINTER."
|
||||
(cl-json-pointer:exists-p-by-json-pointer obj pointer :flavor flavor))
|
||||
|
||||
(defun json-pointer-shorten-functions ()
|
||||
"Shorten function names inside the cl-json-pointer package."
|
||||
(let ((tuples (list
|
||||
(list "GET-BY" #'json-pointer-get-by)
|
||||
;; NAME NEW FUNCTION
|
||||
(list "ADD-BY" #'json-pointer-add-by)
|
||||
(list "SET-BY" #'json-pointer-set-by)
|
||||
(list "UPDATE-BY" #'json-pointer-update-by)
|
||||
(list "DELETE-BY" #'json-pointer-delete-by)
|
||||
(list "DELETEF-BY" #'json-pointer-deletef-by)
|
||||
(list "REMOVE-BY" #'json-pointer-remove-by)
|
||||
(list "EXISTS-P-BY" #'json-pointer-exists-p-by))))
|
||||
(loop for tuple in tuples
|
||||
for sym = (intern (first tuple) 'cl-json-pointer)
|
||||
do (export sym 'cl-json-pointer)
|
||||
(setf (symbol-function sym) (second tuple))
|
||||
collect sym)))
|
||||
|
||||
(json-pointer-shorten-functions)
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
(:csv :cl-csv)
|
||||
(:http :dexador)
|
||||
(:json :shasht)
|
||||
(:json-pointer :cl-json-pointer)
|
||||
|
||||
(:routes :easy-routes)))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue