Skip to content

Commit

Permalink
Add ref-resolve as RefLike protocol method
Browse files Browse the repository at this point in the history
This allows implementing "RefThing"s beyond just Ref & RefSet that resolve
in a custom way. For example a RefMap would be like RefSet but would
resolve to a map `{k -> ref}` instead a refs set.

Related to weavejester#63
  • Loading branch information
clyfe committed Jan 8, 2020
1 parent 4078113 commit c306ebd
Showing 1 changed file with 48 additions and 47 deletions.
95 changes: 48 additions & 47 deletions src/integrant/core.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,54 @@
[weavejester.dependency :as dep]))

(defprotocol RefLike
(ref-key [r] "Return the key of the reference."))
(ref-key [r] "Return the key of the reference.")
(ref-resolve [r config resolvef] "Return the resolved value."))

(defrecord Ref [key] RefLike (ref-key [_] key))
(defrecord RefSet [key] RefLike (ref-key [_] key))
(defonce
^{:doc "Return a unique keyword that is derived from an ordered collection of
keywords. The function will return the same keyword for the same collection."
:arglists '([kws])}
composite-keyword
(memoize
(fn [kws]
(let [parts (for [kw kws] (str (namespace kw) "." (name kw)))
prefix (str (str/join "+" parts) "_")
composite (keyword "integrant.composite" (str (gensym prefix)))]
(doseq [kw kws] (derive composite kw))
composite))))

(defn- normalize-key [k]
(if (vector? k) (composite-keyword k) k))

(defn derived-from?
"Return true if a key is derived from candidate keyword or vector of
keywords."
[key candidate]
(let [key (normalize-key key)]
(if (vector? candidate)
(every? #(isa? key %) candidate)
(isa? key candidate))))

(defn find-derived
"Return a seq of all entries in a map, m, where the key is derived from the
a candidate key, k. If there are no matching keys, nil is returned. The
candidate key may be a keyword, or vector of keywords."
[m k]
(seq (filter #(or (= (key %) k) (derived-from? (key %) k)) m)))

(defrecord Ref [key]
RefLike
(ref-key [_] key)
(ref-resolve [_ config resolvef]
(let [[k v] (first (find-derived config key))]
(resolvef k v))))

(defrecord RefSet [key]
RefLike
(ref-key [_] key)
(ref-resolve [_ config resolvef]
(set (for [[k v] (find-derived config key)]
(resolvef k v)))))

(defn- composite-key? [keys]
(and (vector? keys) (every? qualified-keyword? keys)))
Expand Down Expand Up @@ -51,22 +95,6 @@
(defn- depth-search [pred? coll]
(filter pred? (tree-seq coll? seq coll)))

(defonce
^{:doc "Return a unique keyword that is derived from an ordered collection of
keywords. The function will return the same keyword for the same collection."
:arglists '([kws])}
composite-keyword
(memoize
(fn [kws]
(let [parts (for [kw kws] (str (namespace kw) "." (name kw)))
prefix (str (str/join "+" parts) "_")
composite (keyword "integrant.composite" (str (gensym prefix)))]
(doseq [kw kws] (derive composite kw))
composite))))

(defn- normalize-key [k]
(if (vector? k) (composite-keyword k) k))

(defn- ambiguous-key-exception [config key matching-keys]
(ex-info (str "Ambiguous key: " key ". Found multiple candidates: "
(str/join ", " matching-keys))
Expand All @@ -75,22 +103,6 @@
:key key
:matching-keys matching-keys}))

(defn derived-from?
"Return true if a key is derived from candidate keyword or vector of
keywords."
[key candidate]
(let [key (normalize-key key)]
(if (vector? candidate)
(every? #(isa? key %) candidate)
(isa? key candidate))))

(defn find-derived
"Return a seq of all entries in a map, m, where the key is derived from the
a candidate key, k. If there are no matching keys, nil is returned. The
candidate key may be a keyword, or vector of keywords."
[m k]
(seq (filter #(or (= (key %) k) (derived-from? (key %) k)) m)))

(defn find-derived-1
"Return the map entry in a map, m, where the key is derived from the keyword,
k. If there are no matching keys, nil is returned. If there is more than one
Expand Down Expand Up @@ -212,20 +224,9 @@
:config config
:key key}))

(defn- resolve-ref [config resolvef ref]
(let [[k v] (first (find-derived config (ref-key ref)))]
(resolvef k v)))

(defn- resolve-refset [config resolvef refset]
(set (for [[k v] (find-derived config (ref-key refset))]
(resolvef k v))))

(defn- expand-key [config resolvef value]
(walk/postwalk
#(cond
(ref? %) (resolve-ref config resolvef %)
(refset? %) (resolve-refset config resolvef %)
:else %)
#(if (reflike? %) (ref-resolve % config resolvef) %)
value))

(defn- run-exception [system completed remaining f k v t]
Expand Down

0 comments on commit c306ebd

Please sign in to comment.