On Fri, Apr 1, 2011 at 22:18, B Smith-Mannschott <bsmith.o...@gmail.com> wrote: > On Wed, Mar 30, 2011 at 15:00, Stuart Sierra > <the.stuart.sie...@gmail.com> wrote: >> Take a look at http://www.stringtemplate.org/ for a Turing-complete, >> purely-functional, Java-based template language designed for code >> generation. >
Well, I've spent the weekend wrangling with StringTemplate (ST) and though I'd share my experiences so far. I'm sorry; this is a bit rambling. I chose to jump straight to ST 4, which came out at the end of March, figuring there was no point in learning 3.x since 4.0 seems to be where active development will go in the future. This was a mixed blessing because the practical examples available on the net and the majority of the documentation is actually still for 3.x, which is not completely compatible with 4.0. Also, I found ST's behavior with respect to syntax errors in templates to be less than helpful. Basically it'll throw a NullPointerException, or maybe an IllegalArgumentException or just puke some stuff on the console (generally hidden behind my emacs window). This is rough for a learner. Also, I'm generating java source code which includes uses of generics. This interacts hideously with ST's default of using < and > to delimit a template expression and << and >> to delimit the beginning and end of a template definition. This can be customized, but the customization is not all I hoped for. At first I tried to customize to « and » but this breaks the ability to include comments in the string template group file. (Normally comments are <! ... !>, presumably they would be «! ... !» when one has customized the delimiter characters like I had. But, the fact is neither syntax seemed to work. This cost me *hours* because while the console printed out a huge number of error messages, they were always the same error messages printed in such a way that the console never seemed to scroll, so I thought I was looking at old output and had fixed the problem (by changing <! to «!). The parse errors caused the non-comment comment caused all kinds of strange behavior in later templates, such as crashes. I found, for example, that: someTemplate(a,b) ::= « ... » «list1,list2:someTemplate()» which is roughly analogous to: (defn someTemplate [a b] ...) (map someTemplate list1 list2) Would crash complaining about not having definitions for i0 and i (these variables are something ST defines implicitly for iteration. I don't know the details.) I found I could fix that by changing the template definition to include i0 and i arguments, though I never used them in the template. This just seemed demented. It was at that point that I went to bed. This morning, I finally understood the comment problem and found that if I changed the delimiters to $ and $ and the comments to $! and !$ all was once again well with the world. It's annoying though that opening $ and closing $ are the same character, which doesn't aid readability. So, I've made some progress in my understanding of ST. Now that I sit down and try to re-implement my existing code emission using ST, I find a design question rearing its head. I'm not sure how much complexity to push into the templates and how much to leave in Clojure. I could have a large number of very simple templates and use Clojure to drive and assemble them. Alternatively, I could have a single "entry point" to a large set of templates which call each other internally. That means using Clojure to construct a data model (a map of lists of maps of ...) suitable for consumption by ST. First I through I'd take the first alternative, but then I decided to try the second one first, though now it's looking like I will go back to doing more in clojure and less in ST. I already have a perfectly serviceable model but it seems increasingly like I'd have to tear it apart and build it up completely differently to get it into a form that ST can consume in a reasonable fashion. Here's a simplified fragment of my model: { :class-name "SomeEnum" :id-field :id :records [{:id "A", :payload 3}, {:id "B", :payload 4}] } produces: enum SomeEnum { A(3), B(4); int payload; SomeEnum(int payload) { this.payload = payload; } } - I'm using keywords, but StringTemplate can't tolerate those as keys - ST's variable's can't contain -, so I can't just convert the keyword keys to strings, I have to rename them too. - the type of :payload is not stored explicitly anywhere, but it's a real java Integer in the model, so I just use (type) to figure out what it is. - I have an function (unbox) which gives me the unboxed equivalent where appropriate, otherwise identity. (ST provides Maps, as part of its template language which could almost do this for me, but not quite.) - I have logic to generate "java literal" versions of various values: i.e. 1.0M -> BigDecimal.ONE; 11.0M -> new BigDecimal("11.0") (ST supports ModelRenderers for this, I think). It's looking more and more like using ST is going to involve as much Clojure code as not using ST -- and that's not counting the additional template code. This doesn't feel like a clear win. I'm still very much an ST beginner, but I feel that I struggling against an impedance mismatch of a sort. Maybe it's because ST is designed to feed off an OO model, and I've got one that's functional (all immutable data really). Indeed, I ran across this just this evening: http://steve.vinoski.net/pdf/IC-Clojure_Templating_Libraries_Fleet_and_Enlive.pdf The author seems to have found the same mismatch between Clojure and ST that I have, though he does a better job of explaining it. One of the two alternatives he recommends https://github.com/Flamefork/fleet seems like it could fit to what I'm trying to accomplish. Still, I'd like to first finish my attempt with ST before I decide wether to stick with it or not. // ben -- 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 Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en