Created
March 5, 2019 21:19
-
-
Save skliarpawlo/21d16d59e11d8f2042fdc8bad4037131 to your computer and use it in GitHub Desktop.
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
;; | |
;; Matcher should recognize and destruct URL by: | |
;; host: domain | |
;; path: parts, splitted with "/" | |
;; queryparam: name/value pairs of query | |
;; (see examples below) | |
;; | |
;; Each string that is started from "?" is a "bind" | |
;; (recognize matcher) should return nil or seq of binds | |
;; | |
(import java.net.URL) | |
(defn new-pattern [pattern] | |
"parse input pattern into list of (command, param) tuples" | |
(let [command-re #"(host|path|queryparam)\(([^)]*)\)" | |
command-matches (->> (re-seq command-re pattern) (map rest))] | |
command-matches)) | |
(defn parse-binds [pattern url-part] | |
"parse binds values from any part of a url" | |
(let [bind-re #"\?([^?/=&]+)" | |
parsed-pattern (clojure.string/replace pattern bind-re "([^?/=&]+)") | |
parsed-re (re-pattern parsed-pattern) | |
parsed-bind-names (->> (re-seq bind-re pattern) (map last)) | |
parsed-bind-values (->> (re-find parsed-re url-part) rest) | |
binds-list (map array-map parsed-bind-names parsed-bind-values) | |
binds-map (apply (partial merge-with into) binds-list)] | |
(clojure.walk/keywordize-keys binds-map))) | |
(defn recognize-one [[command pattern] parsed-url] | |
"process one input pattern only" | |
(if-let [url-part (case command | |
"host" (. parsed-url getHost) | |
"path" (. parsed-url getPath) | |
"queryparam" (. parsed-url getQuery))] | |
(if (clojure.string/includes? pattern "?") | |
(parse-binds pattern url-part) | |
(if (= pattern url-part) url-part)))) | |
(defn merge-recognized [res match] | |
"reduce function to generate final result" | |
(if (or (nil? res) (nil? match)) nil | |
(if (string? match) res | |
(into res (seq match))))) | |
(defn recognize [pattern url] | |
"recognize all patterns in a url" | |
(let [url (URL. url) | |
all-recognized (map #(recognize-one % url) pattern)] | |
(reduce merge-recognized [] all-recognized))) | |
;; Tests | |
(let [youtube (new-pattern "host(?host); path(/watch/?type); queryparam(id=?id)")] | |
(clojure.test/is | |
(= (recognize youtube "http://youtube.com/watch/video/?id=1") | |
[[:host "youtube.com"] [:type "video"] [:id "1"]]))) | |
(let [twitter (new-pattern "host(twitter.com); path(?user/status/?id);")] | |
(clojure.test/is | |
(= (recognize twitter "http://twitter.com/bradfitz/status/562360748727611392") | |
[[:user "bradfitz"] [:id "562360748727611392"]]))) | |
(let [dribbble (new-pattern "host(dribbble.com); path(shots/?id); queryparam(offset=?offset);")] | |
(clojure.test/is | |
(= (recognize dribbble "https://dribbble.com/shots/1905065-Travel-Icons-pack?list=users&offset=1") | |
[[:id "1905065-Travel-Icons-pack"] [:offset "1"]])) | |
(clojure.test/is | |
(nil? (recognize dribbble "https://twitter.com/shots/1905065-Travel-Icons-pack?list=users&offset=1"))) | |
(clojure.test/is | |
(nil? (recognize dribbble "https://dribbble.com/shots/1905065-Travel-Icons-pack?list=users")))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment