Yet another pattern matching library for Clojure(Script).
[io.xapix/matchete "1.1.0"]
(set-env! :dependencies #(conj % [io.xapix/matchete "1.1.0"]))
{:deps {io.xapix/matchete {:mvn/version "1.1.0"}}}
(require '[matchete.core :as m])
;; `match?` function returns true or false to indicate if the data matches the pattern
(m/match? '{:foo ?foo} {:foo 1}) ;; => true
(m/match? '{:bar ?bar} {:foo 1}) ;; => false
;; `matches` function returns lazy sequence with collected bindings
;; empty seq indicates not matched data
(m/matches '{:foo ?foo} {:foo 1}) ;; => '({?foo 1})
(m/matches '{:bar ?bar} {:foo 1}) ;; => '()
;; `matcher` function precompiles pattern into a function
(let [matcher (m/matcher '{:foo ?foo})]
(matcher {:foo 1})) ;; => '({?foo 1})
(m/match? 42 42) ;; => true
(m/match? "42" "24") ;; => false
;; sequences
(m/match? [1 2 3] [1 2 3]) ;; => true
(m/match? '(1 2 3) [1 2 3]) ;; => true
(m/match? [1 2 3] [1 2 3 4]) ;; => false because pattern expects exactly 3 elements
;; to override this behaviour tail destructuring pattern can be used
(m/match? [1 2 3 & _] [1 2 3 4]) ;; => true, `_` is a placeholder here that will match to any provided data
;; hash-maps
(m/match? {:id 123 :name "Alise"} {:id 123 :name "Alise" :lastname "Cooper"}) ;; => true
(m/match? {:id 123 :name "Alise"} {:id 123 :lastname "Cooper"}) ;; => false because `:name` key is missing
There are three types of special symbols that can be used in a pattern:
(m/matches '?user {:id 1 :name "Bob"}) ;; => '({?user {:id 1 :name "Bob"}})
(m/matches '{:id ?user-id :name ?user-name}
{:id 1 :name "Bob"}) ;; => '({?user-id 1 ?user-name "Bob"})
(m/matches '[1 ?two 3 & [?four & _]]
[1 2 3 4 5 6]) ;; => '({?two 2 ?four 4})
(m/matches '{:vector [_ {:id ?id}]}
{:vector [{:id 1} {:id 2}]}) ;; => '({?id 2})
data bindings can be used as a hash-map keys
(m/matches '{?key ?value}
{:foo "foo"
:bar "bar"}) ;; => '({?key :foo ?value "foo"} {?key :bar ?value "bar"})
(m/matches '{?x "foo"
?y "bar"}
{:key-1 "foo"
:key-2 "foo"
:key-3 "bar"}) ;; => '({?x :key-1 ?y :key-3} {?x :key-2 ?y :key-3})
Collect data into a vector. Order of appearence is not guaranteed.
(m/matches '[{:id !ids} {:id !ids} {:id !ids}]
[{:id 1} {:id 2} {:id 3}]) ;; => '({!ids [1 2 3]})
not
predicate(m/matches '{:id (cat (not 10) ?id)
:name ?name}
{:id 42
:name "Alise"} ;; => '({?id 42 ?name "Alise"})
;; {:id 10
;; :name "Bob"} ;; => '()
)
cat
combinatorEach pattern will be applied to the same data combine data bindings into one result. Patterns can extend the result or add more sofisticated restrictions.
(m/matches '(cat {:id ?id :name ?name} ?user)
{:id 1
:name "Alise"
:lastname "Cooper"}) ;; => '({?id 1 ?name "Alise" ?user {:id 1 :name "Alise" :lastname "Cooper"}})
alt
combinatorPatterns combined by alt
will be applied to the same data as long as one of them will match and the matches from that pattern will be the result of matching.
(m/matches '(alt {:id ?id} {"id" ?id} {:userId ?id})
{:id 1} ;; => '({?id 1})
;; {"id" 2} ;; => '({?id 2})
;; {:userId 3} ;; => '({?id 3})
)
scan
(scan P)
Expects one pattern wich will be applied to each item of sequence or hash-map (item will be in the form of tuple: [key, value]).
(m/matches '{:foo (scan [?id ?name])}
{:foo [[1 "Alise"] [::empty] [3 "Bob"]]}) ;; => '({?id 1 ?name "Alise"} {?id 3 ?name "Bob"})'
(scan index-P value-P)
Expects two patterns:
(m/matches '(scan !path (scan !path (scan !path ?node)))
[{:id 1
:user {:name "Alise"
:role :admin}
:actions [{:type :login}]}])
;; => '({!path [0 :user :name] ?node "Alise"}
;; {!path [0 :user :role] ?node :admin}
;; {!path [0 :actions 0] ?node {:type :login}})
(m/matches '(def-rule $children (scan !path (alt $children ?leaf)))
[{:id 1
:user {:name "Alise"
:role :admin}
:actions [{:type :login}]}])
;; => '({!path [0 :id] ?leaf 1}
;; {!path [0 :user :name] ?leaf "Alise"}
;; {!path [0 :user :role] ?leaf :admin}
;; {!path [0 :actions 0 :type] ?leaf :login})
;; rules can be precompiled
(let [rules {'$children (m/matcher '(scan !path (alt $children ?leaf)))}]
(m/matches '$children rules
[{:id 1
:user {:name "Alise"
:role :admin}
:actions [{:type :login}]}]))
;; => '({!path [0 :id] ?leaf 1}
;; {!path [0 :user :name] ?leaf "Alise"}
;; {!path [0 :user :role] ?leaf :admin}
;; {!path [0 :actions 0 :type] ?leaf :login})
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close