[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/yaml 96d3e51aeb 048/124: Add yaml-encode feature
From: |
ELPA Syncer |
Subject: |
[elpa] externals/yaml 96d3e51aeb 048/124: Add yaml-encode feature |
Date: |
Fri, 29 Nov 2024 15:59:59 -0500 (EST) |
branch: externals/yaml
commit 96d3e51aeb48ef61440f99a7f4161ad12cf3e749
Author: Zachary Romero <zacromero@posteo.net>
Commit: Zachary Romero <zacromero@posteo.net>
Add yaml-encode feature
---
README.md | 24 +++++++++--
yaml-tests.el | 51 +++++++++++++++++++++++
yaml.el | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 201 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index a896f9881c..91c635d32b 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
yaml.el is a YAML parser written in Emacs List without any external
dependencies. It provides an interface similar to the Emacs JSON
-parsing utility. The function provided is as follows:
+parsing utility. The functions provided are as follows:
``` emacs-lisp
(yaml-parse-string string &rest args)
@@ -14,7 +14,7 @@ The following keyword args are accepted:
objects data in. It takes the following symbols:
- `hash-table` (default)
- `alist`
- - `plist`
+n - `plist`
- `:sequence-type` specifies the Lisp data structure to store the
parsed sequences in. It takes the following symbols:
- `array` (default)
@@ -24,6 +24,13 @@ The following keyword args are accepted:
- `:false-object` specifies the lisp object to use for false.
Defaults to the symbol `:false`.
+```emacs-lisp
+(yaml-encode object)
+```
+
+The function `yaml-encode` will encode a Lisp object to a YAML string.
+
+
## Installation
Until this is published to MELPA you will need to use the code from this repo
directly.
@@ -56,9 +63,20 @@ translations:
three: үш")
;; => #s(hash-table ... data ("translations" #s(hash-table ...)))
-```
+(yaml-encode '("omitted" ((count . 3) (value . 10) (items ("ruby" "diamond")))
"omitted"))
+
+;; => "
+- omitted
+- count: 3
+ value: 10
+ items:
+ ruby: [diamond]
+- omitted"
+
+
+```
## Caveats
diff --git a/yaml-tests.el b/yaml-tests.el
index 1bc0196bf9..3b0c3fd8dd 100644
--- a/yaml-tests.el
+++ b/yaml-tests.el
@@ -456,6 +456,57 @@ keep: |+
# beep" :object-type 'alist)))
+(defun yaml-test-round-trip (o)
+ "Test (equal (decode (encode o)) o)"
+ (let* ((encoded (yaml-encode o))
+ (parsed (yaml-parse-string encoded
+ :object-type 'alist
+ :sequence-type 'list))
+ (encoded-2 (yaml-encode o)))
+ (equal encoded encoded-2)))
+
+(ert-deftest yaml-encode-tests ()
+ (should (yaml-test-round-trip 1))
+ (should (yaml-test-round-trip "one"))
+ (should (yaml-test-round-trip nil))
+ (should (yaml-test-round-trip '(1 2 3)))
+ (should (yaml-test-round-trip '((1 . 2) (3 . 4) (5 . 6))))
+ (should (yaml-test-round-trip
+ '(("key" . "value")
+ ("nested-map" . ((1 . 2) (3 . 4) (5 . 6))))))
+ (should (yaml-test-round-trip
+ '("one"
+ (("key" . "value")
+ ("nested-map" . ((1 . 2) (3 . 4) (5 . 6))))
+ "three")))
+ (should (yaml-test-round-trip
+ '("one"
+ (("key" . "value")
+ ("nested-map" . ((1 . 2) (3 . 4) (5 . 6))))
+ "three")))
+ (should (yaml-test-round-trip
+ '("one"
+ (("key" . "value")
+ ("nested-map" . ((1 . 2) (3 . 4) (5 . 6))))
+ ("nested" "list" 1 2 3))))
+ (should (yaml-test-round-trip
+ '("one"
+ (("key" . "value")
+ ("nested-map" . ((1 . 2) (3 . 4) (5 . 6)))
+ ("nested-list" . (1 2 3 4 5)))
+ ("nested" "list" 1 2 3))))
+ (should (yaml-test-round-trip
+ '("one"
+ (("key" . "value")
+ ("nested-map" . ((1 . 2) (3 . 4) (5 . 6)))
+ ("nested-list" . (1 2 3 4 5)))
+ ("nested" "list" 1 2 3))))
+ (should (yaml-test-round-trip
+ '(t nil)))
+ (should (yaml-encode
+ '((("aaaa" "bbbb" "cccc") ("dddd" "eeee" "ffff") ("gggg" "hhhh"
"iiii"))
+ ("jjjj" "kkkk" "llll") ("mmmm" "nnnn" "oooo") ("pppp" "qqqq"
"rrrr")))))
+
(provide 'yaml-tests)
;; yaml-tests.el ends here
diff --git a/yaml.el b/yaml.el
index 19a78fd27e..1184cadf67 100644
--- a/yaml.el
+++ b/yaml.el
@@ -30,11 +30,14 @@
;; yaml.el contains the code for parsing YAML natively in Elisp with
;; no dependencies. The main function to parse YAML provided is
-;; `yaml-parse-string'. The following are some examples of its usage:
+;; `yaml-parse-string'. `yaml-encode' is also provided to encode a
+;; Lisp object to YAML. The following are some examples of its usage:
;;
;; (yaml-parse-string "key1: value1\nkey2: value2")
;; (yaml-parse-string "key1: value1\nkey2: value2" :object-type 'alist)
;; (yaml-parse-string "numbers: [1, 2, 3]" :sequence-type 'list)
+;;
+;; (yaml-encode '((count . 3) (value . 10) (items ("ruby" "diamond"))))
;;; Code:
@@ -2338,6 +2341,131 @@ Rules for this function are defined by the yaml-spec
JSON file."
(yaml--parse-from-grammar 'ns-plain n c))))
(_ (error "Unknown parsing grammar state: %s %s" state args))))
+;;; Encoding
+
+(defun yaml-encode (object)
+ "Encode OBJECT to a YAML string."
+ (with-temp-buffer
+ (yaml--encode-object object 0)
+ (buffer-string)))
+
+(defun yaml--encode-object (object indent &optional auto-indent)
+ "Encode a Lisp OBJECT to YAML.
+
+INDENT indicates how deeply nested the object will be displayed
+in the YAML. If AUTO-INDENT is non-nil, then emit the object
+without first inserting a newline."
+ (cond
+ ((yaml--scalarp object) (yaml--encode-scalar object))
+ ((hash-table-p object) (yaml--encode-hash-table object indent auto-indent))
+ ((listp object) (yaml--encode-list object indent auto-indent))
+ (t (error "Unknown object %s" object))))
+
+(defun yaml--scalarp (object)
+ "Return non-nil if OBJECT correlates to a YAML scalar."
+ (or (numberp object)
+ (symbolp object)
+ (stringp object)
+ (not object)))
+
+(defun yaml--encode-escape-string (s)
+ "Escape yaml special characters in string S."
+ (let* ((s (replace-regexp-in-string "\\\\" "\\\\" s))
+ (s (replace-regexp-in-string "\n" "\\\\n" s))
+ (s (replace-regexp-in-string "\t" "\\\\t" s))
+ (s (replace-regexp-in-string "\r" "\\\\r" s))
+ (s (replace-regexp-in-string "\"" "\\\\\"" s)))
+ s))
+
+
+
+(defun yaml--encode-scalar (s)
+ "Encode scalar S to buffer."
+ (cond
+ ((not s) (insert "nil"))
+ ((eql t s) (insert "true"))
+ ((symbolp s) (insert (symbol-name s)))
+ ((numberp s) (insert (number-to-string s)))
+ ((stringp s)
+ (if (string-match "\\`[-_a-zA-Z0-9]+\\'" s)
+ (insert s)
+ (insert "\"" (yaml--encode-escape-string s) "\"")))))
+
+(defun yaml--alist-to-hash-table (l)
+ "Return hash representation of L if it is an alist, nil otherwise."
+ (when (and (listp l) (seq-every-p (lambda (x) (and (consp x) (atom (car
x)))) l))
+ (let ((h (make-hash-table)))
+ (seq-map (lambda (cpair)
+ (let ((k (car cpair))
+ (v (cdr cpair)))
+ (puthash k v h)))
+ l)
+ h)))
+
+(defun yaml--encode-list (l indent &optional auto-indent)
+ "Encode list L to a string in the context of being INDENT deep.
+
+If AUTO-INDENT is non-nil, start the list on the current line,
+auto-detecting the indentation"
+ (let ((ht (yaml--alist-to-hash-table l)))
+ (cond (ht
+ (yaml--encode-hash-table ht indent auto-indent))
+ ((zerop (length l))
+ (insert "[]"))
+ ((seq-every-p #'yaml--scalarp l)
+ (insert "[")
+ (yaml--encode-object (car l) 0)
+ (seq-do (lambda (object)
+ (insert ", ")
+ (yaml--encode-object object 0))
+ (cdr l))
+ (insert "]"))
+ (t
+ (let ((first t)
+ (indent-string (make-string (* 2 indent) ?\s)))
+ (seq-do (lambda (object)
+ (if (not first)
+ (insert "\n" indent-string "- ")
+ (if auto-indent
+ (let ((curr-indent
(yaml--encode-auto-detect-indent)))
+ (insert (make-string (- indent curr-indent)
?\s) "- "))
+ (insert "\n" indent-string "- "))
+ (setq first nil))
+ (yaml--encode-object object (+ indent 2)
+ (or
+ (hash-table-p object)
+ (yaml--alist-to-hash-table
object))))
+ l))))))
+
+(defun yaml--encode-auto-detect-indent ()
+ "Return the amount of indentation at current place in encoding."
+ (length (thing-at-point 'line)))
+
+(defun yaml--encode-hash-table (m indent &optional auto-indent)
+ "Encode hash table M to a string in the context of being INDENT deep.
+
+If AUTO-INDENT is non-nil, auto-detect the indent on the current
+line and insert accordingly."
+ (cond ((zerop (hash-table-size m))
+ (insert "{}"))
+ (t
+ (let ((first t)
+ (indent-string (make-string indent ?\s)))
+ (maphash (lambda (k v)
+ (if (not first)
+ (insert "\n" indent-string)
+ (if auto-indent
+ (let ((curr-indent
(yaml--encode-auto-detect-indent)))
+ (when (> curr-indent indent)
+ (setq indent (+ curr-indent 1)))
+ (insert (make-string (- indent curr-indent)
?\s)))
+ (insert "\n" indent-string))
+ (setq first nil))
+ (yaml--encode-object k indent nil)
+ (insert ": ")
+ (yaml--encode-object v (+ indent 2)))
+ m)))))
+
(provide 'yaml)
;;; yaml.el ends here
- [elpa] externals/yaml ada133f0b1 036/124: Fix regexp to match end of string, (continued)
- [elpa] externals/yaml ada133f0b1 036/124: Fix regexp to match end of string, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 9170ff5cf8 038/124: Add LICENSE; Add documentation, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 1fb0519023 039/124: Fix static check warnings, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml fbf28ffb1d 041/124: Add yaml-spec-1.2.json file, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml d8f676b54d 037/124: Add require for cl-lib, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml a90fc1580c 045/124: Update commentary file, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 79a6bbc1e1 040/124: Fix various parsing bugs; reduce stack usage of parsing strings, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 367f470203 029/124: Add github action file, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml a45f60c999 051/124: Merge pull request #8 from zkry/symbol-keys, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 10af746dad 050/124: Add option to convert string keys to symbols, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 96d3e51aeb 048/124: Add yaml-encode feature,
ELPA Syncer <=
- [elpa] externals/yaml 51023c4551 049/124: Merge pull request #7 from zkry/add-yaml-encode, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 8903b6c7e4 055/124: return plist key as a keyword as a default, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml ed108ab526 084/124: add option for skipping processing of scalars, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml a2ed8f1fd6 072/124: Fix empty single quote string bug, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 419e85fbce 094/124: fix folding block parsing error, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 0bf6a1b686 088/124: YAML anchor should match exactly how it was defined, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 2aa5a6faf7 056/124: Merge pull request #16 from conao3/indent, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml 5b352258f5 067/124: Merge pull request #24 from j-shilling/fix-alist-to-hash, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml d0abc17e3d 060/124: Merge pull request #18 from conao3/alist-symbol, ELPA Syncer, 2024/11/29
- [elpa] externals/yaml e32ef2f5e5 092/124: add note to yaml-parse-string-with-pos function, ELPA Syncer, 2024/11/29