Macro compile vs run time, appengine-magic defentity

100 views
Skip to first unread message

Thorsten Wilms

unread,
Mar 28, 2011, 4:13:27 PM3/28/11
to clo...@googlegroups.com
Hi!

Defining an entity with appengine-magic is straightforward:
----
(ns tlog.models
(:require [appengine-magic.services.datastore :as ds]))

(ds/defentity Article [^:key slug, title, body, created-t, updated-t])
----

But there are several places (other files), where that list sans the
first element would be handy and I would like to avoid copy-pasting
[title, body, created-t, updated-t].

ds/defentity is a macro and won't work if it sees functions at compile
time (I hope this way to put it is acceptable, but tell me if my mental
model is lacking).

amaloy helped me with an almost-solution. The following works:
----
(defmacro def-entity-and-attrs [entity-name key attrs]
`(ds/defentity ~entity-name ~(vec (concat ['^:key key] attrs))))

(def-entity-and-attrs Article slug [title, body, created-t, updated-t])
----

But it was meant to be:
----
(defmacro def-entity-and-attrs [entity-name key attrs-name attrs]
`(do (def ~attrs-name ~attrs)
(ds/defentity ~entity-name ~(vec (concat ['^:key key] attrs)))))

(def-entity-and-attrs Article slug
attrs-name [title, body, created-t, updated-t])
----
Fails with: "Unable to resolve symbol: title in this context"
Or if I quote the vector: "clojure.lang.PersistentVector cannot be cast
to clojure.lang.Symbol"

I guess trying to access attrs-name from elsewhere would have been
"fun", anyway.

I would love to simply
----
(def article-attrs '[title, body, created-t, updated-t])
----
and work with that.

It's not the first time I run into a situation where things beg to be
composited/concatenated, but can't be, at least not easily.

Any ideas?

--
Thorsten Wilms

thorwil's design for free software:
http://thorwil.wordpress.com/

Alan

unread,
Mar 28, 2011, 4:29:17 PM3/28/11
to Clojure
If you need it quoted in the "def" context:

(defmacro def-entity-and-attrs [entity-name key attrs-name attrs]
`(do (def ~attrs-name '~attrs)
(ds/defentity ~entity-name ~(vec (concat ['^:key key]
attrs)))))

Note the ' before attrs.

PS why is there a ' before ^:key? It doesn't seem to me like it does
anything.

Meikel Brandmeyer

unread,
Mar 28, 2011, 4:35:49 PM3/28/11
to clo...@googlegroups.com
Hi,

Am 28.03.2011 um 22:29 schrieb Alan:

> If you need it quoted in the "def" context:
>
> (defmacro def-entity-and-attrs [entity-name key attrs-name attrs]
> `(do (def ~attrs-name '~attrs)
> (ds/defentity ~entity-name ~(vec (concat ['^:key key]
> attrs)))))
>
> Note the ' before attrs.
>
> PS why is there a ' before ^:key? It doesn't seem to me like it does
> anything.

It quotes the key symbol. Without it you get a similar error to the one you fixed with the ' in front of the ~attrs.

Sincerely
Meikel

Meikel Brandmeyer

unread,
Mar 28, 2011, 4:46:22 PM3/28/11
to clo...@googlegroups.com
Hi,

Am 28.03.2011 um 22:35 schrieb Meikel Brandmeyer:

>> PS why is there a ' before ^:key? It doesn't seem to me like it does
>> anything.
>
> It quotes the key symbol. Without it you get a similar error to the one you fixed with the ' in front of the ~attrs.

Ah. In fact you don't, because key is likely resolved to the core function of the same name.

Sincerely
Meikel

Thorsten Wilms

unread,
Mar 29, 2011, 3:56:32 AM3/29/11
to clo...@googlegroups.com
On 03/28/2011 10:29 PM, Alan wrote:
> If you need it quoted in the "def" context:
>
> (defmacro def-entity-and-attrs [entity-name key attrs-name attrs]
> `(do (def ~attrs-name '~attrs)
> (ds/defentity ~entity-name ~(vec (concat ['^:key key]
> attrs)))))
>
> Note the ' before attrs.

Thank you, works!


> PS why is there a ' before ^:key? It doesn't seem to me like it does
> anything.

It compiles without, bu then the datastore won't use that argument as
named-key, but fabricate a running number, instead.

Now the fun is:

[^:key key] leads to a datastore field "slug", as that's the argument
for key, but it won't be used as named-key for the record.

[':key key] fixes the use-as-named-key issue, but leads to a field
called "key", not "slug" (datastore viewer lists named-key attributes
twice, once as ID/name, once with its given name).

The following do not work at all:
[`^:key ~key]
`[^:key ~key]

Meikel Brandmeyer

unread,
Mar 29, 2011, 4:52:41 AM3/29/11
to Clojure
Hi,

On 29 Mrz., 09:56, Thorsten Wilms <t...@freenet.de> wrote:

> [^:key key] leads to a datastore field "slug", as that's the argument
> for key, but it won't be used as named-key for the record.

Ah. Now things become clear. I haven't read the problem correctly. You
want [(with-meta key {:key true})].

Sincerely
Meikel

Thorsten Wilms

unread,
Mar 29, 2011, 3:42:52 PM3/29/11
to clo...@googlegroups.com
On 03/29/2011 10:52 AM, Meikel Brandmeyer wrote:

> Ah. Now things become clear. I haven't read the problem correctly. You
> want [(with-meta key {:key true})].

Thanks, but unfortunately, that builds, but does not set the named key
(running number for the ID/name attribute, again).

['^:key key] or [`^:key ~key] do set ID/name, but key will be
interpreted literally.
['^:key ~key] ; does not compile
[^:key key] or [(with-meta key {:key true})] do not set ID/name.

Any other ideas?


At least, I found a solution for my "define that list only once" and
"macros don't evaluate their arguments" problem: use of eval inside the
macro definition:


----
(ns tlog.models
(:require [appengine-magic.services.datastore :as ds]))

(def article-attrs '[title, body, created-t, updated-t])

(defmacro def-entity-and-attrs [type key attrs]
`(ds/defentity ~type ~(vec (concat [(with-meta key {:key true})]
(eval attrs)))))

(def-entity-and-attrs Article slug article-attrs)
----

Meikel Brandmeyer

unread,
Mar 29, 2011, 4:51:22 PM3/29/11
to clo...@googlegroups.com
Hi,

Am 29.03.2011 um 21:42 schrieb Thorsten Wilms:

> [(with-meta key {:key true})] do not set ID/name.

Which Clojure version are you using? If it is 1.2, try (with-meta key {:tag :key}).

Sincerely
Meikel

Thorsten Wilms

unread,
Mar 30, 2011, 7:34:27 AM3/30/11
to clo...@googlegroups.com
On 03/29/2011 10:51 PM, Meikel Brandmeyer wrote:

>> [(with-meta key {:key true})] do not set ID/name.
>
> Which Clojure version are you using? If it is 1.2, try (with-meta key {:tag :key}).

Clojure 1.2 and your are correct, thanks. I added a comment to remember
that variant, for when I switch version.

Or should I do so already, perhaps, given that all I use is
appengine-magic, moustache and envlive, so far?

Reply all
Reply to author
Forward
0 new messages