Permalink
Browse files

add: Initial working commit.

  • Loading branch information...
0 parents commit c9cacad2607a6a26f104ddb8deb42278f2841595 @gf3 committed Dec 27, 2011
Showing with 163 additions and 0 deletions.
  1. +8 −0 .gitignore
  2. +57 −0 README.md
  3. +8 −0 project.clj
  4. +16 −0 spec/ring-cssgen/core_spec.clj
  5. +74 −0 src/ring_cssgen/core.clj
@@ -0,0 +1,8 @@
+/pom.xml
+*jar
+/lib
+/classes
+/native
+/.lein-failures
+/checkouts
+/.lein-deps-sum
@@ -0,0 +1,57 @@
+ring-cssgen
+===========
+
+[Ring][ring] middleware to automatically compile and regenerate your [cssgen][cssgen] stylesheets. Works well with Compojure and Noir. Very much sttill an alpha.
+
+
+Installation
+------------
+
+**Soon** you'll be able to add the following to your `project.clj`:
+
+``` clojure
+ :dependencies [[ring-cssgen "0.0.1"]]
+```
+
+
+Usage
+-----
+
+First off, create your cssgen stylesheets and throw them in a common namespace, something like `yourapp.css` works well. Here's the important part, be sure to return your cssgen from the `-main` function.
+
+``` clojure
+(ns yourapp.css.design
+ (:use cssgen))
+
+(defn -main []
+ (css
+ [:body
+ :color "blue"]))
+```
+
+Now you can use `load-css-ns` to register your stylesheet namespaces and return
+your middleware function. `load-css-ns` takes a namespace prefix which it will
+use to find all your stylsheet namespaces, it returns a Vector Atom of the
+registered namespaces and the middleware handler. Wherever you're starting your
+server, you'll need to pass in the middleware function.
+
+``` clojure
+(ns yourapp.server
+ (:use [ring-cssgen.core :only [load-css-ns]]))
+
+(let [[css-ns wrap-cssgen] (load-css-ns 'yourapp.css)]
+ (server/add-middleware wrap-cssgen))
+
+; start your server with wrap-cssgen
+```
+Boom! Did you are unimpressed?
+
+
+License
+-------
+
+ring-cssgen is distributed under the Eclipse Public License, the same as Clojure.
+
+[ring]:https://github.com/mmcgrana/ring
+[cssgen]:https://github.com/paraseba/cssgen/tree/0.3.0
+
@@ -0,0 +1,8 @@
+(defproject ring-cssgen "0.0.1-SNAPSHOT"
+ :description "Ring middleware to automatically regenerate cssgen stylesheets."
+ :dependencies [[org.clojure/clojure "1.2.0"]
+ [org.clojure/tools.namespace "0.1.0"]
+ [cssgen "0.3.0-SNAPSHOT"]]
+ :dev-dependencies [[speclj "1.5.2"]]
+ :test-path "spec/"
+ :main ring-cssgen.core)
@@ -0,0 +1,16 @@
+(ns ring-cssgen.core-spec
+ (:use speclj.core
+ ring-cssgen.core))
+
+(describe "css-ns"
+ (it "should find all matches"
+ (should= 2 (count (css-ns 'ring-cssgen)))))
+
+(describe "load-css-ns")
+
+(describe "add-css-ns")
+
+(describe "generate-css")
+
+(run-specs)
+
@@ -0,0 +1,74 @@
+(ns ring-cssgen.core
+ (:use clojure.tools.namespace
+ [clojure.string :only [join]]))
+
+; <amalloy> anyway, a short-term solution is like...just use an atom. but
+; a long-term solution is probably...realize you don't want to solve this
+; problem
+; <amalloy> (defn dyn-routes [init] (let [a (atom init)] [a (fn [req] (let [current-routes @a] (...)))]))
+; <amalloy> now dyn-routes returns a pair [routes-atom, handler]
+; <amalloy> install the handler wherever you want, and save the atom for later changing
+; <amalloy> but *really* it would be more composable to wrap, not a list of
+; routes, but an underlying handler. maybe that handler is just some routes,
+; maybe it's something else. just hold whatever it is in an atom, and swap that
+; out with something different later
+
+; TODO: Use java.io.File.separatorChar
+(defn- namespace-to-file [ans]
+ (str
+ "/"
+ (join "/"
+ (take-last 2 (-> ans str (.split "\\."))))
+ ".css"))
+
+; TODO: Refactor to allow composition w/ predicate.
+(defn- find-namespaces-with-prefix
+ "Find all namespaces on the classpath which match a given prefix."
+ [ns-prefix]
+ (for [ans (find-namespaces-on-classpath)
+ :let [name (str ans)
+ ns-prefix (str ns-prefix)]
+ :when (.startsWith name ns-prefix)]
+ ans))
+
+; TODO: Provide useful error messages when ns can't be reolved.
+(defn generate-css
+ "Generate a css file for a given namespace."
+ [ans]
+ (require ans)
+ (when-let [thens (find-ns ans)]
+ (when-let [func (ns-resolve thens '-main)]
+ (spit (str (-> (new java.io.File ".") (.getCanonicalPath)) "/resources/public/" (namespace-to-file ans))
+ (func)))))
+
+(defn- handler
+ "Ring middleware handler to compare request URI with registered namespaces for cssgen stylesheets."
+ [namespaces app]
+ (fn [req]
+ (doall
+ (for [ans namespaces
+ :let [ans-filename (namespace-to-file ans)
+ uri (:uri req)]
+ :when (= uri ans-filename)]
+ (do
+ (prn (format "Regenerate CSS: '%s -> %s" ans uri))
+ (generate-css ans))))
+ (app req)))
+
+; TODO: Rename to reflect general nature of function.
+; TODO: Refactor to allow composition w/ predicate.
+(defn css-ns
+ "Provide a list of namespaces as symbols matching a given prefix."
+ [ns-prefix]
+ (find-namespaces-with-prefix ns-prefix))
+
+(defn load-css-ns
+ "Register all gencss stylesheets with a ns prefix. These stylsheets will be regenerated per request"
+ [ns-prefix]
+ (let [a (atom (find-namespaces-with-prefix ns-prefix))] [a (partial handler @a)]))
+
+(defn add-css-ns
+ "Add a namespace to the list of cssgen namespaces to watch for."
+ [namespaces ans]
+ (swap! namespaces conj ans))
+

0 comments on commit c9cacad

Please sign in to comment.