Clojurescript version working
This commit is contained in:
parent
dcc061413f
commit
9ac06c10d8
1 changed files with 109 additions and 66 deletions
|
|
@ -1,10 +1,23 @@
|
||||||
(ns com.rpl.specter.impl
|
(ns com.rpl.specter.impl
|
||||||
(:use [com.rpl.specter.protocols :only [StructurePath StructureValsPath Collector StructureValsPathComposer comp-paths*]])
|
(:use [com.rpl.specter.protocols :only
|
||||||
(:require [clojure.walk :as walk]
|
[comp-paths*
|
||||||
|
select* transform* collect-val select-full* transform-full*]])
|
||||||
|
(:require [com.rpl.specter.protocols :as p]
|
||||||
|
[clojure.walk :as walk]
|
||||||
[clojure.core.reducers :as r]
|
[clojure.core.reducers :as r]
|
||||||
[clojure.string :as s])
|
[clojure.string :as s])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#?(
|
||||||
|
:clj
|
||||||
|
(defmacro field [obj quoted-field]
|
||||||
|
`(. ~obj ~(second quoted-field)))
|
||||||
|
|
||||||
|
:cljs
|
||||||
|
(defn field [obj field]
|
||||||
|
(aget obj (s/replace (str field) "-" "_")))
|
||||||
|
)
|
||||||
|
|
||||||
#?(
|
#?(
|
||||||
:clj
|
:clj
|
||||||
(do
|
(do
|
||||||
|
|
@ -58,6 +71,12 @@
|
||||||
(defprotocol CoerceTransformFunctions
|
(defprotocol CoerceTransformFunctions
|
||||||
(coerce-path [this]))
|
(coerce-path [this]))
|
||||||
|
|
||||||
|
(defn- seq-contains? [aseq val]
|
||||||
|
(->> aseq
|
||||||
|
(filter (partial = val))
|
||||||
|
empty?
|
||||||
|
not))
|
||||||
|
|
||||||
(defn no-prot-error-str [obj]
|
(defn no-prot-error-str [obj]
|
||||||
(str "Protocol implementation cannot be found for object.
|
(str "Protocol implementation cannot be found for object.
|
||||||
Extending Specter protocols should not be done inline in a deftype definition
|
Extending Specter protocols should not be done inline in a deftype definition
|
||||||
|
|
@ -65,18 +84,16 @@
|
||||||
optimized performance. Instead, you should extend the protocols via an
|
optimized performance. Instead, you should extend the protocols via an
|
||||||
explicit extend-protocol call. \n" obj))
|
explicit extend-protocol call. \n" obj))
|
||||||
|
|
||||||
|
#?(
|
||||||
|
:clj
|
||||||
|
|
||||||
(defn find-protocol-impl! [prot obj]
|
(defn find-protocol-impl! [prot obj]
|
||||||
(let [ret (find-protocol-impl prot obj)]
|
(let [ret (find-protocol-impl prot obj)]
|
||||||
(if (= ret obj)
|
(if (= ret obj)
|
||||||
(throw-illegal (no-prot-error-str obj))
|
(throw-illegal (no-prot-error-str obj))
|
||||||
ret
|
ret
|
||||||
)))
|
)))
|
||||||
|
)
|
||||||
(defn- seq-contains? [aseq val]
|
|
||||||
(->> aseq
|
|
||||||
(filter (partial = val))
|
|
||||||
empty?
|
|
||||||
not))
|
|
||||||
|
|
||||||
#?(
|
#?(
|
||||||
:clj
|
:clj
|
||||||
|
|
@ -94,8 +111,40 @@
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(do
|
||||||
|
(defn structure-path-impl [this]
|
||||||
|
(if (fn? this)
|
||||||
|
;;TODO: this isn't kosher, it uses knowledge of internals of protocols
|
||||||
|
(-> p/StructurePath :impls (get clojure.lang.AFn))
|
||||||
|
(find-protocol-impl! p/StructurePath this)))
|
||||||
|
|
||||||
|
(defn collector-impl [this]
|
||||||
|
(find-protocol-impl! p/Collector this))
|
||||||
|
|
||||||
|
(defn structure-vals-path-impl [this]
|
||||||
|
(find-protocol-impl! p/StructureValsPath this))
|
||||||
|
))
|
||||||
|
|
||||||
|
#?(:cljs
|
||||||
|
(do
|
||||||
|
(defn structure-path-impl [_]
|
||||||
|
{:select* (fn [this structure next-fn] (select* this structure next-fn))
|
||||||
|
:transform* (fn [this structure next-fn] (transform* this structure next-fn))
|
||||||
|
})
|
||||||
|
|
||||||
|
(defn collector-impl [_]
|
||||||
|
{:collect-val (fn [this structure] (collect-val this structure))
|
||||||
|
})
|
||||||
|
|
||||||
|
(defn structure-vals-path-impl [_]
|
||||||
|
{:select-full* (fn [this structure next-fn] (select-full* this structure next-fn))
|
||||||
|
:transform-full* (fn [this structure next-fn] (transform-full* this structure next-fn))
|
||||||
|
})
|
||||||
|
))
|
||||||
|
|
||||||
(defn coerce-structure-vals-path [this]
|
(defn coerce-structure-vals-path [this]
|
||||||
(let [pimpl (find-protocol-impl! StructureValsPath this)
|
(let [pimpl (structure-vals-path-impl this)
|
||||||
selector (:select-full* pimpl)
|
selector (:select-full* pimpl)
|
||||||
transformer (:transform-full* pimpl)]
|
transformer (:transform-full* pimpl)]
|
||||||
(->TransformFunctions
|
(->TransformFunctions
|
||||||
|
|
@ -108,7 +157,7 @@
|
||||||
|
|
||||||
(defn coerce-collector [this]
|
(defn coerce-collector [this]
|
||||||
(let [cfn (->> this
|
(let [cfn (->> this
|
||||||
(find-protocol-impl! Collector)
|
collector-impl
|
||||||
:collect-val
|
:collect-val
|
||||||
)
|
)
|
||||||
afn (fn [vals structure next-fn]
|
afn (fn [vals structure next-fn]
|
||||||
|
|
@ -117,12 +166,6 @@
|
||||||
(->TransformFunctions StructureValsPathExecutor afn afn)))
|
(->TransformFunctions StructureValsPathExecutor afn afn)))
|
||||||
|
|
||||||
|
|
||||||
(defn structure-path-impl [this]
|
|
||||||
(if (fn? this)
|
|
||||||
;;TODO: this isn't kosher, it uses knowledge of internals of protocols
|
|
||||||
(-> StructurePath :impls (get clojure.lang.AFn))
|
|
||||||
(find-protocol-impl! StructurePath this)))
|
|
||||||
|
|
||||||
(defn coerce-structure-path [this]
|
(defn coerce-structure-path [this]
|
||||||
(let [pimpl (structure-path-impl this)
|
(let [pimpl (structure-path-impl this)
|
||||||
selector (:select* pimpl)
|
selector (:select* pimpl)
|
||||||
|
|
@ -148,7 +191,7 @@
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(defn structure-path? [obj]
|
(defn structure-path? [obj]
|
||||||
(or (fn? obj) (obj-extends? `StructurePath obj)))
|
(or (fn? obj) (obj-extends? `p/StructurePath obj)))
|
||||||
|
|
||||||
(extend-protocol CoerceTransformFunctions
|
(extend-protocol CoerceTransformFunctions
|
||||||
nil ; needs its own path because it doesn't count as an Object
|
nil ; needs its own path because it doesn't count as an Object
|
||||||
|
|
@ -167,23 +210,23 @@
|
||||||
#?(:clj Object :cljs js/Object)
|
#?(:clj Object :cljs js/Object)
|
||||||
(coerce-path [this]
|
(coerce-path [this]
|
||||||
(cond (structure-path? this) (coerce-structure-path this)
|
(cond (structure-path? this) (coerce-structure-path this)
|
||||||
(obj-extends? `Collector this) (coerce-collector this)
|
(obj-extends? `p/Collector this) (coerce-collector this)
|
||||||
(obj-extends? `StructureValsPath this) (coerce-structure-vals-path this)
|
(obj-extends? `p/StructureValsPath this) (coerce-structure-vals-path this)
|
||||||
:else (throw-illegal (no-prot-error-str this))
|
:else (throw-illegal (no-prot-error-str this))
|
||||||
)))
|
)))
|
||||||
|
|
||||||
|
|
||||||
(defn extype [^TransformFunctions f]
|
(defn extype [^TransformFunctions f]
|
||||||
(let [^ExecutorFunctions exs (.executors f)]
|
(let [^ExecutorFunctions exs (field f 'executors)]
|
||||||
(.type exs)
|
(field exs 'type)
|
||||||
))
|
))
|
||||||
|
|
||||||
(defn- combine-same-types [[^TransformFunctions f & _ :as all]]
|
(defn- combine-same-types [[^TransformFunctions f & _ :as all]]
|
||||||
(if (empty? all)
|
(if (empty? all)
|
||||||
(coerce-path nil)
|
(coerce-path nil)
|
||||||
(let [^ExecutorFunctions exs (.executors f)
|
(let [^ExecutorFunctions exs (field f 'executors)
|
||||||
|
|
||||||
t (.type exs)
|
t (field exs 'type)
|
||||||
|
|
||||||
combiner
|
combiner
|
||||||
(if (= t :svalspath)
|
(if (= t :svalspath)
|
||||||
|
|
@ -201,16 +244,16 @@
|
||||||
(reduce (fn [^TransformFunctions curr ^TransformFunctions next]
|
(reduce (fn [^TransformFunctions curr ^TransformFunctions next]
|
||||||
(->TransformFunctions
|
(->TransformFunctions
|
||||||
exs
|
exs
|
||||||
(combiner (.selector curr) (.selector next))
|
(combiner (field curr 'selector) (field next 'selector))
|
||||||
(combiner (.transformer curr) (.transformer next))
|
(combiner (field curr 'transformer) (field next 'transformer))
|
||||||
))
|
))
|
||||||
all))))
|
all))))
|
||||||
|
|
||||||
(defn coerce-structure-vals [^TransformFunctions tfns]
|
(defn coerce-structure-vals [^TransformFunctions tfns]
|
||||||
(if (= (extype tfns) :svalspath)
|
(if (= (extype tfns) :svalspath)
|
||||||
tfns
|
tfns
|
||||||
(let [selector (.selector tfns)
|
(let [selector (field tfns 'selector)
|
||||||
transformer (.transformer tfns)]
|
transformer (field tfns 'transformer)]
|
||||||
(->TransformFunctions
|
(->TransformFunctions
|
||||||
StructureValsPathExecutor
|
StructureValsPathExecutor
|
||||||
(fn [vals structure next-fn]
|
(fn [vals structure next-fn]
|
||||||
|
|
@ -219,7 +262,7 @@
|
||||||
(transformer structure (fn [structure] (next-fn vals structure))))
|
(transformer structure (fn [structure] (next-fn vals structure))))
|
||||||
))))
|
))))
|
||||||
|
|
||||||
(extend-protocol StructureValsPathComposer
|
(extend-protocol p/StructureValsPathComposer
|
||||||
nil
|
nil
|
||||||
(comp-paths* [sp]
|
(comp-paths* [sp]
|
||||||
(coerce-path sp))
|
(coerce-path sp))
|
||||||
|
|
@ -242,8 +285,8 @@
|
||||||
|
|
||||||
(defn coerce-structure-vals-direct [this]
|
(defn coerce-structure-vals-direct [this]
|
||||||
(cond (structure-path? this) (coerce-structure-path-direct this)
|
(cond (structure-path? this) (coerce-structure-path-direct this)
|
||||||
(obj-extends? `Collector this) (coerce-collector this)
|
(obj-extends? `p/Collector this) (coerce-collector this)
|
||||||
(obj-extends? `StructureValsPath this) (coerce-structure-vals-path this)
|
(obj-extends? `p/StructureValsPath this) (coerce-structure-vals-path this)
|
||||||
(instance? TransformFunctions this) (coerce-structure-vals this)
|
(instance? TransformFunctions this) (coerce-structure-vals this)
|
||||||
:else (throw-illegal (no-prot-error-str this))
|
:else (throw-illegal (no-prot-error-str this))
|
||||||
))
|
))
|
||||||
|
|
@ -334,14 +377,14 @@
|
||||||
|
|
||||||
(defn compiled-select*
|
(defn compiled-select*
|
||||||
[^com.rpl.specter.impl.TransformFunctions tfns structure]
|
[^com.rpl.specter.impl.TransformFunctions tfns structure]
|
||||||
(let [^com.rpl.specter.impl.ExecutorFunctions ex (.executors tfns)]
|
(let [^com.rpl.specter.impl.ExecutorFunctions ex (field tfns 'executors)]
|
||||||
((.select-executor ex) (.selector tfns) structure)
|
((field ex 'select-executor) (field tfns 'selector) structure)
|
||||||
))
|
))
|
||||||
|
|
||||||
(defn compiled-transform*
|
(defn compiled-transform*
|
||||||
[^com.rpl.specter.impl.TransformFunctions tfns transform-fn structure]
|
[^com.rpl.specter.impl.TransformFunctions tfns transform-fn structure]
|
||||||
(let [^com.rpl.specter.impl.ExecutorFunctions ex (.executors tfns)]
|
(let [^com.rpl.specter.impl.ExecutorFunctions ex (field tfns 'executors)]
|
||||||
((.transform-executor ex) (.transformer tfns) transform-fn structure)
|
((field ex 'transform-executor) (field tfns 'transformer) transform-fn structure)
|
||||||
))
|
))
|
||||||
|
|
||||||
(defn selected?*
|
(defn selected?*
|
||||||
|
|
@ -385,7 +428,7 @@
|
||||||
|
|
||||||
(deftype AllStructurePath [])
|
(deftype AllStructurePath [])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
AllStructurePath
|
AllStructurePath
|
||||||
(select* [this structure next-fn]
|
(select* [this structure next-fn]
|
||||||
(into [] (r/mapcat next-fn structure)))
|
(into [] (r/mapcat next-fn structure)))
|
||||||
|
|
@ -399,14 +442,14 @@
|
||||||
|
|
||||||
(deftype ValCollect [])
|
(deftype ValCollect [])
|
||||||
|
|
||||||
(extend-protocol Collector
|
(extend-protocol p/Collector
|
||||||
ValCollect
|
ValCollect
|
||||||
(collect-val [this structure]
|
(collect-val [this structure]
|
||||||
structure))
|
structure))
|
||||||
|
|
||||||
(deftype LastStructurePath [])
|
(deftype LastStructurePath [])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
LastStructurePath
|
LastStructurePath
|
||||||
(select* [this structure next-fn]
|
(select* [this structure next-fn]
|
||||||
(next-fn (last structure)))
|
(next-fn (last structure)))
|
||||||
|
|
@ -415,7 +458,7 @@
|
||||||
|
|
||||||
(deftype FirstStructurePath [])
|
(deftype FirstStructurePath [])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
FirstStructurePath
|
FirstStructurePath
|
||||||
(select* [this structure next-fn]
|
(select* [this structure next-fn]
|
||||||
(next-fn (first structure)))
|
(next-fn (first structure)))
|
||||||
|
|
@ -424,31 +467,31 @@
|
||||||
|
|
||||||
(deftype WalkerStructurePath [afn])
|
(deftype WalkerStructurePath [afn])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
WalkerStructurePath
|
WalkerStructurePath
|
||||||
(select* [^WalkerStructurePath this structure next-fn]
|
(select* [^WalkerStructurePath this structure next-fn]
|
||||||
(walk-select (.afn this) next-fn structure))
|
(walk-select (field this 'afn) next-fn structure))
|
||||||
(transform* [^WalkerStructurePath this structure next-fn]
|
(transform* [^WalkerStructurePath this structure next-fn]
|
||||||
(walk-until (.afn this) next-fn structure)))
|
(walk-until (field this 'afn) next-fn structure)))
|
||||||
|
|
||||||
(deftype CodeWalkerStructurePath [afn])
|
(deftype CodeWalkerStructurePath [afn])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
CodeWalkerStructurePath
|
CodeWalkerStructurePath
|
||||||
(select* [^CodeWalkerStructurePath this structure next-fn]
|
(select* [^CodeWalkerStructurePath this structure next-fn]
|
||||||
(walk-select (.afn this) next-fn structure))
|
(walk-select (field this 'afn) next-fn structure))
|
||||||
(transform* [^CodeWalkerStructurePath this structure next-fn]
|
(transform* [^CodeWalkerStructurePath this structure next-fn]
|
||||||
(codewalk-until (.afn this) next-fn structure)))
|
(codewalk-until (field this 'afn) next-fn structure)))
|
||||||
|
|
||||||
|
|
||||||
(deftype FilterStructurePath [path])
|
(deftype FilterStructurePath [path])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
FilterStructurePath
|
FilterStructurePath
|
||||||
(select* [^FilterStructurePath this structure next-fn]
|
(select* [^FilterStructurePath this structure next-fn]
|
||||||
(->> structure (filter #(selected?* (.path this) %)) doall next-fn))
|
(->> structure (filter #(selected?* (field this 'path) %)) doall next-fn))
|
||||||
(transform* [^FilterStructurePath this structure next-fn]
|
(transform* [^FilterStructurePath this structure next-fn]
|
||||||
(let [[filtered ancestry] (filter+ancestry (.path this) structure)
|
(let [[filtered ancestry] (filter+ancestry (field this 'path) structure)
|
||||||
;; the vec is necessary so that we can get by index later
|
;; the vec is necessary so that we can get by index later
|
||||||
;; (can't get by index for cons'd lists)
|
;; (can't get by index for cons'd lists)
|
||||||
next (vec (next-fn filtered))]
|
next (vec (next-fn filtered))]
|
||||||
|
|
@ -459,33 +502,33 @@
|
||||||
|
|
||||||
(deftype KeyPath [akey])
|
(deftype KeyPath [akey])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
KeyPath
|
KeyPath
|
||||||
(select* [^KeyPath this structure next-fn]
|
(select* [^KeyPath this structure next-fn]
|
||||||
(key-select (.akey this) structure next-fn))
|
(key-select (field this 'akey) structure next-fn))
|
||||||
(transform* [^KeyPath this structure next-fn]
|
(transform* [^KeyPath this structure next-fn]
|
||||||
(key-transform (.akey this) structure next-fn)
|
(key-transform (field this 'akey) structure next-fn)
|
||||||
))
|
))
|
||||||
|
|
||||||
(deftype SelectCollector [sel-fn selector])
|
(deftype SelectCollector [sel-fn selector])
|
||||||
|
|
||||||
(extend-protocol Collector
|
(extend-protocol p/Collector
|
||||||
SelectCollector
|
SelectCollector
|
||||||
(collect-val [^SelectCollector this structure]
|
(collect-val [^SelectCollector this structure]
|
||||||
((.sel-fn this) (.selector this) structure)))
|
((field this 'sel-fn) (field this 'selector) structure)))
|
||||||
|
|
||||||
(deftype SRangePath [start-fn end-fn])
|
(deftype SRangePath [start-fn end-fn])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
SRangePath
|
SRangePath
|
||||||
(select* [^SRangePath this structure next-fn]
|
(select* [^SRangePath this structure next-fn]
|
||||||
(let [start ((.start-fn this) structure)
|
(let [start ((field this 'start-fn) structure)
|
||||||
end ((.end-fn this) structure)]
|
end ((field this 'end-fn) structure)]
|
||||||
(next-fn (-> structure vec (subvec start end)))
|
(next-fn (-> structure vec (subvec start end)))
|
||||||
))
|
))
|
||||||
(transform* [^SRangePath this structure next-fn]
|
(transform* [^SRangePath this structure next-fn]
|
||||||
(let [start ((.start-fn this) structure)
|
(let [start ((field this 'start-fn) structure)
|
||||||
end ((.end-fn this) structure)
|
end ((field this 'end-fn) structure)
|
||||||
structurev (vec structure)
|
structurev (vec structure)
|
||||||
newpart (next-fn (-> structurev (subvec start end)))
|
newpart (next-fn (-> structurev (subvec start end)))
|
||||||
res (concat (subvec structurev 0 start)
|
res (concat (subvec structurev 0 start)
|
||||||
|
|
@ -498,24 +541,24 @@
|
||||||
|
|
||||||
(deftype ViewPath [view-fn])
|
(deftype ViewPath [view-fn])
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
ViewPath
|
ViewPath
|
||||||
(select* [^ViewPath this structure next-fn]
|
(select* [^ViewPath this structure next-fn]
|
||||||
(->> structure ((.view-fn this)) next-fn))
|
(->> structure ((field this 'view-fn)) next-fn))
|
||||||
(transform* [^ViewPath this structure next-fn]
|
(transform* [^ViewPath this structure next-fn]
|
||||||
(->> structure ((.view-fn this)) next-fn)
|
(->> structure ((field this 'view-fn)) next-fn)
|
||||||
))
|
))
|
||||||
|
|
||||||
(deftype PutValCollector [val])
|
(deftype PutValCollector [val])
|
||||||
|
|
||||||
(extend-protocol Collector
|
(extend-protocol p/Collector
|
||||||
PutValCollector
|
PutValCollector
|
||||||
(collect-val [^PutValCollector this structure]
|
(collect-val [^PutValCollector this structure]
|
||||||
(.val this)
|
(field this 'val)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
nil
|
nil
|
||||||
(select* [this structure next-fn]
|
(select* [this structure next-fn]
|
||||||
(next-fn structure))
|
(next-fn structure))
|
||||||
|
|
@ -537,15 +580,15 @@
|
||||||
))
|
))
|
||||||
|
|
||||||
;;TODO: test nothing matches case
|
;;TODO: test nothing matches case
|
||||||
(extend-protocol StructurePath
|
(extend-protocol p/StructurePath
|
||||||
ConditionalPath
|
ConditionalPath
|
||||||
(select* [this structure next-fn]
|
(select* [this structure next-fn]
|
||||||
(if-let [selector (retrieve-selector (.cond-pairs this) structure)]
|
(if-let [selector (retrieve-selector (field this 'cond-pairs) structure)]
|
||||||
(->> (compiled-select* selector structure)
|
(->> (compiled-select* selector structure)
|
||||||
(mapcat next-fn)
|
(mapcat next-fn)
|
||||||
doall)))
|
doall)))
|
||||||
(transform* [this structure next-fn]
|
(transform* [this structure next-fn]
|
||||||
(if-let [selector (retrieve-selector (.cond-pairs this) structure)]
|
(if-let [selector (retrieve-selector (field this 'cond-pairs) structure)]
|
||||||
(compiled-transform* selector next-fn structure)
|
(compiled-transform* selector next-fn structure)
|
||||||
structure
|
structure
|
||||||
)))
|
)))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue