Commits

Kresimir Sojat  committed 1b33a3e

New builder and almost build-scope macro. Moved examples, added doc style css files.

  • Participants
  • Parent commits c41094e

Comments (0)

Files changed (24)

File build.properties

-# Apache Ivy.
-ivy.version=2.0.0-beta1
-ivy.jar.dir=${user.home}/.ivy2/jars
-ivy.jar.src=http://www.apache.org/dist/ant/ivy/${ivy.version}/ivy.jar
-ivy.jar.dst=${ivy.jar.dir}/ivy.jar
-
-ivy.local.default.root=${user.home}/.ivy2/local
-ivy.local.default.ivy.pattern=[organisation]/[module]/[revision]/ivys/ivy.xml
-ivy.local.default.artifact.pattern=[organisation]/[module]/[revision]/jars/[artifact].[ext]

File examples/json1.clj

-;; Copyright (c) 2008 Krešimir Šojat. All rights reserved.  The use and
-;; distribution terms for this software are covered by the Common
-;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
-;; which can be found in the file CPL.TXT at the root of this
-;; distribution.  By using this software in any fashion, you are
-;; agreeing to be bound by the terms of this license.  You must not
-;; remove this notice, or any other, from this software.
-
-(ns user
-  (:require [net.ksojat.neman.json :as json]))
-
-(json/write-file "json1-1.json"
-  {:one   1
-   :two   "two"
-   :three [1 2 3]})
-
-(defstruct json-output
-  :first :second :third)
-
-(json/write-file "json1-2.json"
-  (struct-map json-output
-    :first  [1 2 {:a 1 :b 2}]
-    :second false
-    :third  {:a "b" :c "d"}))

File examples/xml1.clj

-;; Copyright (c) 2008 Krešimir Šojat. All rights reserved.  The use and
-;; distribution terms for this software are covered by the Common
-;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
-;; which can be found in the file CPL.TXT at the root of this
-;; distribution.  By using this software in any fashion, you are
-;; agreeing to be bound by the terms of this license.  You must not
-;; remove this notice, or any other, from this software.
-
-(ns user
-  (:require net.ksojat.neman.xml)
-  (:use net.ksojat.neman.core [net.ksojat.neman.xml :only [xml]])
-  (:import (org.jdom.output XMLOutputter)))
-
-(def html-doc
-  (xml
-    (=> :html
-      [(=> :head)
-       (=> :body
-         {:class "klass" :id "main"}
-         [(=> :p "Just some text.")])])))
-
-(.output (XMLOutputter.) html-doc System/out)

File examples/xml2.clj

-;; Copyright (c) 2008 Krešimir Šojat. All rights reserved.  The use and
-;; distribution terms for this software are covered by the Common
-;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
-;; which can be found in the file CPL.TXT at the root of this
-;; distribution.  By using this software in any fashion, you are
-;; agreeing to be bound by the terms of this license.  You must not
-;; remove this notice, or any other, from this software.
-
-(ns user
-  (:use net.ksojat.neman.core [net.ksojat.neman.xml :only [render template template-from child]])
-  (:import (org.jdom.output XMLOutputter)))
-
-(def base
-  (template [title message]
-    (=> :html
-      [(=> :head
-         [(=> :title [title])])
-       (=> :body
-         [(=> :h1 [title])
-          (child :body)
-          (=> :p [message])
-          (child :extra)])])))
-
-(def level1
-  (template-from base
-    (:body
-      (=> :h2 "Second Header")
-      (for [i (range 5)]
-        (=> :p [(str "Generated " i)]))
-      (=> :div
-        [(child :body) (=> :p "Extra")]))
-    (:extra
-      (=> :div "ExtraDivTag"))))
-
-(def level2
-  (template-from level1
-    (:body
-      (=> :p "ExtraDva"))))
-
-(render level2 {:title "Naslov" :message "Poruka"})

File examples/xml3.clj

-(ns user
-  (:use
-    (net.ksojat.neman
-      core
-      [web :only [url-for url-for-path *current-path*]]
-      [xml :only [render xml xml-node xml-nodes template template-from child]])))
-
-
-;(def baseh
-;  (template
-;    (=> :html
-;      [(=>> (:head [(child :head) (child :css)])
-;            (:body [(child :body) (child :js)]))])))
-
-(def baseh
-  (template
-    (=> :html
-      [(=> :head [(child :head) (child :css)])
-       (=> :body [(child :body) (child :js)])])))
-
-
-(def base
-  (template-from baseh
-    (:head
-      (=> :meta {:http-equiv "Content-Type" :content "text/html; charset=utf-8"})
-      (=> :title "Hatchery Alpha")
-      ;(shortcut-icon "media/favicon.png")
-      (child :head))
-    (:css
-      (child :css))
-    (:js
-      (child :js))
-    (:body
-      (=> :div {:id "main"}
-        [(=> :div {:id "header" :class "fluid"}
-           [(=> :h1 "Hatchery")
-            (=> :p "Experiments in Genetic Algorithms, Procedural Graphics and Functional Languages")])
-         (child :body)])
-
-      (=> :div {:id "footer"}
-        "© 2008.  Kre\u0161imir \u0160ojat. All right reserved."))))
-
-;(def base2
-;  (template-from base
-;    (:body
-;      (=> :div.fluid#nav
-;        [(=> :form.search
-;           [(=>> (:label {:for "search"} "Search")
-;                 (:input.search {:type "text" :name "search"})
-;                 (:input {:type "submit" :value "Go"}))])
-;         (=> :div {:class "clear"})])
-;      (=> :div [(child :body)]))))
-
-;(def index-template
-;  (template-from baseh
-;    (:body
-;      (=> :a))))
-
-(render base)

File ivy.xml

