我想知道是否可以將包含在Clojure .clj
源文件中的代碼作爲列表加載,而無需編譯它。修改clojure中的Clojure源代碼文件
如果我可以加載一個.clj
文件作爲列表,我可以修改該列表並將其打印回相同的文件,然後再次加載。
(也許這是一個壞主意。)有誰知道這是可能的嗎?
我想知道是否可以將包含在Clojure .clj
源文件中的代碼作爲列表加載,而無需編譯它。修改clojure中的Clojure源代碼文件
如果我可以加載一個.clj
文件作爲列表,我可以修改該列表並將其打印回相同的文件,然後再次加載。
(也許這是一個壞主意。)有誰知道這是可能的嗎?
稍微簡單的例子:
user=> (def a '(println (+ 1 1))) ; "'" escapes the form to prevent immediate evaluation
#'user/a
user=> (spit "test.code" a) ; write it to a file
nil
user=> (def from-file (read-string (slurp "test.code"))) ; read it from a file
#'user/from-file
user=> (def modified (clojure.walk/postwalk-replace {1 2} from-file)) ; modify the code
#'user/modified
user=> (spit "new.code" modified) ; write it back
nil
user=> (load-string (slurp "new.code")) ; check it worked!
4
nil
哪裏slurp
給你一個字符串,read-string
給你一個未評估的形式,load-string
給你評估形式的結果。
這不是一個壞主意,它是lisp的主要屬性之一,代碼是數據。 你可以讀取clj文件作爲列表使用讀取字符串修改它並寫回來。
(ns tmp
(:require [clojure.zip :as zip])
(:use clojure.contrib.pprint))
(def some-var true)
;;stolen from http://nakkaya.com/2011/06/29/ferret-an-experimental-clojure-compiler/
(defn morph-form [tree pred f]
(loop [loc (zip/seq-zip tree)]
(if (zip/end? loc)
(zip/root loc)
(recur
(zip/next
(if (pred (zip/node loc))
(zip/replace loc (f (zip/node loc)))
loc))))))
(let [morphed (morph-form (read-string (str \((slurp "test.clj")\)))
#(or (= 'true %)
(= 'false %))
(fn [v] (if (= 'true v)
'false
'true)))]
(spit "test.clj"
(with-out-str
(doseq [f morphed]
(pprint f)))))
這會讀取自身並切換布爾值並將其寫回。
有一個庫叫做rewrite-clj它可以這種類型的東西。
這根本不是個壞主意。它可以用於代碼分析和rfactoring等。 – ivant