From 53dd34c2f7928f3037c744b13c3293c724433caa Mon Sep 17 00:00:00 2001 From: Martin Kavalar Date: Mon, 13 Jun 2022 10:40:31 +0200 Subject: [PATCH] Preserve *ns* during analysis and eval --- resources/viewer-js-hash | 2 +- src/nextjournal/clerk.clj | 13 ++++---- src/nextjournal/clerk/hashing.clj | 44 +++++++++++++------------ src/nextjournal/clerk/webserver.clj | 5 +-- test/nextjournal/clerk/hashing_test.clj | 25 +++++++++----- test/nextjournal/clerk_test.clj | 1 + 6 files changed, 51 insertions(+), 39 deletions(-) diff --git a/resources/viewer-js-hash b/resources/viewer-js-hash index 6f38441c3..b4c158db8 100644 --- a/resources/viewer-js-hash +++ b/resources/viewer-js-hash @@ -1 +1 @@ -MZAFz7cCjz5iXe9gpb2mNybfmhh \ No newline at end of file +2QomkaERveEgZwKtSGc6f95nabbt \ No newline at end of file diff --git a/src/nextjournal/clerk.clj b/src/nextjournal/clerk.clj index 05d10a041..d7973610a 100644 --- a/src/nextjournal/clerk.clj +++ b/src/nextjournal/clerk.clj @@ -81,7 +81,7 @@ (try (let [value (let [cached-value (thaw-from-cas cas-hash)] (when introduced-var - (intern *ns* (-> introduced-var symbol name symbol) cached-value)) + (intern (-> introduced-var symbol namespace find-ns) (-> introduced-var symbol name symbol) cached-value)) cached-value)] (wrapped-with-metadata (if introduced-var (var-from-def introduced-var) value) visibility hash)) (catch Exception _e @@ -189,10 +189,11 @@ (defn +eval-results [results-last-run parsed-doc] - (let [analyzed-doc (hashing/build-graph parsed-doc)] - (-> analyzed-doc - (assoc :blob->result results-last-run :->hash (hashing/hash analyzed-doc) :ns *ns*) - eval-analyzed-doc))) + (let [{:as analyzed-doc :keys [ns]} (hashing/build-graph parsed-doc)] + (binding [*ns* ns] + (-> analyzed-doc + (assoc :blob->result results-last-run :->hash (hashing/hash analyzed-doc)) + eval-analyzed-doc)))) (defn parse-file [file] (hashing/parse-file {:doc? true} file)) @@ -495,7 +496,7 @@ _ (report-fn {:stage :init :state state}) {state :result duration :time-ms} (time-ms (mapv (comp parse-file :file) state)) _ (report-fn {:stage :parsed :state state :duration duration}) - {state :result duration :time-ms} (time-ms (mapv (comp (fn [doc] (assoc doc :->hash (hashing/hash doc) :ns *ns*)) + {state :result duration :time-ms} (time-ms (mapv (comp (fn [doc] (assoc doc :->hash (hashing/hash doc))) hashing/build-graph) state)) _ (report-fn {:stage :analyzed :state state :duration duration}) state (mapv (fn [doc] diff --git a/src/nextjournal/clerk/hashing.clj b/src/nextjournal/clerk/hashing.clj index 68f4830e1..c5725836f 100644 --- a/src/nextjournal/clerk/hashing.clj +++ b/src/nextjournal/clerk/hashing.clj @@ -328,27 +328,29 @@ ([doc] (analyze-doc {:doc? true :graph (dep/graph)} doc)) ([{:as state :keys [doc?]} doc] - (reduce (fn [state i] - (let [{:keys [type text]} (get-in state [:blocks i])] - (if (not= type :code) - state - (let [form (read-string text) - {:as analyzed :keys [vars deps ns-effect?]} (cond-> (analyze form) - (:file doc) (assoc :file (:file doc))) - state (cond-> (reduce (fn [state ana-key] - (assoc-in state [:->analysis-info ana-key] analyzed)) - (dissoc state :doc?) - (->ana-keys analyzed)) - doc? (update-in [:blocks i] merge (dissoc analyzed :deps :no-cache? :ns-effect?)))] - (when ns-effect? - (eval form)) - (if (seq deps) - (-> (reduce (partial analyze-deps analyzed) state deps) - (make-deps-inherit-no-cache analyzed)) - state))))) - (cond-> state - doc? (merge doc)) - (-> doc :blocks count range)))) + (binding [*ns* *ns*] + (reduce (fn [state i] + (let [{:keys [type text]} (get-in state [:blocks i])] + (if (not= type :code) + state + (let [form (read-string text) + {:as analyzed :keys [vars deps ns-effect?]} (cond-> (analyze form) + (:file doc) (assoc :file (:file doc))) + state (cond-> (reduce (fn [state ana-key] + (assoc-in state [:->analysis-info ana-key] analyzed)) + (dissoc state :doc?) + (->ana-keys analyzed)) + doc? (update-in [:blocks i] merge (dissoc analyzed :deps :no-cache? :ns-effect?)) + doc? (assoc :ns *ns*))] + (when ns-effect? + (eval form)) + (if (seq deps) + (-> (reduce (partial analyze-deps analyzed) state deps) + (make-deps-inherit-no-cache analyzed)) + state))))) + (cond-> state + doc? (merge doc)) + (-> doc :blocks count range))))) #_(let [doc (parse-clojure-string {:doc? true} "(ns foo) (def a 41) (def b (inc a)) (do (def c 4) (def d (inc a)))")] (analyze-doc doc)) diff --git a/src/nextjournal/clerk/webserver.clj b/src/nextjournal/clerk/webserver.clj index faa661be7..c56ced007 100644 --- a/src/nextjournal/clerk/webserver.clj +++ b/src/nextjournal/clerk/webserver.clj @@ -41,8 +41,9 @@ #_(get-pagination-opts "") #_(get-pagination-opts "foo=bar&n=42&start=20") -(defn serve-blob [{:as _doc :keys [blob->result ns]} {:keys [blob-id fetch-opts]}] - (assert ns "namespace must be set") +(defn serve-blob [{:as doc :keys [blob->result ns]} {:keys [blob-id fetch-opts]}] + (when-not ns + (throw (ex-info "namespace must be set" {:doc doc}))) (if (contains? blob->result blob-id) (let [result (v/apply-viewer-unwrapping-var-from-def (blob->result blob-id)) desc (v/present (v/ensure-wrapped-with-viewers diff --git a/test/nextjournal/clerk/hashing_test.clj b/test/nextjournal/clerk/hashing_test.clj index 54d194a2e..22019fb45 100644 --- a/test/nextjournal/clerk/hashing_test.clj +++ b/test/nextjournal/clerk/hashing_test.clj @@ -78,16 +78,18 @@ par one par two")))) (deftest no-cache? - (testing "are variables set to no-cache?" - (is (not (h/no-cache? (h/analyze+emit '(rand-int 10))))) - (is (not (h/no-cache? (h/analyze+emit '(def random-thing (rand-int 1000)))))) - (is (not (h/no-cache? (h/analyze+emit '(defn random-thing [] (rand-int 1000)))))) - (is (h/no-cache? (h/analyze+emit '(def ^:nextjournal.clerk/no-cache random-thing (rand-int 1000))))) - (is (h/no-cache? (h/analyze+emit '(defn ^:nextjournal.clerk/no-cache random-thing [] (rand-int 1000))))) - (is (h/no-cache? (h/analyze+emit '(defn ^{:nextjournal.clerk/no-cache true} random-thing [] (rand-int 1000)))))) + (with-ns-binding 'nextjournal.clerk.hashing-test + (testing "are variables set to no-cache?" + (is (not (h/no-cache? (h/analyze+emit '(rand-int 10))))) + (is (not (h/no-cache? (h/analyze+emit '(def random-thing (rand-int 1000)))))) + (is (not (h/no-cache? (h/analyze+emit '(defn random-thing [] (rand-int 1000)))))) + (is (h/no-cache? (h/analyze+emit '(def ^:nextjournal.clerk/no-cache random-thing (rand-int 1000))))) + (is (h/no-cache? (h/analyze+emit '(defn ^:nextjournal.clerk/no-cache random-thing [] (rand-int 1000))))) + (is (h/no-cache? (h/analyze+emit '(defn ^{:nextjournal.clerk/no-cache true} random-thing [] (rand-int 1000))))))) (testing "is evaluating namespace set to no-cache?" - (is (not (h/no-cache? '(rand-int 10)))) + (with-ns-binding 'nextjournal.clerk.hashing-test + (is (not (h/no-cache? '(rand-int 10))))) (with-ns-binding 'nextjournal.clerk.hashing (is (nextjournal.clerk.hashing/no-cache? '(rand-int 10)))))) @@ -197,7 +199,12 @@ par two")))) :deps set?} #{1 3 2} {:form '#{1 3 2}}}} (analyze-string "^:nextjournal.clerk/no-cache (ns example-notebook) -#{3 1 2}")))) +#{3 1 2}"))) + + (testing "preserves *ns*" + (with-ns-binding 'nextjournal.clerk.hashing-test + (is (= (find-ns 'nextjournal.clerk.hashing-test) + (do (analyze-string "(ns example-notebook)") *ns*)))))) (deftest no-cache-dep (is (match? [{:no-cache? true} {:no-cache? true} {:no-cache? true}] diff --git a/test/nextjournal/clerk_test.clj b/test/nextjournal/clerk_test.clj index 23666bc03..54ed5e6c1 100644 --- a/test/nextjournal/clerk_test.clj +++ b/test/nextjournal/clerk_test.clj @@ -184,3 +184,4 @@ (let [paths (clerk/expand-paths ["notebooks/*clj"])] (is (> (count paths) 25)) (is (every? #(str/ends-with? % ".clj") paths)))) +