-<!--
-ivy.xml
-Copyright (c) 2008  Krešimir Šojat
-All rights reserved.
--->
-<ivy-module version='2.0'>
-    <info organisation='net.ksojat' module='neman'/>
-    <publications>
-        <artifact name='neman' type='jar' ext='jar'/>
-    </publications>
-    <dependencies>
-        <dependency org='clojure' name='clojure' rev='svn1205'>
-            <artifact name='clojure' type='jar'/>
-        </dependency>
-        <dependency org='clojure' name='clojure-contrib' rev='svn328'>
-            <artifact name='clojure-contrib' type='jar'/>
-        </dependency>
-        <dependency org='org.codehaus' name='jackson' rev='0.9.2'>
-            <artifact name='jackson'
-                type='jar'
-                url='http://www.cowtowncoder.com/hatchery/jackson/0.9.2/jackson-0.9.2.jar'/>
-        </dependency>
-        <dependency org='net.java' name='textile-j' rev='2.2'/>
-        <dependency org='commons-cli' name='commons-cli' rev='1.1'>
-            <exclude org='junit'/>
-        </dependency>
-        <dependency org='org.mortbay.jetty' name='jetty' rev='6.1.11'/>
-        <dependency org='org.mortbay.jetty' name='jetty-plus' rev='6.1.11'/>
-        <dependency org='jdom' name='jdom' rev='1.1'/>
-        <dependency org='jline' name='jline' rev='0.9.91'/>
-    </dependencies>
-</ivy-module>

File neman/cells/docs/style.css

