From: Joseph Turner via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: Adam Porter <adam.porter@47ap.net>,
63513@debbugs.gnu.org, monnier@iro.umontreal.ca,
phillip.lord@russet.org.uk
Subject: bug#63513: [PATCH] Make persist-defvar work with records and hash tables
Date: Sun, 03 Sep 2023 17:29:22 -0700 [thread overview]
Message-ID: <87a5u2ydzg.fsf@breatheoutbreathe.in> (raw)
In-Reply-To: <83cyyz94c6.fsf@gnu.org>
[-- Attachment #1: Type: text/plain, Size: 366 bytes --]
Eli Zaretskii <eliz@gnu.org> writes:
> Thanks, but this lacks the commit log messages (see CONTRIBUTE).
I have added commit log messages. See attached patches.
> Also, I think the new features warrant a NEWS entry.
Should that go in the NEWS file in the main Emacs repo? I don't see a
NEWS file in either of the main or externals/persist ELPA branches.
Joseph
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-test-persist-save-macro.patch --]
[-- Type: text/x-diff, Size: 3629 bytes --]
From 2ca778a44c10f11059f16ef5922cf1eff9118105 Mon Sep 17 00:00:00 2001
From: Joseph Turner <joseph@breatheoutbreathe.in>
Date: Tue, 23 May 2023 12:57:02 -0700
Subject: [PATCH 1/5] Add test-persist-save macro
* test/persist-tests.el (persist-test-persist-save):
Consolidate logic of test-persist-save and
test-persist-save-non-number.
(test-persist-save-number test-persist-save-string): Simple wrappers
over persist-test-persist-save
---
test/persist-tests.el | 76 +++++++++++++++++++------------------------
1 file changed, 33 insertions(+), 43 deletions(-)
diff --git a/test/persist-tests.el b/test/persist-tests.el
index b6645a9297..f2b04769ef 100644
--- a/test/persist-tests.el
+++ b/test/persist-tests.el
@@ -25,51 +25,41 @@ (ert-deftest test-persist-save-only-persistant ()
:type 'error
:exclude-subtypes t))
-(ert-deftest test-persist-save ()
- (with-local-temp-persist
- (let ((sym (cl-gensym)))
- ;; precondition
- (should-not (file-exists-p (persist--file-location sym)))
- (set sym 10)
- (persist-symbol sym 10)
- (persist-save sym)
- (should t)
- (should-not (file-exists-p (persist--file-location sym)))
- (set sym 20)
- (persist-save sym)
- (should (file-exists-p (persist--file-location sym)))
- (should
- (string-match-p
- "20"
- (with-temp-buffer
- (insert-file-contents (persist--file-location sym))
- (buffer-string))))
- (set sym 10)
- (persist-save sym)
- (should-not (file-exists-p (persist--file-location sym)))
- (should-error
- (persist-save 'fred)))))
+(defmacro persist-test-persist-save (init default change printed-changed)
+ "Test persisting symbols.
+- symbol is not persisted when value is set to INIT and default
+ value is set to DEFAULT.
+- symbol is persisted when value is changed according to CHANGE.
+- persisted file contents match PRINTED-CHANGED.
+- symbol is not persisted after value is set back to DEFAULT."
+ `(with-local-temp-persist
+ (let ((sym (cl-gensym)))
+ (should-not (file-exists-p (persist--file-location sym)))
+ (set sym ,init)
+ (persist-symbol sym ,default)
+ (persist-save sym)
+ (should t)
+ (should-not (file-exists-p (persist--file-location sym)))
+ ,change
+ (persist-save sym)
+ (should (file-exists-p (persist--file-location sym)))
+ (should
+ (string-match-p
+ ,printed-changed
+ (with-temp-buffer
+ (insert-file-contents (persist--file-location sym))
+ (buffer-string))))
+ (set sym ,default)
+ (persist-save sym)
+ (should-not (file-exists-p (persist--file-location sym))))))
-(ert-deftest test-persist-save-non-number ()
- "Test saving something that is not a number.
+(ert-deftest test-persist-save-number ()
+ "Test saving number."
+ (persist-test-persist-save 1 1 (set sym 2) "2"))
-`test-persist-save' missed "
- (with-local-temp-persist
- (let ((sym (cl-gensym)))
- (set sym "fred")
- (persist-symbol sym "fred")
- (persist-save sym)
- (should t)
- (should-not (file-exists-p (persist--file-location sym)))
- (set sym "george")
- (persist-save sym)
- (should (file-exists-p (persist--file-location sym)))
- (should
- (string-match-p
- "george"
- (with-temp-buffer
- (insert-file-contents (persist--file-location sym))
- (buffer-string)))))))
+(ert-deftest test-persist-save-string ()
+ "Test saving string."
+ (persist-test-persist-save "foo" "foo" (set sym "bar") "bar"))
(ert-deftest test-persist-load ()
(with-local-temp-persist
--
2.41.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Add-persist-equal.patch --]
[-- Type: text/x-diff, Size: 1394 bytes --]
From b379d8d1779e0190541ef7f8adf39dfe4d4c551a Mon Sep 17 00:00:00 2001
From: Joseph Turner <joseph@breatheoutbreathe.in>
Date: Sat, 2 Sep 2023 16:52:31 -0700
Subject: [PATCH 2/5] Add persist-equal
* persist.el (persist-hash-equal): Like equal, but compares hash
tables also.
See bug#63671 for a discussion of built-in hash table comparison.
---
persist.el | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/persist.el b/persist.el
index d80943d19e..a707d038cd 100644
--- a/persist.el
+++ b/persist.el
@@ -187,5 +187,25 @@ (defun persist--save-all ()
(add-hook 'kill-emacs-hook
'persist--save-all)
+(defun persist-equal (a b)
+ "Return non-nil when the values of A and B are equal.
+A and B are compared using `equal' unless they are both hash
+tables. In that case, the following are compared:
+
+- hash table count
+- hash table predicate
+- values, using `persist-equal'"
+ (if (and (hash-table-p a) (hash-table-p b))
+ (and (= (hash-table-count a) (hash-table-count b))
+ (eq (hash-table-test a) (hash-table-test b))
+ (catch 'done
+ (maphash
+ (lambda (key a-value)
+ (unless (persist-equal a-value (gethash key b (not a-value)))
+ (throw 'done nil)))
+ a)
+ t))
+ (equal a b)))
+
(provide 'persist)
;;; persist.el ends here
--
2.41.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-Make-persist-defvar-work-with-hash-tables.patch --]
[-- Type: text/x-diff, Size: 2645 bytes --]
From 11194569423dcdf8778a55f59dbca8f49e8b7b37 Mon Sep 17 00:00:00 2001
From: Joseph Turner <joseph@breatheoutbreathe.in>
Date: Sun, 3 Sep 2023 17:10:38 -0700
Subject: [PATCH 3/5] Make persist-defvar work with hash tables
Previously, when persist-defvar received a hash table for an initial
value, updated values were not persisted.
* persist.el (persist-symbol): Use hash table copy as default so that
the original table can be modified without modifying the default value.
(persist-save): Use persist-equal to ensure that hash tables are
correctly compared
* test/persist-tests.el (test-persist-save-hash): Test hash tables
persistence.
---
persist.el | 8 +++++---
test/persist-tests.el | 8 ++++++++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/persist.el b/persist.el
index a707d038cd..7b2ab491d7 100644
--- a/persist.el
+++ b/persist.el
@@ -118,7 +118,9 @@ (defun persist-symbol (symbol &optional initvalue)
(let ((initvalue (or initvalue (symbol-value symbol))))
(add-to-list 'persist--symbols symbol)
(put symbol 'persist t)
- (put symbol 'persist-default initvalue)))
+ (if (hash-table-p initvalue)
+ (put symbol 'persist-default (copy-hash-table initvalue))
+ (put symbol 'persist-default initvalue))))
(defun persist--persistant-p (symbol)
"Return non-nil if SYMBOL is a persistant variable."
@@ -133,8 +135,8 @@ (defun persist-save (symbol)
(error (format
"Symbol %s is not persistant" symbol)))
(let ((symbol-file-loc (persist--file-location symbol)))
- (if (equal (symbol-value symbol)
- (persist-default symbol))
+ (if (persist-equal (symbol-value symbol)
+ (persist-default symbol))
(when (file-exists-p symbol-file-loc)
(delete-file symbol-file-loc))
(let ((dir-loc
diff --git a/test/persist-tests.el b/test/persist-tests.el
index f2b04769ef..90adf1c6d6 100644
--- a/test/persist-tests.el
+++ b/test/persist-tests.el
@@ -61,6 +61,14 @@ (ert-deftest test-persist-save-string ()
"Test saving string."
(persist-test-persist-save "foo" "foo" (set sym "bar") "bar"))
+(ert-deftest test-persist-save-hash ()
+ "Test saving hash table."
+ (let* ((hash (make-hash-table))
+ (default (copy-hash-table hash)))
+ (persist-test-persist-save hash default
+ (puthash 'foo "bar" (symbol-value sym))
+ "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))")))
+
(ert-deftest test-persist-load ()
(with-local-temp-persist
(let ((sym (cl-gensym)))
--
2.41.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-Add-persist-copy-tree.patch --]
[-- Type: text/x-diff, Size: 1983 bytes --]
From f360f7ae53125a847c2a8d5762ca5f08d16445b9 Mon Sep 17 00:00:00 2001
From: Joseph Turner <joseph@breatheoutbreathe.in>
Date: Tue, 23 May 2023 13:43:02 -0700
Subject: [PATCH 4/5] Add persist-copy-tree
The behavior of copy-tree was changed in Emacs 30. This function will
ensure that persist works correctly for previous Emacs versions.
* persist.el (persist-copy-tree): Add copy-tree, so that records can
be compared.
---
persist.el | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/persist.el b/persist.el
index 7b2ab491d7..93444995f2 100644
--- a/persist.el
+++ b/persist.el
@@ -209,5 +209,33 @@ (defun persist-equal (a b)
t))
(equal a b)))
+(defun persist-copy-tree (tree &optional vectors-and-records)
+ "Make a copy of TREE.
+If TREE is a cons cell, this recursively copies both its car and its cdr.
+Contrast to `copy-sequence', which copies only along the cdrs.
+With the second argument VECTORS-AND-RECORDS non-nil, this
+traverses and copies vectors and records as well as conses."
+ (declare (side-effect-free error-free))
+ (if (consp tree)
+ (let (result)
+ (while (consp tree)
+ (let ((newcar (car tree)))
+ (if (or (consp (car tree))
+ (and vectors-and-records
+ (or (vectorp (car tree)) (recordp (car tree)))))
+ (setq newcar (persist-copy-tree (car tree) vectors-and-records)))
+ (push newcar result))
+ (setq tree (cdr tree)))
+ (nconc (nreverse result)
+ (if (and vectors-and-records (or (vectorp tree) (recordp tree)))
+ (persist-copy-tree tree vectors-and-records)
+ tree)))
+ (if (and vectors-and-records (or (vectorp tree) (recordp tree)))
+ (let ((i (length (setq tree (copy-sequence tree)))))
+ (while (>= (setq i (1- i)) 0)
+ (aset tree i (persist-copy-tree (aref tree i) vectors-and-records)))
+ tree)
+ tree)))
+
(provide 'persist)
;;; persist.el ends here
--
2.41.0
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0005-Make-persist-defvar-work-with-records.patch --]
[-- Type: text/x-diff, Size: 2019 bytes --]
From ea57e6205b10678b9c26f7dcf3704e2a7acb25a7 Mon Sep 17 00:00:00 2001
From: Joseph Turner <joseph@breatheoutbreathe.in>
Date: Tue, 23 May 2023 13:44:40 -0700
Subject: [PATCH 5/5] Make persist-defvar work with records
Previously, when persist-defvar received a record for an initial
value, updated values were not persisted.
* persist.el (persist-symbol): Set default to a copy of initvalue so
when initvalue is a record, the original can be modified without
modifying the default.
* test/persist-tests.el: Test persist-save with a record.
---
persist.el | 2 +-
test/persist-tests.el | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/persist.el b/persist.el
index 93444995f2..e43171459e 100644
--- a/persist.el
+++ b/persist.el
@@ -120,7 +120,7 @@ (defun persist-symbol (symbol &optional initvalue)
(put symbol 'persist t)
(if (hash-table-p initvalue)
(put symbol 'persist-default (copy-hash-table initvalue))
- (put symbol 'persist-default initvalue))))
+ (put symbol 'persist-default (persist-copy-tree initvalue t)))))
(defun persist--persistant-p (symbol)
"Return non-nil if SYMBOL is a persistant variable."
diff --git a/test/persist-tests.el b/test/persist-tests.el
index 90adf1c6d6..62d8501493 100644
--- a/test/persist-tests.el
+++ b/test/persist-tests.el
@@ -69,6 +69,14 @@ (ert-deftest test-persist-save-hash ()
(puthash 'foo "bar" (symbol-value sym))
"#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))")))
+(ert-deftest test-persist-save-record ()
+ "Test saving record."
+ (let* ((rec (record 'foo 'a 'b))
+ (default (copy-sequence rec)))
+ (persist-test-persist-save rec default
+ (setf (aref (symbol-value sym) 2) 'quux)
+ "#s(foo a quux)")))
+
(ert-deftest test-persist-load ()
(with-local-temp-persist
(let ((sym (cl-gensym)))
--
2.41.0
next prev parent reply other threads:[~2023-09-04 0:29 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-08 8:41 Comparing hash table objects Ihor Radchenko
2022-06-08 8:51 ` Andreas Schwab
2022-06-08 9:17 ` Ihor Radchenko
2022-06-10 22:45 ` Richard Stallman
2022-06-11 5:52 ` Ihor Radchenko
2022-06-11 16:04 ` Stefan Monnier
2022-06-12 9:16 ` Ihor Radchenko
2022-06-12 23:55 ` Sam Steingold
2022-06-13 13:02 ` Stefan Monnier
2022-06-13 16:18 ` Sam Steingold
2023-05-15 5:56 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-05-15 11:31 ` Eli Zaretskii
2023-05-23 20:14 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-02 23:54 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-03 6:08 ` Eli Zaretskii
2023-09-04 0:29 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2023-09-04 11:33 ` Eli Zaretskii
2023-09-04 15:57 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-04 17:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-04 22:28 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-05 21:06 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-08 11:30 ` Ihor Radchenko
2023-09-08 11:58 ` Eli Zaretskii
2023-09-08 12:06 ` Ihor Radchenko
2023-09-08 12:46 ` Eli Zaretskii
2023-09-08 12:51 ` Ihor Radchenko
2023-09-08 16:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-08 17:06 ` Ihor Radchenko
2023-09-08 17:10 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-09 10:01 ` Ihor Radchenko
2023-09-09 10:15 ` Daniel Mendler
2023-09-09 11:35 ` Ihor Radchenko
2023-09-09 11:57 ` Daniel Mendler
2023-09-09 12:12 ` compat.el and Emacs unstable master branch features (was: bug#63513: [PATCH] Make persist-defvar work with records and hash tables) Ihor Radchenko
2023-09-09 12:29 ` Daniel Mendler
2023-09-09 16:52 ` Joseph Turner
2023-09-11 8:45 ` Ihor Radchenko
2023-09-12 10:02 ` compat.el and Emacs unstable master branch features Philip Kaludercic
2023-09-12 10:27 ` Daniel Mendler
2023-09-13 10:31 ` Philip Kaludercic
2023-09-13 17:11 ` Daniel Mendler
2023-10-15 8:43 ` Ihor Radchenko
2023-10-15 12:09 ` Philip Kaludercic
2023-09-05 15:08 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables phillip.lord
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87a5u2ydzg.fsf@breatheoutbreathe.in \
--to=bug-gnu-emacs@gnu.org \
--cc=63513@debbugs.gnu.org \
--cc=adam.porter@47ap.net \
--cc=eliz@gnu.org \
--cc=joseph@breatheoutbreathe.in \
--cc=monnier@iro.umontreal.ca \
--cc=phillip.lord@russet.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.