2011-08-17 52 views
8

我想知道是否可以將包含在Clojure .clj源文件中的代碼作爲列表加載,而無需編譯它。修改clojure中的Clojure源代碼文件

如果我可以加載一個.clj文件作爲列表,我可以修改該列表並將其打印回相同的文件,然後再次加載。

(也許這是一個壞主意。)有誰知道這是可能的嗎?

+1

這根本不是個壞主意。它可以用於代碼分析和rfactoring等。 – ivant

回答

1

稍微簡單的例子:

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給你評估形式的結果。

7

這不是一個壞主意,它是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))))) 
 

這會讀取自身並切換布爾值並將其寫回。

+1

在sl text的文字周圍添加parens不是一個好主意。重複使用'read'直到文件被使用爲止更清晰且更健壯。 – kotarak

+0

酷!我要試試這個!謝謝! – sneilan