+body {
+    margin: 10px 50px;
+    font-family: Arial;
+}
+
+h1 {
+    /*text-align: center;*/
+    font-size: 1.6em;
+}
+
+a {
+    color: #215A6D;
+}
+
+p {
+    letter-spacing: 0.2px;
+    line-height: 1.5em;
+}
+
+.notice {
+    padding: 3px;
+    background-color: #CCCCCC;
+    border-left: 4px solid black;
+    font-size: 0.8em;
+}
+
+pre {
+    padding: 5px;
+    background-color: #FFFFF5;
+    border-top: 1px solid #CDDAD9;
+    border-bottom: 1px solid #CDDAD9;
+    border-left: 4px solid orange;
+    line-height: 1.4em;
+}
+
+code {
+    background-color: #EBF7F6;
+    padding: 2px;
+}
+
+.tags {
+    clear: both;
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol {
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol li {
+    list-style: none;
+    display: inline;
+}
+
+.note {
+    border: 1px dashed #282828;
+    background-color: #ECF2F3;
+    padding: 10px;
+}
+
+.pagetitle {
+    font-size: 2.3em;
+    font-weight: bold;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+    border: 1px solid #C72545;
+}
+
+th {
+    color: white;
+    background-color: #C72545;
+    text-align: left;
+    font-family: Monospace;
+    font-weight: normal;
+    padding: 2px;
+}
+
+td {
+    padding: 4px;
+}
+
+tr.odd {
+    background-color: #f8f8f8;
+}

File neman/core/docs/core.textile

+h1. Core functions and macros
+
+Main part of @neman.core@ library is @=>@ (builder) macro used for constructiong Java objects and there compositions. Usage of builder is similar to builtin @doto@ macro and @new@ special form with abbility to __inject__ new methods in existing Java classes, add __new constructors__, __override__ existing methods and (*TODO*).
+
+p(notice). There is no real injection of new methods and constructors, they are effective only inside builder macro.
+
+This is how you would construct a SWING menu for your app using builder macro (configured with @neman.swing@):
+
+pre.. 
+ (ns user
+   (:import (javax.swing JMenuBase JMenu JMenuItem JSeparator))
+   (:require net.ksojat.neman.swing)
+   (:use net.ksojat.neman.core))
+
+ (def m
+   (=> (JMenuBar.)
+     [(=> [JMenu "&File"]
+        [(=> [JMenuItem "&New [ctrl n]"])
+         (=> [JMenuItem "&Open [ctrl o]"])
+         (=> [JMenuItem "&Save [ctrl s]"]
+           :Enabled false)
+         (JSeparator.)
+         (=> [JMenuItem "&Exit [ctrl q]"])])
+       (=> [JMenu "&Edit"]
+         [(=> [JMenuItem "Cu&t [ctrl x]"])
+          (=> [JMenuItem "&Copy [ctrl c]"])
+          (=> [JMenuItem "&Paste [ctrl v]"])])]))
+p. Equivalent code using @doto@ and @new@ could be written as:
+
+pre.. 
+  (ns user
+    (:import (javax.swing JMenuBar JMenu JMenuItem JSeparator KeyStroke))
+
+  (def m
+    (doto (JMenuBar.)
+      (.add
+        (doto (JMenu. "File")
+          (.setMnemonic "f")
+          (.add
+            (doto (JMenuItem. "New")
+              (.setMnemonic "n")
+              (.setAccelerator (KeyStroke/getKeyStroke "ctrl n"))))
+          (.add
+            (doto (JMenuItem. "Open")
+              (.setMnemonic "o")
+              (.setAccelerator (KeyStroke/getKeyStroke "ctrl o"))))
+          (.add
+            (doto (JMenuItem. "Save")
+              (.setEnabled false)
+              (.setMnemonic "s")
+              (.setAccelerator (KeyStroke/getKeyStroke "ctrl s"))))))
+      (.add
+        (doto (JMenu. "Edit")
+          (.setMnemonic "e")
+          (.add
+            (doto (JMenuItem. "Cut")
+              (.setMnemonic "t")
+              (.setAccelerator (KeyStroke/getKeyStroke "ctrl x"))))
+          (.add
+            (doto (JMenuItem. "Copy")
+              (.setMnemonic "c")
+              (.setAccelerator (KeyStroke/getKeyStroke "ctrl c"))))
+          (.add
+            (doto (JMenuItem. "Paste")
+              (.setMnemonic "p")
+              (.setAccelerator (KeyStroke/getKeyStroke "ctrl v"))))))))

File neman/core/docs/style.css

+body {
+    margin: 10px 50px;
+    font-family: Arial;
+}
+
+h1 {
+    /*text-align: center;*/
+    font-size: 1.6em;
+}
+
+a {
+    color: #215A6D;
+}
+
+p {
+    letter-spacing: 0.2px;
+    line-height: 1.5em;
+}
+
+.notice {
+    padding: 3px;
+    background-color: #CCCCCC;
+    border-left: 4px solid black;
+    font-size: 0.8em;
+}
+
+pre {
+    padding: 5px;
+    background-color: #FFFFF5;
+    border-top: 1px solid #CDDAD9;
+    border-bottom: 1px solid #CDDAD9;
+    border-left: 4px solid orange;
+    line-height: 1.4em;
+}
+
+code {
+    background-color: #EBF7F6;
+    padding: 2px;
+}
+
+.tags {
+    clear: both;
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol {
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol li {
+    list-style: none;
+    display: inline;
+}
+
+.note {
+    border: 1px dashed #282828;
+    background-color: #ECF2F3;
+    padding: 10px;
+}
+
+.pagetitle {
+    font-size: 2.3em;
+    font-weight: bold;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+    border: 1px solid #C72545;
+}
+
+th {
+    color: white;
+    background-color: #C72545;
+    text-align: left;
+    font-family: Monospace;
+    font-weight: normal;
+    padding: 2px;
+}
+
+td {
+    padding: 4px;
+}
+
+tr.odd {
+    background-color: #f8f8f8;
+}

File neman/core/src/net/ksojat/neman/core.clj

 
 (ns net.ksojat.neman.core
   (:import (clojure.lang RT Reflector)
-           (java.util UUID)))
+           (java.util UUID))
+  (:load "core/builder"))
 
 (defn str-join [s & strings]
   (str (interpose s strings)))
 (defn resource-url [res]
   (when res (.getResource (RT/baseLoader) res)))
 
-;(defn resource-url [& res]
-;  (when-let [res (apply str-join "/" res)]
-;    (.getResource (RT/baseLoader) res)))
-
 (defn resource-as-stream [res]
   (when res (.getResourceAsStream (RT/baseLoader) res)))
 
-;(defn resource-as-stream [& res]
-;  (when-let [res (apply str-join "/" res)]
-;    (.getResource (RT/baseLoader) res)))
-
-;(defn resource-as-file [res]
-;  (when-let [res (apply str-join "/" res)]
-;    (when-let [res (.ge
-
-;(defn resource-as-file [& res]
-;  (when-let [res (apply resource-url res)]
-;    (.getFile res)))
-
 (defn resource-as-file [res]
   (when-let [res (resource-url res)] (.getFile res)))
 
   (filter (complement sequential?)
           (rest (tree-seq sequential? seq x))))
 
-(defn- make-args [x]
-  (if x (to-array x) RT/EMPTY_ARRAY))
+;(defn- make-args [x]
+;  (if x (to-array x) RT/EMPTY_ARRAY))
 
-(defn- arglist [x]
-  (if (seq? x) x (list x)))
+;(defn- arglist [x]
+;  (if (seq? x) x (list x)))
 
-(defmulti
-  ctor (fn [x] (if (vector? x) (first x) x)))
+;(defmulti
+;  ctor (fn [x] (if (vector? x) (first x) x)))
 
-(defmethod ctor :default [x]
-  (if (vector? x)
-    (let [[o & args] x]
-      (Reflector/invokeConstructor o (make-args args)))
-    x))
+;(defmethod ctor :default [x]
+;  (if (vector? x)
+;    (let [[o & args] x]
+;      (Reflector/invokeConstructor o (make-args args)))
+;    x))
 
 ; Default builder contructor binding.
-(def *ctor* #'ctor)
+;(def *ctor* #'ctor)
 
-(defmulti
-  #^{:doc "Class method 'monkey patching' system used by => macro."}
-  patch (fn [object method & args] [(class object) method]))
+;(defmulti
+;  #^{:doc "Class method 'monkey patching' system used by => macro."}
+;  patch (fn [object method & args] [(class object) method]))
 
-(defmethod patch :default [object method & args]
-  (Reflector/invokeInstanceMethod object (name method) (make-args args)))
+;(defmethod patch :default [object method & args]
+;  (Reflector/invokeInstanceMethod object (name method) (make-args args)))
 
-(defmulti default-method (fn [x t] [(class x) t]))
-(defmethod default-method :default [& _] nil)
+;(defmulti default-method (fn [x t] [(class x) t]))
+;(defmethod default-method :default [& _] nil)
 
-(defn last-char [s]
-  (first (reverse s)))
+;(defn last-char [s]
+;  (first (reverse s)))
 
-(defn drop-last-char [s]
-  (apply str (drop-last s)))
+;(defn drop-last-char [s]
+;  (apply str (drop-last s)))
 
-(defn str-ends-with [s c]
-  (= (last-char s) c))
+;(defn str-ends-with [s c]
+;  (= (last-char s) c))
 
-(defn setter-symbol [x]
-  (symbol (str "set" (name x))))
+;(defn setter-symbol [x]
+;  (symbol (str "set" (name x))))
 
-(defn- mquote [x]
-  (list 'quote x))
+;(defn- mquote [x]
+;  (list 'quote x))
 
-(defmacro => [x & members]
-  (let [gx (gensym)
-        x `(*ctor* ~x)
-        map-dm (gensym)
-        vec-dm (gensym)
-        str-dm (gensym)]
-    `(let [~gx ~x
-           ~map-dm (default-method ~gx :map)
-           ~vec-dm (default-method ~gx :vector)
-           ~str-dm (default-method ~gx :string)]
-      ~@(loop [mx members, p nil]
-          (if mx
-            (let [m (first mx)]
-              (cond
-                (keyword? m)
-                  (recur
-                    (rrest mx)
-                    (cons
-                      (concat
-                        (list 'patch gx (mquote (setter-symbol m)))
-                        (if (vector? (second mx))
-                          (second mx)
-                          (list (second mx))))
-                      p))
-                (map? m)
-                  (recur (rest mx) (cons (list 'patch gx map-dm m) p))
-                (string? m)
-                  (recur (rest mx) (cons (list 'patch gx str-dm m) p))
-                (vector? m)
-                  (let [calls (map
-                                #(concat
-                                  (list 'patch gx vec-dm)
-                                  (if (vector? %) % (list %)))
-                                m)]
-                    (recur (rest mx) (concat (reverse calls) p)))
-                :else
-                  (if (str-ends-with (name (first m)) \+)
-                    (let [mn (symbol (drop-last-char (name (first m))))
-                          calls (map
-                                  #(concat
-                                    (list 'patch gx (mquote (first m))) %)
-                                  (rest m))]
-                      (recur (rest mx) (concat (reverse calls) p)))
-                    (recur
-                      (rest mx)
-                      (cons
-                        (concat
-                          (list 'patch gx (mquote (first m))) (rest m))
-                        p)))))
-            (reverse p)))
-      ~gx)))
-
-(defmacro let-builder-ids
-  ([x]
-    `(let-builder-vars {:id :Id :result :toplevel} ~x))
-
-  ([{id :id result :result} x]
-    `(do ~x)))
+;(defmacro => [x & members]
+;  (let [gx (gensym)
+;        x `(*ctor* ~x)
+;        map-dm (gensym)
+;        vec-dm (gensym)
+;        str-dm (gensym)]
+;    `(let [~gx ~x
+;           ~map-dm (default-method ~gx :map)
+;           ~vec-dm (default-method ~gx :vector)
+;           ~str-dm (default-method ~gx :string)]
+;      ~@(loop [mx members, p nil]
+;          (if mx
+;            (let [m (first mx)]
+;              (cond
+;                (keyword? m)
+;                  (recur
+;                    (rrest mx)
+;                    (cons
+;                      (concat
+;                        (list 'patch gx (mquote (setter-symbol m)))
+;                        (if (vector? (second mx))
+;                          (second mx)
+;                          (list (second mx))))
+;                      p))
+;                (map? m)
+;                  (recur (rest mx) (cons (list 'patch gx map-dm m) p))
+;                (string? m)
+;                  (recur (rest mx) (cons (list 'patch gx str-dm m) p))
+;                (vector? m)
+;                  (let [calls (map
+;                                #(concat
+;                                  (list 'patch gx vec-dm)
+;                                  (if (vector? %) % (list %)))
+;                                m)]
+;                    (recur (rest mx) (concat (reverse calls) p)))
+;                :else
+;                  (if (str-ends-with (name (first m)) \+)
+;                    (let [mn (symbol (drop-last-char (name (first m))))
+;                          calls (map
+;                                  #(concat
+;                                    (list 'patch gx (mquote (first m))) %)
+;                                  (rest m))]
+;                      (recur (rest mx) (concat (reverse calls) p)))
+;                    (recur
+;                      (rest mx)
+;                      (cons
+;                        (concat
+;                          (list 'patch gx (mquote (first m))) (rest m))
+;                        p)))))
+;            (reverse p)))
+;      ~gx)))

File neman/core/src/net/ksojat/neman/core/builder.clj

+;; Copyright (c) 2009 Krešimir Šojat. All rights reserved.  The use and
+;; distribution terms for this software are covered by the Common
+;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
+;; which can be found in the file CPL.TXT at the root of this
+;; distribution.  By using this software in any fashion, you are
+;; agreeing to be bound by the terms of this license.  You must not
+;; remove this notice, or any other, from this software.
+
+(ns user
+  (:require [clojure.zip :as zip])
+  (:import (clojure.lang RT Reflector)))
+
+(defmulti
+  #^{:doc
+      "Builder macro provides alternative way of object a Java object. It's syntax is:
+
+        (=> [Class arg1..argN] ..)
+
+       If object is constructed using this syntax builder will delegate object
+       construction to ctor multimethod."}
+  ctor (fn [x] (if (vector? x) (first x) x)))
+
+(defn- make-args [x]
+  (if (seq x) (to-array x) RT/EMPTY_ARRAY))
+
+(defn- arglist [x]
+  (if (seq? x) x (list x)))
+
+;; Default constructor, invokes standard Java contructor for given Class.
+(defmethod ctor :default [x]
+  (if (vector? x)
+    (let [[o & args] x]
+      (Reflector/invokeConstructor o (make-args args)))
+    x))
+
+(def
+  #^{:doc
+      "While *ctor* is not private you should never provide your own binding
+      for it. Treat it as private to neman library."}
+  *ctor* #'ctor)
+
+(defmulti
+  #^{:doc
+      "Class method 'monkey patching' system used by => (builder) macro.
+       Provides ways to overwrite existing or add new 'methods' to Class.
+       Injected methods will work only inside => calls."}
+  patch (fn [object method & args] [(class object) method]))
+
+;; Default method call, delegates to Java.
+(defmethod patch :default [object method & args]
+  (Reflector/invokeInstanceMethod object (name method) (make-args args)))
+
+(defmulti  default-method* (fn [x t] [(class x) t]))
+(defmethod default-method* :default [& _] nil)
+
+(defmacro
+  #^{:doc
+      "Define method name wich call can be replaced with Clojure literal
+       in builder body.
+
+       There are three types of Clojure literals that can be used as
+       replacements for method calls.
+
+        for string literals
+          (=> (MyClass.) (setText \"SomeText\"))
+        can be replaced with
+          (=> (MyClass.) \"SomeText\")
+
+        for map literals:
+          (=> (MyClass.) (addAttribute \"id1\" 10) (addAttribute \"id2\" 20))
+        can be replaced with
+          (=> (MyClass.) {\"id1\" 10, \"id2\" 20})
+
+        for vector literals:
+          (=> (MyWidget.) (add (ChildWidget.)) (add (ChildWidget.)))
+        can be replaced with
+          (=> (MyWidget.) [(ChildWidget.) (ChildWidget.)])
+
+        Example:
+          (default-method
+            MyWidget :vector add
+            (MyClass :string addText
+                     :map    addAttribute))"}
+  default-method [& specs]
+  (let [specs (loop [[x & _ :as specs] specs, res []]
+                (if (seq specs)
+                  (if (seq? x)
+                    (recur
+                      (rest specs)
+                      (apply conj res (map #(cons (first x) %) (partition 2 (rest x)))))
+                    (recur
+                      (drop 3 specs)
+                      (conj res (take 3 specs))))
+                  res))]
+    `(do
+       ~@(map
+           (fn [[object type method]]
+             `(defmethod default-method* [~object ~type] [& _#] (quote ~method)))
+           specs))))
+
+(defmacro
+  #^{:doc
+      "Builder macro is used for constructing large compositions of Java object,
+       while it duplicates some of functionality of `doto` and `new` it is not
+       ment as there replacement, use them when contruction one object at the time.
+
+       Builder works like `doto`, but adds features that make calling Java APIs
+       more natural inside your Clojure code.
+
+       Example 1, removing duplicate method calls:
+         (import '(java.util TreeMap))
+
+         (=> (TreeMap.)
+           (put+
+             [\"key1\" \"value1\"]
+             [\"key2\" \"value2\"]))
+
+       Example 2, setters as keyword arguments:
+         (import '(javax.swing JFrame))
+
+         (=> (JFrame. \"Example\")
+           :DefaultCloseOperation JFrame/EXIT_ON_CLOSE
+           :Size [800 600])
+
+       Example 3, replacing method calls with Clojure literals:
+         (default-method
+           (JFrame :string setTitle
+                   :vector add))
+         (=> (JFrame.)
+           \"Example\"
+           :Layout (BorderLayour.)
+           [[(JButton. \"Button1\") BorderLayout/WEST]
+            [(JButton. \"Button2\") BorderLayout/EAST]])
+
+       Example 4, alternative object contructors:
+        (defmethod ctor JButton [object & args]
+          ...); Your implementation
+
+        (=> [JButton \"&Button [ctrl b]\"]
+          ..)
+
+       Example 5, method shadowing or injection of new methods:
+        (defmethod patch [JFrame 'setDefaultCloseOperation] [o _ & [op]]
+          (if (= op :exit-on-close)
+            (.setDefaultCloseOperation o JFrame/EXIT_ON_CLOSE)
+            (.setDefaultCloseOperation o op)))
+
+        (=> (JFrame. \"Example\")
+          :DefaultCloseOperation :exit-on-close)
+
+       See also: (doc default-method)"}
+  => [x & members]
+  (let [gx (gensym)
+        x  `(*ctor* ~x)
+        map-dm (gensym)
+        vec-dm (gensym)
+        str-dm (gensym)]
+    `(let [~gx ~x
+           ~map-dm (default-method* ~gx :map)
+           ~vec-dm (default-method* ~gx :vector)
+           ~str-dm (default-method* ~gx :string)]
+      ~@(loop [[m & ms :as mx] members, p []]
+          (if (seq mx)
+            (cond
+              (= '>> m)
+               (let [[_ expr & ms] mx]
+                 (recur ms (conj p `(~(first expr) ~gx ~@(rest expr)))))
+              (keyword? m)
+                (let [[_ val & ms] mx]
+                  (recur ms (conj p `(patch ~gx '~(symbol (str "set" (name m))) ~val))))
+              (map? m)
+                (recur ms (conj p `(patch ~gx ~map-dm ~m)))
+              (vector? m)
+                (recur ms (concat p (map #(do `(patch ~gx ~vec-dm ~@(if (vector? %) % (list %)))) m)))
+              (string? m)
+                (recur ms (conj p `(patch ~gx ~str-dm ~m)))
+              :else
+                (let [[mf & mr] m]
+                  (if (= (last (name mf)) \+)
+                    (let [mf (symbol (apply str (butlast (name mf))))]
+                      (recur
+                        ms
+                        (concat p (map #(do `(patch ~gx '~mf ~@(if (vector? %) % (list %)))) mr))))
+                    (recur ms (conj p `(patch ~gx '~mf ~@mr))))))
+            p))
+      ~gx)))
+
+(defn builder? [form]
+  (and (seq? form) (= (first form) '=>))); TODO; watch for =>
+
+(defn name? [form]
+  (and (seq? form) (= (first form) 'clojure.core/unquote)))
+
+(defn named? [form]
+  (and (builder? form) (name? (second form))))
+
+;(defn get-name [form]
+;  (if (and (builder? form) (name? (second form)))
+;    (let [[sym [_ id] expr & members] form]
+;      [(concat (list sym id) members) [id expr]])
+;    [form nil]))
+
+;(defn walk [form]
+;  (if (coll? form)
+;    (let [res     (map walk form)
+;          newform (map first res)
+;          names   (filter (complement nil?) (mapcat second res))]
+;      (cond
+;        (seq? form)
+;          (let [[newform name] (get-name newform)]
+;            [newform (concat name names)])
+;        (vector? form)
+;          [(vec newform) names]
+;        (coll? form)
+;          [(into (empty form) newform) names]))
+;    [form nil]))
+
+(defn walk [form]
+  (if (coll? form)
+    (let [res     (map walk form)
+          newform (map first res)
+          names   (filter (complement nil?) (mapcat second res))]
+      (cond
+        (named? form)
+          (let [[sym [_ id] expr & members] newform]
+            [(concat (list sym id) members) (concat [id expr] names)])
+        (seq? form)
+          [newform names]
+        (vector? form)
+          [(vec newform) names]
+        (coll? form)
+          [(into (empty form) newform) names]))
+    [form nil]))
+
+    
+(println "?????"
+(walk
+  '(=> ~frame (JFrame.)
+     (add (=> ~jj (J.)))
+     #{(=> ~x1 (JButton.))}
+     {:a1 (=> ~x2 (JButton.))
+      :a2 (=> ~x3 (JButton.))}
+     [(=> ~b1 (JButton.)
+        [(=> ~z (JX.))])
+      (=> ~b2 (JButton.))])))
+
+(defmacro
+  #^{:doc
+      ""}
+  build
+  ([expr]
+    `(build :toplevel expr))
+  ([result expr]
+    ~expr))

File neman/json/docs/style.css

+body {
+    margin: 10px 50px;
+    font-family: Arial;
+}
+
+h1 {
+    /*text-align: center;*/
+    font-size: 1.6em;
+}
+
+a {
+    color: #215A6D;
+}
+
+p {
+    letter-spacing: 0.2px;
+    line-height: 1.5em;
+}
+
+.notice {
+    padding: 3px;
+    background-color: #CCCCCC;
+    border-left: 4px solid black;
+    font-size: 0.8em;
+}
+
+pre {
+    padding: 5px;
+    background-color: #FFFFF5;
+    border-top: 1px solid #CDDAD9;
+    border-bottom: 1px solid #CDDAD9;
+    border-left: 4px solid orange;
+    line-height: 1.4em;
+}
+
+code {
+    background-color: #EBF7F6;
+    padding: 2px;
+}
+
+.tags {
+    clear: both;
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol {
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol li {
+    list-style: none;
+    display: inline;
+}
+
+.note {
+    border: 1px dashed #282828;
+    background-color: #ECF2F3;
+    padding: 10px;
+}
+
+.pagetitle {
+    font-size: 2.3em;
+    font-weight: bold;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+    border: 1px solid #C72545;
+}
+
+th {
+    color: white;
+    background-color: #C72545;
+    text-align: left;
+    font-family: Monospace;
+    font-weight: normal;
+    padding: 2px;
+}
+
+td {
+    padding: 4px;
+}
+
+tr.odd {
+    background-color: #f8f8f8;
+}

File neman/json/examples/json1.clj

+;; Copyright (c) 2008 Krešimir Šojat. All rights reserved.  The use and
+;; distribution terms for this software are covered by the Common
+;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
+;; which can be found in the file CPL.TXT at the root of this
+;; distribution.  By using this software in any fashion, you are
+;; agreeing to be bound by the terms of this license.  You must not
+;; remove this notice, or any other, from this software.
+
+(ns user
+  (:require [net.ksojat.neman.json :as json]))
+
+(json/write-file "json1-1.json"
+  {:one   1
+   :two   "two"
+   :three [1 2 3]})
+
+(defstruct json-output
+  :first :second :third)
+
+(json/write-file "json1-2.json"
+  (struct-map json-output
+    :first  [1 2 {:a 1 :b 2}]
+    :second false
+    :third  {:a "b" :c "d"}))

File neman/swing/docs/style.css

+body {
+    margin: 10px 50px;
+    font-family: Arial;
+}
+
+h1 {
+    /*text-align: center;*/
+    font-size: 1.6em;
+}
+
+a {
+    color: #215A6D;
+}
+
+p {
+    letter-spacing: 0.2px;
+    line-height: 1.5em;
+}
+
+.notice {
+    padding: 3px;
+    background-color: #CCCCCC;
+    border-left: 4px solid black;
+    font-size: 0.8em;
+}
+
+pre {
+    padding: 5px;
+    background-color: #FFFFF5;
+    border-top: 1px solid #CDDAD9;
+    border-bottom: 1px solid #CDDAD9;
+    border-left: 4px solid orange;
+    line-height: 1.4em;
+}
+
+code {
+    background-color: #EBF7F6;
+    padding: 2px;
+}
+
+.tags {
+    clear: both;
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol {
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol li {
+    list-style: none;
+    display: inline;
+}
+
+.note {
+    border: 1px dashed #282828;
+    background-color: #ECF2F3;
+    padding: 10px;
+}
+
+.pagetitle {
+    font-size: 2.3em;
+    font-weight: bold;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+    border: 1px solid #C72545;
+}
+
+th {
+    color: white;
+    background-color: #C72545;
+    text-align: left;
+    font-family: Monospace;
+    font-weight: normal;
+    padding: 2px;
+}
+
+td {
+    padding: 4px;
+}
+
+tr.odd {
+    background-color: #f8f8f8;
+}

File neman/utils/docs/style.css

+body {
+    margin: 10px 50px;
+    font-family: Arial;
+}
+
+h1 {
+    /*text-align: center;*/
+    font-size: 1.6em;
+}
+
+a {
+    color: #215A6D;
+}
+
+p {
+    letter-spacing: 0.2px;
+    line-height: 1.5em;
+}
+
+.notice {
+    padding: 3px;
+    background-color: #CCCCCC;
+    border-left: 4px solid black;
+    font-size: 0.8em;
+}
+
+pre {
+    padding: 5px;
+    background-color: #FFFFF5;
+    border-top: 1px solid #CDDAD9;
+    border-bottom: 1px solid #CDDAD9;
+    border-left: 4px solid orange;
+    line-height: 1.4em;
+}
+
+code {
+    background-color: #EBF7F6;
+    padding: 2px;
+}
+
+.tags {
+    clear: both;
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol {
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol li {
+    list-style: none;
+    display: inline;
+}
+
+.note {
+    border: 1px dashed #282828;
+    background-color: #ECF2F3;
+    padding: 10px;
+}
+
+.pagetitle {
+    font-size: 2.3em;
+    font-weight: bold;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+    border: 1px solid #C72545;
+}
+
+th {
+    color: white;
+    background-color: #C72545;
+    text-align: left;
+    font-family: Monospace;
+    font-weight: normal;
+    padding: 2px;
+}
+
+td {
+    padding: 4px;
+}
+
+tr.odd {
+    background-color: #f8f8f8;
+}

File neman/web/docs/style.css

+body {
+    margin: 10px 50px;
+    font-family: Arial;
+}
+
+h1 {
+    /*text-align: center;*/
+    font-size: 1.6em;
+}
+
+a {
+    color: #215A6D;
+}
+
+p {
+    letter-spacing: 0.2px;
+    line-height: 1.5em;
+}
+
+.notice {
+    padding: 3px;
+    background-color: #CCCCCC;
+    border-left: 4px solid black;
+    font-size: 0.8em;
+}
+
+pre {
+    padding: 5px;
+    background-color: #FFFFF5;
+    border-top: 1px solid #CDDAD9;
+    border-bottom: 1px solid #CDDAD9;
+    border-left: 4px solid orange;
+    line-height: 1.4em;
+}
+
+code {
+    background-color: #EBF7F6;
+    padding: 2px;
+}
+
+.tags {
+    clear: both;
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol {
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol li {
+    list-style: none;
+    display: inline;
+}
+
+.note {
+    border: 1px dashed #282828;
+    background-color: #ECF2F3;
+    padding: 10px;
+}
+
+.pagetitle {
+    font-size: 2.3em;
+    font-weight: bold;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+    border: 1px solid #C72545;
+}
+
+th {
+    color: white;
+    background-color: #C72545;
+    text-align: left;
+    font-family: Monospace;
+    font-weight: normal;
+    padding: 2px;
+}
+
+td {
+    padding: 4px;
+}
+
+tr.odd {
+    background-color: #f8f8f8;
+}

File neman/webapps/docs/style.css

+body {
+    margin: 10px 50px;
+    font-family: Arial;
+}
+
+h1 {
+    /*text-align: center;*/
+    font-size: 1.6em;
+}
+
+a {
+    color: #215A6D;
+}
+
+p {
+    letter-spacing: 0.2px;
+    line-height: 1.5em;
+}
+
+.notice {
+    padding: 3px;
+    background-color: #CCCCCC;
+    border-left: 4px solid black;
+    font-size: 0.8em;
+}
+
+pre {
+    padding: 5px;
+    background-color: #FFFFF5;
+    border-top: 1px solid #CDDAD9;
+    border-bottom: 1px solid #CDDAD9;
+    border-left: 4px solid orange;
+    line-height: 1.4em;
+}
+
+code {
+    background-color: #EBF7F6;
+    padding: 2px;
+}
+
+.tags {
+    clear: both;
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol {
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol li {
+    list-style: none;
+    display: inline;
+}
+
+.note {
+    border: 1px dashed #282828;
+    background-color: #ECF2F3;
+    padding: 10px;
+}
+
+.pagetitle {
+    font-size: 2.3em;
+    font-weight: bold;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+    border: 1px solid #C72545;
+}
+
+th {
+    color: white;
+    background-color: #C72545;
+    text-align: left;
+    font-family: Monospace;
+    font-weight: normal;
+    padding: 2px;
+}
+
+td {
+    padding: 4px;
+}
+
+tr.odd {
+    background-color: #f8f8f8;
+}

File neman/xml/docs/style.css

+body {
+    margin: 10px 50px;
+    font-family: Arial;
+}
+
+h1 {
+    /*text-align: center;*/
+    font-size: 1.6em;
+}
+
+a {
+    color: #215A6D;
+}
+
+p {
+    letter-spacing: 0.2px;
+    line-height: 1.5em;
+}
+
+.notice {
+    padding: 3px;
+    background-color: #CCCCCC;
+    border-left: 4px solid black;
+    font-size: 0.8em;
+}
+
+pre {
+    padding: 5px;
+    background-color: #FFFFF5;
+    border-top: 1px solid #CDDAD9;
+    border-bottom: 1px solid #CDDAD9;
+    border-left: 4px solid orange;
+    line-height: 1.4em;
+}
+
+code {
+    background-color: #EBF7F6;
+    padding: 2px;
+}
+
+.tags {
+    clear: both;
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol {
+    display: inline;
+    margin: 0; padding: 0;
+}
+
+.tags + ol li {
+    list-style: none;
+    display: inline;
+}
+
+.note {
+    border: 1px dashed #282828;
+    background-color: #ECF2F3;
+    padding: 10px;
+}
+
+.pagetitle {
+    font-size: 2.3em;
+    font-weight: bold;
+}
+
+table {
+    border-spacing: 0;
+    border-collapse: collapse;
+    border: 1px solid #C72545;
+}
+
+th {
+    color: white;
+    background-color: #C72545;
+    text-align: left;
+    font-family: Monospace;
+    font-weight: normal;
+    padding: 2px;
+}
+
+td {
+    padding: 4px;
+}
+
+tr.odd {
+    background-color: #f8f8f8;
+}

File neman/xml/docs/xml.textile

+h1. XML and XML templates
+
+Neman XML library is thin wrapper around "JDOM":http://www.jdom.org/ using builder macro for DOM construction. This way you don't loose any capabilities of original JDOM API.
+
+pre.. 
+ (ns user
+   (:use
+     (net.ksojat.neman
+       core
+       [xml :only [xml]])))
+
+ (def simple-html-page
+   (xml
+     (=> :html
+       [(=> :head [(=> :title "Hello World!")])
+        (=> :body
+          [(=> :h1 "Hello World!")
+           (=> :p  "Example paragraph.")])])))
+
+p. Default methods for JDOM classes:
+|_.Class|_.Method|_.Default|
+(odd).|org.jdom.Document|setDocType|:string|
+(even).|org.jdom.Element|addContent|:vector|
+(odd).|org.jdom.Element|addContent|:string|
+(even).|org.jdom.Element|setAttributes|:map|
+
+p. Patched methods for JDOM classes:
+|_.Class|_.Method|_.Description|
+(odd).|org.jdom.Document|setDocType|Accepts @org.jdom.DocType@ or regular @java.lang.String@|
+(even).|org.jdom.Element|setAttributes|*TODO*|
+(odd).|org.jdom.Element|addContent|Accepts @java.util.List@ of @org.jdom.Content@ objects, single @org.jdom.Content@ object or anything that can be converted to String (it will be inserted as text node).|
+

File neman/xml/examples/xml1.clj

+;; Copyright (c) 2008 Krešimir Šojat. All rights reserved.  The use and
+;; distribution terms for this software are covered by the Common
+;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
+;; which can be found in the file CPL.TXT at the root of this
+;; distribution.  By using this software in any fashion, you are
+;; agreeing to be bound by the terms of this license.  You must not
+;; remove this notice, or any other, from this software.
+
+(ns user
+  (:require net.ksojat.neman.xml)
+  (:use net.ksojat.neman.core [net.ksojat.neman.xml :only [xml]])
+  (:import (org.jdom.output XMLOutputter)))
+
+(def html-doc
+  (xml
+    (=> :html
+      [(=> :head)
+       (=> :body
+         {:class "klass" :id "main"}
+         [(=> :p "Just some text.")])])))
+
+(.output (XMLOutputter.) html-doc System/out)

File neman/xml/examples/xml2.clj

+;; Copyright (c) 2008 Krešimir Šojat. All rights reserved.  The use and
+;; distribution terms for this software are covered by the Common
+;; Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
+;; which can be found in the file CPL.TXT at the root of this
+;; distribution.  By using this software in any fashion, you are
+;; agreeing to be bound by the terms of this license.  You must not
+;; remove this notice, or any other, from this software.
+
+(ns user
+  (:use net.ksojat.neman.core [net.ksojat.neman.xml :only [render template template-from child]])
+  (:import (org.jdom.output XMLOutputter)))
+
+(def base
+  (template [title message]
+    (=> :html
+      [(=> :head
+         [(=> :title [title])])
+       (=> :body
+         [(=> :h1 [title])
+          (child :body)
+          (=> :p [message])
+          (child :extra)])])))
+
+(def level1
+  (template-from base
+    (:body
+      (=> :h2 "Second Header")
+      (for [i (range 5)]
+        (=> :p [(str "Generated " i)]))
+      (=> :div
+        [(child :body) (=> :p "Extra")]))
+    (:extra
+      (=> :div "ExtraDivTag"))))
+
+(def level2
+  (template-from level1
+    (:body
+      (=> :p "ExtraDva"))))
+
+(render level2 {:title "Naslov" :message "Poruka"})

File neman/xml/examples/xml3.clj

+(ns user
+  (:use
+    (net.ksojat.neman
+      core
+      [web :only [url-for url-for-path *current-path*]]
+      [xml :only [render xml xml-node xml-nodes template template-from child]])))
+
+
+;(def baseh
+;  (template
+;    (=> :html
+;      [(=>> (:head [(child :head) (child :css)])
+;            (:body [(child :body) (child :js)]))])))
+
+(def baseh
+  (template
+    (=> :html
+      [(=> :head [(child :head) (child :css)])
+       (=> :body [(child :body) (child :js)])])))
+
+
+(def base
+  (template-from baseh
+    (:head
+      (=> :meta {:http-equiv "Content-Type" :content "text/html; charset=utf-8"})
+      (=> :title "Hatchery Alpha")
+      ;(shortcut-icon "media/favicon.png")
+      (child :head))
+    (:css
+      (child :css))
+    (:js
+      (child :js))
+    (:body
+      (=> :div {:id "main"}
+        [(=> :div {:id "header" :class "fluid"}
+           [(=> :h1 "Hatchery")
+            (=> :p "Experiments in Genetic Algorithms, Procedural Graphics and Functional Languages")])
+         (child :body)])
+
+      (=> :div {:id "footer"}
+        "&copy; 2008.  Kre\u0161imir \u0160ojat. All right reserved."))))
+
+;(def base2
+;  (template-from base
+;    (:body
+;      (=> :div.fluid#nav
+;        [(=> :form.search
+;           [(=>> (:label {:for "search"} "Search")
+;                 (:input.search {:type "text" :name "search"})
+;                 (:input {:type "submit" :value "Go"}))])
+;         (=> :div {:class "clear"})])
+;      (=> :div [(child :body)]))))
+
+;(def index-template
+;  (template-from baseh
+;    (:body
+;      (=> :a))))
+
+(render base)

File oldbuild.xml

-<!--
-  Copyright (c) 2008 Krešimir Šojat. All rights reserved.  The use and
-  distribution terms for this software are covered by the Common
-  Public License 1.0 (http://www.opensource.org/licenses/cpl1.0.php)
-  which can be found in the file CPL.TXT at the root of this
-  distribution.  By using this software in any fashion, you are
-  agreeing to be bound by the terms of this license.  You must not
-  remove this notice, or any other, from this software.
--->
-<project name='neman' basedir='.' xmlns:ivy='antlib:org.apache.ivy.ant'>
-
-    <import file='${basedir}/common.xml'/>
-    <import file='${common.dir}/common.xml' optional='true'/>
-
-    <property name='build.classes' location='${build}/classes'/>
-    <property name='build.jar'     location='${build}/neman.jar'/>
-
-    <!--
-    Neman targets.
-    -->
-
-    <target name='resolve' depends='ivy-install' unless='skip.resolve'>
-        <ivy:settings file='${basedir}/ivysettings.xml'/>
-        <ivy:resolve file='${basedir}/ivy.xml'/>
-        <ivy:retrieve/>
-    </target>
-
-    <target name='build' depends='resolve, build-docs'>
-        <mkdir dir='${build.classes}'/>
-
-        <path id='clojure.compiler.classpath'>
-            <fileset dir='${lib}'>
-                <include name='**/*.jar'/>
-            </fileset>
-        </path>
-
-        <java classname='clojure.lang.Compile'
-            classpath='${build.classes}:${src}'
-            classpathref='clojure.compiler.classpath'>
-            <sysproperty key='clojure.compile.path' value='${build.classes}'/>
-            <arg value='net.ksojat.neman.cli'/>
-            <arg value='net.ksojat.neman.core'/>
-            <arg value='net.ksojat.neman.jetty'/>
-            <arg value='net.ksojat.neman.json'/>
-            <arg value='net.ksojat.neman.web'/>
-            <arg value='net.ksojat.neman.xml'/>
-            <arg value='net.ksojat.neman.storage'/>
-            <arg value='net.ksojat.neman.textile'/>
-            <arg value='net.ksojat.neman.css'/>
-            <arg value='net.ksojat.neman.cells'/>
-	    <arg value='net.ksojat.neman.swing'/>
-        </java>
-
-        <jar destfile='${build.jar}'>
-            <zipfileset dir='${build.classes}'/>
-        </jar>
-
-    </target>
-
-    <target name='dist' depends='dist-docs'/>
-
-    <target name='publish' depends='build'>
-        <ivy:publish
-            forcedeliver='true'
-            overwrite='true'
-            resolver='neman'
-            status='release'
-            pubrevision='0.0.1'
-            artifactspattern='${build}/[artifact].[ext]'/>
-    </target>
-
-    <target name='test' depends='build'>
-        <path id='test.classpath'>
-            <fileset dir='${lib}'>
-                <include name='**/*.jar'/>
-            </fileset>
-        </path>
-
-        <clojure
-            file='${test}/test.clj'
-            classpath='${build.classes}:${src}'
-            classpathref='test.classpath'/>
-    </target>
-</project>
             </fileset>
         </path>
 
+        <javac srcdir='${src}' destdir='${target.classes}' classpathref='clojure.compile.classpath'/>
         <clojurec srcdir='${src}' destdir='${target.classes}' classpathref='clojure.compile.classpath'/>
 
+        <!-- TODO: Get textilej back and add docs generation. -->
+
         <jar destfile='${target.jar}'>
             <zipfileset dir='${target.classes}'/>
             <zipfileset dir='${target.resources}'/>
     </target>
 
     <target name='test'>
+        <!-- TODO: Create test target -->
     </target>
 
     <target name='clean'>