Created
February 14, 2013 11:47
-
-
Save duarten/4952302 to your computer and use it in GitHub Desktop.
A function to search Hiccup data structures.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(def ^{:private true} not-nil? (comp not nil?)) | |
(defprotocol Matcher | |
"Protocol for types that can be used to search a Hiccup data structure." | |
(matches [this elem])) | |
(defn- comp-name [x y] | |
(and (not-nil? y) (= (name x) (name y)))) | |
(extend-protocol Matcher | |
nil | |
(matches [this [tag & _]] | |
(= nil tag)) | |
clojure.lang.Keyword | |
(matches [this [tag & _]] | |
(comp-name this tag)) | |
java.lang.String | |
(matches [this [tag & _]] | |
(comp-name this tag)) | |
clojure.lang.Symbol | |
(matches [this [tag & _]] | |
(comp-name this tag)) | |
java.util.regex.Pattern | |
(matches [this [tag & _]] | |
(and (not-nil? tag) (not-nil? (re-find this (name tag))))) | |
clojure.lang.IPersistentSet | |
(matches [this [tag & _]] | |
(and (not-nil? tag) (not-nil? (this (keyword (name tag)))))) | |
clojure.lang.IPersistentMap | |
(matches [this [tag attrs & children]] | |
(and | |
(map? attrs) | |
(every? | |
(fn [[k v]] | |
(let [target (attrs k)] | |
(and | |
(or (not-nil? target) (nil? v)) | |
(if (fn? v) | |
(v target) | |
(matches v [target {}]))))) | |
this))) | |
java.lang.Object | |
(matches [this [tag & _]] | |
(= this tag))) | |
(defn- is-match? [matcher value] | |
(if (fn? matcher) | |
(matcher value) | |
(matches matcher value))) | |
(defn text [t] | |
(reify | |
Matcher | |
(matches [_ [tag attrs text]] | |
(= t text)))) | |
(defn match-any [& matchers] | |
(reify | |
Matcher | |
(matches [_ elem] | |
(not-nil? (some #(is-match? % elem) matchers))))) | |
(defn find [x & matchers] | |
(letfn [(rf [ret [tag attrs & children :as source]] | |
(if (every? #(is-match? % source) matchers) | |
(conj! ret source)) | |
(reduce rf ret (filter coll? children)))] | |
(persistent! (reduce rf (transient []) [x])))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment