Thanks Rich, that worked great.  Here's what I ended up using:

(in-ns 'velocity)
(clojure/refer 'clojure)

(import '(org.apache.velocity.app VelocityEngine))
(import '(org.apache.velocity.context Context))
(import '(java.io StringWriter))

(defn make-context [context]
  (proxy [Context] []
    (containsKey [key] (contains? context (keyword key)))
    (get [key] (context (keyword key)))
    (getKeys [] (keys context))
    (put [key value] false)
    (remove [key] false)))

(defn render [template context]
  (let
      [ve (new VelocityEngine)
       ctx (make-context context)
       out (new StringWriter)]
    (.init ve)
    (.evaluate ve ctx out "clojure" template)
    (.toString out)))

The VelocityEngine gets re-created every time, so I'll have to fix
that, but other than that, this seems to work.  Probably should have
put and remove throw an Exception rather than return false also.

On Oct 13, 11:22 am, Rich Hickey <[EMAIL PROTECTED]> wrote:
> On Oct 13, 10:17 am, Paul Barry <[EMAIL PROTECTED]> wrote:
>
>
>
> > To give a specific example of what I'm trying to do, I'd like to use
> > velocity templates in Clojure.  So I have this code:
>
> > (in-ns 'velocity)
> > (clojure/refer 'clojure)
>
> > (import '(org.apache.velocity.app VelocityEngine))
> > (import '(org.apache.velocity VelocityContext))
> > (import '(java.io StringWriter))
>
> > (defn render [template context]
> >   (let
> >       [ve (new VelocityEngine)
> >        ctx (new VelocityContext context)
> >        out (new StringWriter)]
> >     (.init ve)
> >     (.evaluate ve ctx out "clojure" template)
> >     (.toString out)))
>
> > And then I can do:
>
> > (velocity/render "foo is $foo" {"foo" "bar"})
>
> > But obviously this isn't going to work:
>
> > (velocity/render "foo is $foo" {:foo "bar"})
>
> > So short of modifying the Java implementation of either Clojure or
> > Velocity to be indifferent to Strings/Keywords, I either have to:
>
> > 1) Only pass String-keyed maps into this method
> > 2) Have this method turn all the Keywords into Strings before creating
> > the VelocityContext
>
> > I'm leaning towards #2, just because I would expect (velocity/render
> > "foo is $foo" {:foo "bar"}) to "work", and others might too.  I'm
> > thinking about how to build a MVC web app with Clojure, and I would
> > have the model layer return Keyword-keyed maps that represent data
> > stored in the database, and then I'd like to pass those values into a
> > method like this to be the view layer.
>
> > What are your thoughts?  Should I change the model layer to return
> > String-keyed maps?  Or convert the Keywords to Strings before building
> > the VelocityContext?
>
> It depends on how much you are going to do with your model, other than
> pass it to Velocity. But doing what's right for the model should
> dominate. If that's keywords, you have 2 options here. One is to clone
> the map with string keys and pass to VelocityContext ctor. The other
> is to proxy Context (a simple interface above VelocityContext, or
> AbstractContext, an implementation helper) on the map in situ, instead
> of using VelocityContext. The tradeoff will be between a one-time copy
> of the entire map, using fast conversions of keywords to strings, vs
> no map copy, but more overhead per lookup as strings will have to be
> turned into keywords using Keyword.intern(null,str). Map size vs
> number of lookups will determine which is more efficient.
>
> Rich
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to