Hi there
Find attached some code that uses apache velocity for command line based
processing, i.e. it's not setup for servlets; i use this as an offline
pre processor for web sites.
It does hierarchical templating of files in a source directory and
copies to a target directory. The templating maps are contained in (by
default) __pp.clj files in the source tree. Further, your __pp.clj maps
can also contain functions for dynamically populating the template.
The nice thing is that each directory can contain it's own __pp.clj file
each of which can override it's parent definitions (in a zope like
'aquisition').
Processing can also be controlled by passing command line arguments
which are added to the templates top level context.
It's not documented, but if anyone is interested I can do some.
cheers
bd
On Tue, 2009-05-26 at 19:47 -0700, markgunnels wrote:
> Hopefully this doesn't get me booed off the message board but is there
> a Clojure equivalent to Ruby's ERB? I'm try to use Clojure to perform
> code generation and, while it makes for an excellent language to write
> a parser in, I can't quite figure out the best way to actually
> template out the code.
>
> Thanks for any help,
> Mark
>
> P.S. Rich -- if you read this, Clojure is terrific.
>
> >
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To post to this group, send email to [email protected]
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
-~----------~----~----~----~------~----~------~--~---
(ns ipowerhouse.live
(:import java.io.File
(org.apache.velocity VelocityContext Template)
(org.apache.velocity.app Velocity)
(org.apache.velocity.app.event InvalidReferenceEventHandler EventCartridge)
java.util.Properties
(org.apache.commons.io FileUtils FilenameUtils))
(:use ipowerhouse.utils.useful))
(declare *pp*)
(declare *extensions*)
(declare *src*)
(declare *dst*)
(declare *ignore*)
(declare *verbose*)
(def *rvc* (VelocityContext.))
(def Rcontexts (ref (hash-map)))
(def Rdirty (ref (vector)))
(defn printIt [& m]
(if (= *verbose* "yes")
(println m)))
; event handler stuff unused as of now ...
(comment
(defn getIRH []
(proxy [InvalidReferenceEventHandler] []
(invalidGetMethod [ctx rf obj prop info]
(printIt "**get:" info)
)
(invalidSetMethod [ctx left right info]
(printIt "**set:" info)
)
(invalidMethod [ctx rf obj method info]
(printIt "**method:" info)
)))
(defn addEventHandler [vc]
(let [ec (EventCartridge.)]
(.addEventHandler ec (getIRH))
(.attachToContext ec vc)))
(addEventHandler *rvc*)
)
(defn removeSrc [#^File f]
(let [p (.getPath f)
ctop (count *src*)]
(subs p ctop)))
(defn check-dirty [p fileName]
(let [src (File. (str *src* "/" p fileName))
dst (File. (str *dst* "/" p fileName))]
(when (and (.exists src) (.exists dst))
(when (FileUtils/isFileNewer src dst)
(printIt src "is dirty")
(dosync
(commute Rdirty conj p))))))
(defn dirty? [f]
(some #(.startsWith f %1) @Rdirty))
(defn forced? []
(.containsKey *rvc* "force"))
(defn getDir [f]
(FilenameUtils/getPath (FilenameUtils/normalizeNoEndSeparator f)))
(defn closestContext [curdir]
(loop [d curdir]
(let [p (getDir d)]
(if (contains? @Rcontexts p)
(do
;(printIt "ctx for " curdir " is " p)
(@Rcontexts p))
(if (= p "")
*rvc*
(recur p))))))
;(def getClosestContext (memoize MgetClosestContext))
(defn keyCheck [k]
(if (keyword? k) (name k) k))
(defn keywordsToStrings [z]
(if (map? z)
(reduce (fn [a k] (assoc a (keyCheck k) (keywordsToStrings (z k))))
{} (keys z))
z))
(defn execute [f prms]
(if (fn? f) (f prms) f))
(defn mapIntoContext [m context]
(let [conv (keywordsToStrings m)]
(doseq [[k v] conv]
(.put context k v)) context))
(defn construct [#^File f]
"this only checks dirs where *pp* are actually present"
(let [fr (java.io.FileReader. f)
p (removeSrc f)
ctxKey (getDir p)]
(if-not (contains? @Rcontexts ctxKey)
(let [
vc (if (= ctxKey "")
(VelocityContext. *rvc*)
(VelocityContext. (closestContext p)))]
(let [m (load-reader fr)]
(when m
(let [conv (keywordsToStrings m)
tmpParams { :parentFile (.getParentFile f)
:context vc
:uri p }]
(reduce (fn [a k] (.put a k (execute (conv k) tmpParams)) a) vc (keys conv)))))
(check-dirty ctxKey (str "/" *pp*))
(dosync
(alter Rcontexts assoc ctxKey vc))))))
(defn context[top]
(let [
pps (filter #(re-find (re-pattern (str *pp* "$")) (.getAbsolutePath %1))
(file-seq (java.io.File. top)))
pathlen (fn [f]
(.length (.getAbsolutePath f)))]
(doseq [s (sort-by pathlen pps)]
(construct s))))
(defn newer? [srcf dstf] (FileUtils/isFileNewer srcf dstf))
(defn ignore? [fs]
(if *ignore*
(filter (fn [f]
(let [p (.getPath f)]
(every? #(= (.indexOf p %1) -1) *ignore*))) fs)
fs))
(defn preserveExec [s d]
(if (.canExecute s)
(.setExecutable d true true)))
(defn copyPreserve [s d]
(FileUtils/copyFile s d)
(preserveExec s d))
(defn process [dest]
(let [
gen (fn [f srcf dstf]
(let [
closestCtx (closestContext f)
tmpl (Velocity/getTemplate f)]
(printIt "templating " f )
(try
(barf dstf
(with-out-str
(.merge tmpl closestCtx *out*)))
(preserveExec srcf dstf)
(catch Exception e
(print e)))))
template (fn [#^String f #^File srcf #^File dstf]
(if (.exists dstf)
(when (or (newer? srcf dstf) (dirty? f) (forced?))
(gen f srcf dstf))
(gen f srcf dstf)))
copy (fn [#^File srcf #^File dstf]
(if (.exists dstf)
(when (newer? srcf dstf)
(do
(printIt "copying " dstf)
(copyPreserve srcf dstf)))
(do (printIt "creating " dstf)
(copyPreserve srcf dstf))))
run (fn [srcf]
(let [relative (removeSrc srcf)
dstf (File. (str *dst* relative))]
(if (.isDirectory srcf)
(when (not (.exists dstf))
(FileUtils/forceMkdir dstf))
(if (FilenameUtils/isExtension relative *extensions*)
(template relative srcf dstf)
(copy srcf dstf)))))
]
(dorun
(map run (ignore? (file-seq (java.io.File. *src*)))))))
(defn checkFile [p]
(let [f (File. p)]
(if (.exists f)
(FilenameUtils/normalizeNoEndSeparator p)
(throw (Exception. (str "File " p " does not exist"))))))
(defn validateConfig [m]
(if-not (contains? m :src)
(throw (Exception. "Need :src"))
(def *src* (checkFile (m :src))))
(if-not (contains? m :dst)
(throw (Exception. "Need :dst"))
(def *dst* (checkFile (m :dst))))
(if-not (contains? m :meta)
(def *pp* "__pp.clj")
(def *pp* (m :meta)))
(if-not (contains? m :ignore)
(def *ignore* nil)
(def *ignore* (m :ignore)))
(if-not (contains? m :ext)
(def *extensions* (into-array ["html","json","conf","css"]))
(def *extensions* (into-array (m :ext)))))
(let [config (second *command-line-args*)]
(let [fr (java.io.FileReader. (File. config))
m (load-reader fr)]
(validateConfig m)))
(println "src --> " *src*)
(println "dst --> " *dst*)
(println "ignoring:" *ignore*)
(.put *rvc* "_STAGE_TOP" *dst*)
(.put *rvc* "_SOURCE_TOP" *src*)
(.put *rvc* "_FNU" FilenameUtils)
(.put *rvc* "_ESC" (org.apache.velocity.tools.generic.EscapeTool.))
(println "Command line:")
(doseq [[k v] (drop 1 (partition 2 *command-line-args*))]
(println "\t" k ": " v)
(if (= k "VERBOSE")
(def *verbose* v)
(.put *rvc* k v)))
(let [p (Properties.)]
(.setProperty p "file.resource.loader.path" *src*)
(Velocity/init p))
(time (do
(context *src*)
(check-dirty "" "VM_global_library.vm")
(println "\nprocessing ...")
(process *src*)))
{
:nginxUser "blackdog",
:site "igameware - web 2.0 games",
:software-supplier "ipowerhouse.com",
:software-supplier-email "[email protected]"
}
(import '(org.apache.commons.io FileUtils FilenameUtils))
{
:helpFiles (fn [prms]
(let [c (.length (str (.get (prms :context) "_SOURCE_TOP")
"/sites/igameware/www"))]
(sort (map #(java.io.File. %1)
(filter #(FilenameUtils/isExtension %1 "html")
(map #(subs (.getPath %1) c)
(file-seq (java.io.File. (prms
:parentFile) "help"))))))))
}