branch: elpa/extmap
commit 02f1dfeab15e3691eac37561ea2cd93e3b590c9d
Author: Paul Pogonyshev <pogonys...@gmail.com>
Commit: Paul Pogonyshev <pogonys...@gmail.com>

    Make `extmap-init' lazy by default in that it won't even preload extmap 
metadata.
---
 extmap.el           | 63 ++++++++++++++++++++++++++++++++++-------------------
 test/extmap-test.el | 41 ++++++++++++++++++++++++----------
 2 files changed, 71 insertions(+), 33 deletions(-)

diff --git a/extmap.el b/extmap.el
index 5e92cacbd3..20a3f5e241 100644
--- a/extmap.el
+++ b/extmap.el
@@ -113,11 +113,50 @@ OPTIONS can be a list of the following keyword arguments:
     developing, when you'd often re-generate disk files, though
     nothing precludes using it in end-code either.
 
+  :preload-metadata
+
+    Immediately parse the header of the extmap file.  Otherwise
+    this is done lazily, on first access.  For consistency, it is
+    still an error if FILENAME points to an unreadable file.
+
 The file must remain accessible in case `extmap-get' needs to
 load a value later.  There is no need to somehow close a map:
 just stop using it."
+  (let ((extmap (list (cons filename (if (plist-get options :auto-reload) 
:auto-reload :not-initialized))
+                      nil (when (plist-get options :weak-data) 
(make-hash-table :test #'eq :weakness 'value)))))
+    (if (plist-get options :preload-metadata)
+        (extmap--do-reload-if-needed extmap)
+      ;; Still check that `filename' exists and is readable.
+      (unless (file-regular-p filename)
+        (signal 'file-error (list "Not a regular file" filename))))
+    extmap))
+
+;; After a call to this, any value in `extmap' other than the filename
+;; might change.
+(defsubst extmap--reload-if-needed (extmap)
+  (let ((modtime (cdr (nth 0 extmap))))
+    (when modtime
+      (extmap--do-reload-if-needed extmap))))
+
+(defun extmap--do-reload-if-needed (extmap)
+  (let* ((filename     (car (nth 0 extmap)))
+         (modtime-then (cdr (nth 0 extmap)))
+         ;; Fifth element of `file-attributes' result is the modification date.
+         ;; `file-attribute-modification-time' doesn't exist in Emacs 25.
+         (modtime-now  (nth 5 (file-attributes filename))))
+    (cond ((keywordp modtime-then)
+           ;; Means the map has not been initialized yet.
+           (progn (extmap--do-initialize extmap)
+                  (setf (cdr (nth 0 extmap)) (when (eq modtime-then 
:auto-reload) modtime-now))))
+          ((not (equal modtime-now modtime-then))
+           (let ((reloaded-extmap (extmap-init filename :auto-reload t 
:weak-data (nth 2 extmap) :preload-metadata t)))
+             (setf (car extmap) (car reloaded-extmap))
+             (setf (cdr extmap) (cdr reloaded-extmap)))))))
+
+(defun extmap--do-initialize (extmap)
   (with-temp-buffer
-    (let* ((header-length            (bindat-length extmap--header-bindat-spec 
    nil))
+    (let* ((filename                 (car (nth 0 extmap)))
+           (header-length            (bindat-length extmap--header-bindat-spec 
    nil))
            (item-short-header-length (bindat-length 
extmap--item-short-bindat-spec nil))
            (item-header-length       (bindat-length extmap--item-bindat-spec   
    nil))
            (read-as                  (insert-file-contents-literally filename 
nil 0 header-length))
@@ -152,27 +191,7 @@ just stop using it."
                   (unless (= type 0)
                     (error "Corrupted extmap file")))
                 (puthash key (cons t value) items))))))
-      ;; Fifth element of `file-attributes' result is the modification date.
-      ;; `file-attribute-modification-time' doesn't exist in Emacs 25.
-      (list (cons filename (when (plist-get options :auto-reload) (nth 5 
(file-attributes filename))))
-            items (when (plist-get options :weak-data) (make-hash-table :test 
#'eq :weakness 'value))))))
-
-;; After a call to this, any value in `extmap' other than the filename
-;; might change.
-(defsubst extmap--reload-if-needed (extmap)
-  (let ((modtime (cdr (nth 0 extmap))))
-    (when modtime
-      (extmap--do-reload-if-needed extmap))))
-
-(defun extmap--do-reload-if-needed (extmap)
-  (let ((filename (car (nth 0 extmap)))
-        (modtime  (cdr (nth 0 extmap))))
-    ;; Fifth element of `file-attributes' result is the modification date.
-    ;; `file-attribute-modification-time' doesn't exist in Emacs 25.
-    (unless (equal (nth 5 (file-attributes filename)) modtime)
-      (let ((reloaded-extmap (extmap-init filename :auto-reload t :weak-data 
(nth 2 extmap))))
-        (setcar extmap (car reloaded-extmap))
-        (setcdr extmap (cdr reloaded-extmap))))))
+      (setf (nth 1 extmap) items))))
 
 
 (defun extmap-get (extmap key &optional no-error)
diff --git a/test/extmap-test.el b/test/extmap-test.el
index e30f69b975..14cf427b67 100644
--- a/test/extmap-test.el
+++ b/test/extmap-test.el
@@ -22,23 +22,35 @@
 
 (defconst extmap--test-directory (file-name-directory (or load-file-name 
(buffer-file-name))))
 
-(defvar extmap--test-filename nil)
+(defun extmap--test-file (&optional filename)
+  (expand-file-name (or filename "test.extmap") extmap--test-directory))
 
 
 (defun extmap--test-alist (data &rest options)
-  (let ((filename (concat extmap--test-directory (or extmap--test-filename 
"test.extmap"))))
+  (let ((filename (extmap--test-file))
+        extmap)
     (apply #'extmap-from-alist filename data :overwrite t options)
-    (let ((extmap (extmap-init filename)))
-      (should (equal (sort (mapcar #'car data) #'string<) (sort (extmap-keys 
extmap) #'string<)))
-      (dolist (entry data)
-        (should (extmap-contains-key extmap (car entry)))
-        (should (extmap--equal-including-properties (extmap-get extmap (car 
entry)) (cdr entry)))
-        (should (extmap-value-loaded extmap (car entry))))
-      extmap)))
+    ;; By default, test both without and with preloading metadata.
+    (dolist (preload-metadata (or (plist-get options :preload-metadata) '(nil 
t)))
+      (setq extmap (extmap--do-test-alist filename data preload-metadata)))
+    extmap))
+
+(defun extmap--do-test-alist (filename data preload-metadata)
+  (let ((extmap (extmap-init filename :preload-metadata preload-metadata)))
+    ;; It's fine to access internals in our own tests.
+    (if preload-metadata
+        (should (hash-table-p (nth 1 extmap)))
+      (should (null (nth 1 extmap))))
+    (should (equal (sort (mapcar #'car data) #'string<) (sort (extmap-keys 
extmap) #'string<)))
+    (dolist (entry data)
+      (should (extmap-contains-key extmap (car entry)))
+      (should (extmap--equal-including-properties (extmap-get extmap (car 
entry)) (cdr entry)))
+      (should (extmap-value-loaded extmap (car entry))))
+    extmap))
 
 (defun extmap--test-compare (data1 data2 &optional keys-to-ignore &rest 
options)
-  (let* ((filename1 (concat extmap--test-directory (or extmap--test-filename 
"test1.extmap")))
-         (filename2 (concat extmap--test-directory (or extmap--test-filename 
"test2.extmap"))))
+  (let* ((filename1 (extmap--test-file "test1.extmap"))
+         (filename2 (extmap--test-file "test2.extmap")))
     (apply #'extmap-from-alist filename1 data1 :overwrite t options)
     (apply #'extmap-from-alist filename2 data2 :overwrite t options)
     (extmap-equal-p filename1 filename2 keys-to-ignore)))
@@ -102,6 +114,13 @@
     (should     (eq (nth 0 foo) (nth 1 foo)))))
 
 
+(ert-deftest extmap-init-signals-for-non-existing-file ()
+  (should-error (extmap-init (extmap--test-file 
"this-file-shouldnt-exist-or-test-will-fail.extmap"))
+                :type 'file-error)
+  (should-error (extmap-init (extmap--test-file 
"this-file-shouldnt-exist-or-test-will-fail.extmap") :preload-metadata t)
+                :type 'file-error))
+
+
 (ert-deftest extmap-equal-p-1 ()
   (should (extmap--test-compare `((foo  . 1))
                                 `((foo  . 1))))

Reply via email to