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 clojure@googlegroups.com
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
-~----------~----~----~----~------~----~------~--~---

(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 "black...@ipowerhouse.com"
}
(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"))))))))

}

Reply via email to