Skip to content

Commit

Permalink
move middleware to carica.middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
leathekd committed Aug 13, 2015
1 parent 6d4b7ff commit d85ac6d
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 133 deletions.
104 changes: 15 additions & 89 deletions src/carica/core.clj
@@ -1,6 +1,7 @@
(ns carica.core
(:use [clojure.java.io :only [reader input-stream] :as io])
(:require [clojure.tools.logging :as log]
(:require [carica.middleware :as mw]
[clojure.java.io :as io]
[clojure.tools.logging :as log]
[clojure.tools.reader :as clj-reader]
[clojure.tools.reader.edn :as edn]
[clojure.tools.reader.reader-types :as readers]
Expand Down Expand Up @@ -41,7 +42,7 @@

(defn load-with [resource loader]
(try
(-> resource input-stream readers/input-stream-push-back-reader loader)
(-> resource io/input-stream readers/input-stream-push-back-reader loader)
(catch Throwable t
(log/warn t "error reading config" resource)
(throw
Expand All @@ -66,7 +67,7 @@

(defmethod load-config :carica/json [resource]
(with-open [s (.openStream resource)]
(-> s reader (json-parse-stream true))))
(-> s io/reader (json-parse-stream true))))

(derive :carica/clj :carica/edn)

Expand Down Expand Up @@ -104,74 +105,6 @@
n))
resources))

(defn get-config-fn
"Retrieve the wrapped fn from the middleware, or return f if
it isn't wrapped."
[f]
{:post [f]}
(if (map? f)
(:carica/fn f)
f))

(defn get-options
"Retrieve the exposed options from the wrapped middleware, or return
{} if the middleware isn't wrapped."
[f]
{:post [f]}
(if (map? f)
(:carica/options f)
{}))

(defn unwrap-middleware-fn
"Convenience function for pulling the fn and options out of the
wrapped middleware. It's easier to destructure a seq than a map
with namespaced keys."
[f]
[(get-config-fn f) (get-options f)])

(defn wrap-middleware-fn
"Take the passed function and an optional map of options and return
the wrapped middleware map that the rest of the code expects to
use."
[f & [opt-map]]
{:carica/options (or opt-map {})
:carica/fn f})

(defn eval-config
"Config middleware that will evaluate the config map. This allows
arbitrary code to live in the config file. It is often useful for
coercing config values to a particular type."
[f]
(fn [resources]
(let [cfg-map (f resources)]
(try
(eval cfg-map)
(catch Throwable t
(log/warn t "error evaling config" cfg-map)
(throw
(Exception. (str "error evaling config " cfg-map) t)))))))

(defn cache-config
"Config middleware that will cache the config map so that it is
loaded only once."
[f]
(let [mem (atom {})]
(wrap-middleware-fn
(fn [resources]
(if-let [e (find @mem resources)]
(val e)
(let [ret (f resources)]
(swap! mem assoc resources ret)
ret)))
{:carica/mem mem})))

(defn clear-config-cache!
"Clear the cached config. If a custom config function has been
defined, it must be passed in."
[& [config-fn]]
(when ((or config-fn config) :carica/middleware :carica/mem)
(swap! ((or config-fn config) :carica/middleware :carica/mem) empty)))

(defn config*
"Looks up the keys in the maps. If not found, log and return nil."
[m ks]
Expand All @@ -182,20 +115,8 @@

(def default-middleware
"The default list of middleware carica uses."
[eval-config
cache-config])

(defn middleware-compose
"Unwrap and rewrap the function and middleware. Used in a reduce to
create the actual config funtion that is eventually called to fetch
the values from the config map."
[f mw]
(let [[f-fn f-opts] (unwrap-middleware-fn f)
[mw-fn mw-opts] (unwrap-middleware-fn mw)
;; mw-fn might return wrapped mw, so pull *it* apart as well
[new-f-fn new-f-opts] (unwrap-middleware-fn (mw-fn f-fn))]
(wrap-middleware-fn new-f-fn
(merge f-opts mw-opts new-f-opts))))
[mw/eval-config
mw/cache-config])

(defn configurer
"Given a the list of resources in the format expected by get-configs,
Expand All @@ -212,9 +133,9 @@
(configurer resources default-middleware))
([resources middleware]
(let [[config-fn options]
(unwrap-middleware-fn
(reduce middleware-compose
(wrap-middleware-fn get-configs)
(mw/unwrap-middleware-fn
(reduce mw/middleware-compose
(mw/wrap-middleware-fn get-configs)
middleware))]
(fn [& ks]
(if (= (first ks) :carica/middleware)
Expand Down Expand Up @@ -272,3 +193,8 @@
E.g.,
(with-redefs [config (override-config nil)])"
(overrider config))

;; for backwards compatibility
(def eval-config mw/eval-config)
(def cache-config mw/cache-config)
(def clear-config-cache! mw/clear-config-cache!)
84 changes: 84 additions & 0 deletions src/carica/middleware.clj
@@ -0,0 +1,84 @@
(ns carica.middleware
(:require [clojure.tools.logging :as log]))

(defn get-config-fn
"Retrieve the wrapped fn from the middleware, or return f if
it isn't wrapped."
[f]
{:post [f]}
(if (map? f)
(:carica/fn f)
f))

(defn get-options
"Retrieve the exposed options from the wrapped middleware, or return
{} if the middleware isn't wrapped."
[f]
{:post [f]}
(if (map? f)
(:carica/options f)
{}))

(defn unwrap-middleware-fn
"Convenience function for pulling the fn and options out of the
wrapped middleware. It's easier to destructure a seq than a map
with namespaced keys."
[f]
[(get-config-fn f) (get-options f)])

(defn wrap-middleware-fn
"Take the passed function and an optional map of options and return
the wrapped middleware map that the rest of the code expects to
use."
[f & [opt-map]]
{:carica/options (or opt-map {})
:carica/fn f})

(defn middleware-compose
"Unwrap and rewrap the function and middleware. Used in a reduce to
create the actual config funtion that is eventually called to fetch
the values from the config map."
[f mw]
(let [[f-fn f-opts] (unwrap-middleware-fn f)
[mw-fn mw-opts] (unwrap-middleware-fn mw)
;; mw-fn might return wrapped mw, so pull *it* apart as well
[new-f-fn new-f-opts] (unwrap-middleware-fn (mw-fn f-fn))]
(wrap-middleware-fn new-f-fn
(merge f-opts mw-opts new-f-opts))))

(defn eval-config
"Config middleware that will evaluate the config map. This allows
arbitrary code to live in the config file. It is often useful for
coercing config values to a particular type."
[f]
(fn [resources]
(let [cfg-map (f resources)]
(try
(eval cfg-map)
(catch Throwable t
(log/warn t "error evaling config" cfg-map)
(throw
(Exception. (str "error evaling config " cfg-map) t)))))))

(defn cache-config
"Config middleware that will cache the config map so that it is
loaded only once."
[f]
(let [mem (atom {})]
(wrap-middleware-fn
(fn [resources]
(if-let [e (find @mem resources)]
(val e)
(let [ret (f resources)]
(swap! mem assoc resources ret)
ret)))
{:carica/mem mem})))

(defn clear-config-cache!
"Clear the cached config. If a custom config function has been
defined, it must be passed in."
[& [config-fn]]
(let [config-fn (or config-fn (ns-resolve 'carica.core 'config))]
(when (config-fn :carica/middleware :carica/mem)
(swap! (config-fn :carica/middleware :carica/mem) empty))))

44 changes: 0 additions & 44 deletions test/carica/test/core.clj
Expand Up @@ -71,50 +71,6 @@
(is (= (get-configs [(resources "config.clj")])
(get-configs [nil (resources "config.clj") nil [nil nil]]))))

(deftest test-middleware
(let [call-count (atom 0)
call-mdlware (fn [f]
(fn [resources]
(swap! call-count inc)
(f resources)))
empty-cfg (configurer (resources "config.clj") [])
mdlware-cfg (configurer (resources "config.clj")
[call-mdlware])
cached-cfg (configurer (resources "config.clj")
[call-mdlware cache-config])
eval-cfg (configurer (resources "config.clj")
[eval-config])]
(testing "General middleware"
(is (= true (empty-cfg :from-test)))
(is (= 0 @call-count))
(is (= true (mdlware-cfg :from-test)))
(is (= 1 @call-count)))
(testing "Caching works"
(is (= true (cached-cfg :from-test)))
(is (= true (cached-cfg :from-test)))
(is (= 2 @call-count)))
(testing "Eval works"
(is (= '(+ 1 1) (empty-cfg :eval-cfg)))
(is (= 2 (eval-cfg :eval-cfg))))))

(deftest test-wrap-middleware
(let [call-count (atom 0)
call-mdlware (fn [f]
(fn [resources]
(swap! call-count inc)
(f resources)))
cached-cfg (configurer (resources "config.clj")
[call-mdlware cache-config])
eval-cfg (configurer (resources "config.clj")
[eval-config])]
(testing "Resetting cache works"
(is (= true (cached-cfg :from-test)))
(is (= true (cached-cfg :from-test)))
(is (= 1 @call-count))
(clear-config-cache! cached-cfg)
(is (= true (cached-cfg :from-test)))
(is (= 2 @call-count)))))

(deftest test-edn-config
(is (= "test-edn" (config :test-edn))))

Expand Down
49 changes: 49 additions & 0 deletions test/carica/test/middleware.clj
@@ -0,0 +1,49 @@
(ns carica.test.middleware
(:require [carica.core :refer [configurer resources config]]
[carica.middleware :refer :all]
[clojure.test :refer :all]
[clojure.tools.logging.impl :refer [write!]]))

(deftest test-middleware
(let [call-count (atom 0)
call-mdlware (fn [f]
(fn [resources]
(swap! call-count inc)
(f resources)))
empty-cfg (configurer (resources "config.clj") [])
mdlware-cfg (configurer (resources "config.clj")
[call-mdlware])
cached-cfg (configurer (resources "config.clj")
[call-mdlware cache-config])
eval-cfg (configurer (resources "config.clj")
[eval-config])]
(testing "General middleware"
(is (= true (empty-cfg :from-test)))
(is (= 0 @call-count))
(is (= true (mdlware-cfg :from-test)))
(is (= 1 @call-count)))
(testing "Caching works"
(is (= true (cached-cfg :from-test)))
(is (= true (cached-cfg :from-test)))
(is (= 2 @call-count)))
(testing "Eval works"
(is (= '(+ 1 1) (empty-cfg :eval-cfg)))
(is (= 2 (eval-cfg :eval-cfg))))))

(deftest test-wrap-middleware
(let [call-count (atom 0)
call-mdlware (fn [f]
(fn [resources]
(swap! call-count inc)
(f resources)))
cached-cfg (configurer (resources "config.clj")
[call-mdlware cache-config])
eval-cfg (configurer (resources "config.clj")
[eval-config])]
(testing "Resetting cache works"
(is (= true (cached-cfg :from-test)))
(is (= true (cached-cfg :from-test)))
(is (= 1 @call-count))
(clear-config-cache! cached-cfg)
(is (= true (cached-cfg :from-test)))
(is (= 2 @call-count)))))

0 comments on commit d85ac6d

Please sign in to comment.