2011-05-08 62 views
6

我特別試圖在Clojure中使用appengine-magic來爲粗體函數生成樣板,以便與Google App Engine數據存儲一起使用。我很難研究如何從下面轉載的模型中生成值。在Clojure中使用宏

(def *model* {:users [{:name "Adam" 
         :email "[email protected]" 
         :registered-on "07-05-2011"} 
         {:name "Greg" 
         :email "[email protected]" 
         :registered-on "11-05-2011"}] 
       :post [{:title "A" 
         :authour "Adam"} 
        {:title "B" 
         :author "Greg"}]}) 

我是相當新的AppEngine上魔法,但它提供了一個defentity它允許您定義,你可以把到數據存儲實體和保存!它允許您將預定義的實體保存到數據存儲中。

這些採取以下形式:

(ds/defentity Post [title author]) 
(ds/save! (Post. title author)) 

現在剛開始我定義:

(list-entities *model*) 

輸出:

(defn list-entities [model] 
    "Takes a representation of the model and lists the entities in preparation for generating defentities" 
    (interleave (vec (map first (partition 1 (map (comp symbol capitalize #(str % ".") name) (keys model))))) 
    (map vec (map keys (map first (vals model)))))) 

與調用它

(Users. [:name :email :registered-on] Post. [:title :author]) 

現在,我很難定義gen-entities,它將採用上面的輸出並反覆調用ds/defentities來定義與我的模型所需的實體數量一樣多的實體。

(defmacro gen-entities [entity fields] 
    `(ds/defentity 'entity 'fields)) 

此外,我無法確定這是解決此問題的合理方法。我對宏還很新,可能犯了一些錯誤。任何幫助/清晰度將不勝感激。

注:

,我已經實現了模型設計很糟糕,下面一個是好了很多:

(def *model* {:users [:name :email :registered-on] 
       :post [:title :author]}) 

然而,它是寫一個宏,所以我會離開的條件更復雜它是如此。

+1

爲什麼你不想做一個函數將輸入轉換爲直接調用ds/defentity?你需要宏的唯一原因是你的函數產生的輸出。 – Gert 2011-05-08 06:22:05

+0

那麼我可能會錯過這裏的東西,我試過了,它似乎不工作。所以我認爲這是一個我不得不使用宏的情況。我知道我們不應該使用它們,除非我們需要,所以我想我會在這裏問一下。 – toofarsideways 2011-05-08 10:56:07

回答

1

我認爲一個宏是必需的,因爲defentity似乎定義了一個類型。

(defmacro gen-entities 
    [model] 
    `(do 
    [email protected](for [[entity-kw values] model] 
     (let [entity-sym (-> entity-kw name capitalize symbol) 
       fields  (map (comp symbol name) (keys (first values)))] 
      `(ds/defentity ~entity-sym [[email protected]]))))) 

你不必一個一個地擺弄對方的鍵和值,只是把它們放在一起再交錯。通過地圖進行映射將一次性爲您提供密鑰和相應的值。

user=> (macroexpand-1 `(gen-entities ~model)) 
(do 
    (ds/defentity Users [name registered-on email]) 
    (ds/defentity Post [title authour])) 

注意:這不適用於存儲在Var中的模型。您需要在致電gen-entities時指定模型。

user=> (macroexpand-1 '(gen-entities model)) 
(
#<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol> 
+0

我似乎錯過了一些東西,當我運行macroexpand-1時,如你所示,我得到了輸出。但是,如果我嘗試評估調用(gen-entities insertion-model-here)而不是宏擴展它,它不起作用,給我一個java.lang.ClassCastException:clojure.lang。關鍵字不能轉換爲clojure.lang.IObj [拋出的類java.lang.RuntimeException]。任何想法我失蹤? – toofarsideways 2011-05-08 13:06:13

+0

另外,你不能使用預定義的Var,這種限制的任何原因似乎很奇怪? – toofarsideways 2011-05-08 13:16:38

+0

@toofarsideways修復了一個愚蠢的錯誤。它現在應該工作。它不適用於Var,因爲在這種情況下宏沒有看到Var的實際值,但是符號「model」。 – kotarak 2011-05-08 15:45:27