[clout-clojure] 01/02: New upstream version 2.1.2
Apollon Oikonomopoulos
apoikos at moszumanska.debian.org
Sat Aug 5 13:34:31 UTC 2017
This is an automated email from the git hooks/post-receive script.
apoikos pushed a commit to branch master
in repository clout-clojure.
commit b68560fd0be73b68703f3ff3952c9382d0c25e56
Author: Apollon Oikonomopoulos <apoikos at debian.org>
Date: Sat Aug 5 09:24:41 2017 -0400
New upstream version 2.1.2
---
.gitignore | 9 ++
.travis.yml | 6 ++
LICENSE.html | 261 +++++++++++++++++++++++++++++++++++++++++++++++
README.md | 136 ++++++++++++++++++++++++
project.clj | 13 +++
src/clout/core.clj | 126 +++++++++++++++++++++++
test/clout/core_test.clj | 127 +++++++++++++++++++++++
7 files changed, 678 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e04714b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+/target
+/classes
+/checkouts
+pom.xml
+pom.xml.asc
+*.jar
+*.class
+/.lein-*
+/.nrepl-port
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..75560d1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,6 @@
+language: clojure
+lein: lein2
+script: lein2 with-profile dev:dev,1.4:dev,1.5:dev,1.6:dev,1.7 test
+jdk:
+ - openjdk7
+ - openjdk6
diff --git a/LICENSE.html b/LICENSE.html
new file mode 100644
index 0000000..813c07d
--- /dev/null
+++ b/LICENSE.html
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<title>Eclipse Public License - Version 1.0</title>
+<style type="text/css">
+ body {
+ size: 8.5in 11.0in;
+ margin: 0.25in 0.5in 0.25in 0.5in;
+ tab-interval: 0.5in;
+ }
+ p {
+ margin-left: auto;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ }
+ p.list {
+ margin-left: 0.5in;
+ margin-top: 0.05em;
+ margin-bottom: 0.05em;
+ }
+ </style>
+
+</head>
+
+<body lang="EN-US">
+
+<p align=center><b>Eclipse Public License - v 1.0</b></p>
+
+<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
+DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
+AGREEMENT.</p>
+
+<p><b>1. DEFINITIONS</b></p>
+
+<p>"Contribution" means:</p>
+
+<p class="list">a) in the case of the initial Contributor, the initial
+code and documentation distributed under this Agreement, and</p>
+<p class="list">b) in the case of each subsequent Contributor:</p>
+<p class="list">i) changes to the Program, and</p>
+<p class="list">ii) additions to the Program;</p>
+<p class="list">where such changes and/or additions to the Program
+originate from and are distributed by that particular Contributor. A
+Contribution 'originates' from a Contributor if it was added to the
+Program by such Contributor itself or anyone acting on such
+Contributor's behalf. Contributions do not include additions to the
+Program which: (i) are separate modules of software distributed in
+conjunction with the Program under their own license agreement, and (ii)
+are not derivative works of the Program.</p>
+
+<p>"Contributor" means any person or entity that distributes
+the Program.</p>
+
+<p>"Licensed Patents" mean patent claims licensable by a
+Contributor which are necessarily infringed by the use or sale of its
+Contribution alone or when combined with the Program.</p>
+
+<p>"Program" means the Contributions distributed in accordance
+with this Agreement.</p>
+
+<p>"Recipient" means anyone who receives the Program under
+this Agreement, including all Contributors.</p>
+
+<p><b>2. GRANT OF RIGHTS</b></p>
+
+<p class="list">a) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free copyright license to reproduce, prepare derivative works
+of, publicly display, publicly perform, distribute and sublicense the
+Contribution of such Contributor, if any, and such derivative works, in
+source code and object code form.</p>
+
+<p class="list">b) Subject to the terms of this Agreement, each
+Contributor hereby grants Recipient a non-exclusive, worldwide,
+royalty-free patent license under Licensed Patents to make, use, sell,
+offer to sell, import and otherwise transfer the Contribution of such
+Contributor, if any, in source code and object code form. This patent
+license shall apply to the combination of the Contribution and the
+Program if, at the time the Contribution is added by the Contributor,
+such addition of the Contribution causes such combination to be covered
+by the Licensed Patents. The patent license shall not apply to any other
+combinations which include the Contribution. No hardware per se is
+licensed hereunder.</p>
+
+<p class="list">c) Recipient understands that although each Contributor
+grants the licenses to its Contributions set forth herein, no assurances
+are provided by any Contributor that the Program does not infringe the
+patent or other intellectual property rights of any other entity. Each
+Contributor disclaims any liability to Recipient for claims brought by
+any other entity based on infringement of intellectual property rights
+or otherwise. As a condition to exercising the rights and licenses
+granted hereunder, each Recipient hereby assumes sole responsibility to
+secure any other intellectual property rights needed, if any. For
+example, if a third party patent license is required to allow Recipient
+to distribute the Program, it is Recipient's responsibility to acquire
+that license before distributing the Program.</p>
+
+<p class="list">d) Each Contributor represents that to its knowledge it
+has sufficient copyright rights in its Contribution, if any, to grant
+the copyright license set forth in this Agreement.</p>
+
+<p><b>3. REQUIREMENTS</b></p>
+
+<p>A Contributor may choose to distribute the Program in object code
+form under its own license agreement, provided that:</p>
+
+<p class="list">a) it complies with the terms and conditions of this
+Agreement; and</p>
+
+<p class="list">b) its license agreement:</p>
+
+<p class="list">i) effectively disclaims on behalf of all Contributors
+all warranties and conditions, express and implied, including warranties
+or conditions of title and non-infringement, and implied warranties or
+conditions of merchantability and fitness for a particular purpose;</p>
+
+<p class="list">ii) effectively excludes on behalf of all Contributors
+all liability for damages, including direct, indirect, special,
+incidental and consequential damages, such as lost profits;</p>
+
+<p class="list">iii) states that any provisions which differ from this
+Agreement are offered by that Contributor alone and not by any other
+party; and</p>
+
+<p class="list">iv) states that source code for the Program is available
+from such Contributor, and informs licensees how to obtain it in a
+reasonable manner on or through a medium customarily used for software
+exchange.</p>
+
+<p>When the Program is made available in source code form:</p>
+
+<p class="list">a) it must be made available under this Agreement; and</p>
+
+<p class="list">b) a copy of this Agreement must be included with each
+copy of the Program.</p>
+
+<p>Contributors may not remove or alter any copyright notices contained
+within the Program.</p>
+
+<p>Each Contributor must identify itself as the originator of its
+Contribution, if any, in a manner that reasonably allows subsequent
+Recipients to identify the originator of the Contribution.</p>
+
+<p><b>4. COMMERCIAL DISTRIBUTION</b></p>
+
+<p>Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use of
+the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create
+potential liability for other Contributors. Therefore, if a Contributor
+includes the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and
+indemnify every other Contributor ("Indemnified Contributor")
+against any losses, damages and costs (collectively "Losses")
+arising from claims, lawsuits and other legal actions brought by a third
+party against the Indemnified Contributor to the extent caused by the
+acts or omissions of such Commercial Contributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In
+order to qualify, an Indemnified Contributor must: a) promptly notify
+the Commercial Contributor in writing of such claim, and b) allow the
+Commercial Contributor to control, and cooperate with the Commercial
+Contributor in, the defense and any related settlement negotiations. The
+Indemnified Contributor may participate in any such claim at its own
+expense.</p>
+
+<p>For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those
+performance claims and warranties, and if a court requires any other
+Contributor to pay any damages as a result, the Commercial Contributor
+must pay those damages.</p>
+
+<p><b>5. NO WARRANTY</b></p>
+
+<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
+ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement , including but not limited to
+the risks and costs of program errors, compliance with applicable laws,
+damage to or loss of data, programs or equipment, and unavailability or
+interruption of operations.</p>
+
+<p><b>6. DISCLAIMER OF LIABILITY</b></p>
+
+<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
+NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>
+
+<p><b>7. GENERAL</b></p>
+
+<p>If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further action
+by the parties hereto, such provision shall be reformed to the minimum
+extent necessary to make such provision valid and enforceable.</p>
+
+<p>If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other
+software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the
+date such litigation is filed.</p>
+
+<p>All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of time
+after becoming aware of such noncompliance. If all Recipient's rights
+under this Agreement terminate, Recipient agrees to cease use and
+distribution of the Program as soon as reasonably practicable. However,
+Recipient's obligations under this Agreement and any licenses granted by
+Recipient relating to the Program shall continue and survive.</p>
+
+<p>Everyone is permitted to copy and distribute copies of this
+Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The
+Agreement Steward reserves the right to publish new versions (including
+revisions) of this Agreement from time to time. No one other than the
+Agreement Steward has the right to modify this Agreement. The Eclipse
+Foundation is the initial Agreement Steward. The Eclipse Foundation may
+assign the responsibility to serve as the Agreement Steward to a
+suitable separate entity. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new version
+of the Agreement is published, Contributor may elect to distribute the
+Program (including its Contributions) under the new version. Except as
+expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
+rights or licenses to the intellectual property of any Contributor under
+this Agreement, whether expressly, by implication, estoppel or
+otherwise. All rights in the Program not expressly granted under this
+Agreement are reserved.</p>
+
+<p>This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No party
+to this Agreement will bring a legal action under this Agreement more
+than one year after the cause of action arose. Each party waives its
+rights to a jury trial in any resulting litigation.</p>
+
+</body>
+
+</html>
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2bc53e8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,136 @@
+# Clout
+
+[![Build Status](https://travis-ci.org/weavejester/clout.svg?branch=master)](https://travis-ci.org/weavejester/clout)
+
+Clout is a library for matching [Ring][1] HTTP requests. It uses the same
+routing syntax as used by popular Ruby web frameworks like Ruby on Rails and
+Sinatra.
+
+[1]: https://github.com/ring-clojure/ring
+
+## Installation
+
+Add the following to your project.clj dependencies:
+
+```clj
+[clout "2.1.2"]
+```
+
+## Usage
+
+Require Clout in the normal way:
+
+```clj
+(require '[clout.core :as clout])
+```
+
+These following examples also make use of the [Ring-Mock][2] library
+to generate Ring request maps:
+
+[2]: https://github.com/ring-clojure/ring-mock
+
+```clj
+(require '[ring.mock.request :as mock])
+```
+
+Routes can match by keyword:
+
+```clj
+(clout/route-matches
+ "/article/:title"
+ (mock/request :get "/article/clojure"))
+
+=> {:title "clojure"}
+```
+
+Or with wildcards:
+
+```clj
+(clout/route-matches
+ "/public/*"
+ (mock/request :get "/public/style/screen.css"))
+
+=> {:* "style/screen.css"}
+```
+
+Clout can also match absolute routes:
+
+```clj
+(clout/route-matches
+ "http://subdomain.example.com/"
+ (mock/request :get "http://subdomain.example.com/"))
+
+=> {}
+```
+And scheme-relative routes:
+
+```clj
+(clout/route-matches
+ "//subdomain.example.com/"
+ (mock/request :get "http://subdomain.example.com/"))
+
+=> {}
+
+(clout/route-matches
+ "//subdomain.example.com/"
+ (mock/request :get "https://subdomain.example.com/"))
+
+=> {}
+```
+
+Clout supports both keywords and wildcards. Keywords (like ":title") will
+match any character but the following: `/ . , ; ?`. Wildcards (*) will match
+anything.
+
+If a route does not match, nil is returned:
+
+```clj
+(clout/route-matches "/products" (mock/request :get "/articles"))
+
+=> nil
+```
+
+For additional performance, you can choose to pre-compile a route:
+
+```clj
+(def user-route
+ (clout/route-compile "/user/:id"))
+
+(clout/route-matches user-route (mock/request :get "/user/10"))
+
+=> {:id "10"}
+```
+
+When compiling a route, you can specify a map of regular expressions to use
+for different keywords. This allows more specific routing:
+
+```clj
+(def user-route
+ (clout/route-compile "/user/:id" {:id #"\d+"}))
+
+(clout/route-matches user-route (mock/request :get "/user/10"))
+
+=> {:user "10"}
+
+(clout/route-matches user-route (mock/request :get "/user/jsmith"))
+
+=> nil
+```
+
+You can also specify regular expressions inline in braces after the
+keyword:
+
+```clj
+(def user-route
+ (clout/route-compile "/user/:id{\\d+}"))
+```
+
+Note that regular expression escape sequences (like `\d`) need to be
+double-escaped when placed inline in a string.
+
+## License
+
+Copyright © 2015 James Reeves
+
+Distributed under the Eclipse Public License either version 1.0 or (at
+your option) any later version.
diff --git a/project.clj b/project.clj
new file mode 100644
index 0000000..43b6e2e
--- /dev/null
+++ b/project.clj
@@ -0,0 +1,13 @@
+(defproject clout "2.1.2"
+ :description "A HTTP route matching library"
+ :url "https://github.com/weavejester/clout"
+ :license {:name "Eclipse Public License"
+ :url "http://www.eclipse.org/legal/epl-v10.html"}
+ :dependencies [[org.clojure/clojure "1.5.1"]
+ [instaparse "1.4.0" :exclusions [org.clojure/clojure]]]
+ :profiles
+ {:dev {:jvm-opts ^:replace []
+ :dependencies [[ring/ring-mock "0.2.0"]
+ [criterium "0.4.2"]]}
+ :1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]}
+ :1.7 {:dependencies [[org.clojure/clojure "1.7.0-beta2"]]}})
diff --git a/src/clout/core.clj b/src/clout/core.clj
new file mode 100644
index 0000000..afc324b
--- /dev/null
+++ b/src/clout/core.clj
@@ -0,0 +1,126 @@
+(ns clout.core
+ "A small language for routing."
+ (:require [clojure.string :as string]
+ [clojure.set :as set]
+ [instaparse.core :as insta]))
+
+(def ^:private re-chars (set "\\.*+|?()[]{}$^"))
+
+(defn- re-escape [s]
+ (string/escape s #(if (re-chars %) (str \\ %))))
+
+(defn- re-groups* [^java.util.regex.Matcher matcher]
+ (for [i (range (.groupCount matcher))]
+ (.group matcher (int (inc i)))))
+
+(defn- assoc-conj [m k v]
+ (assoc m k
+ (if-let [cur (get m k)]
+ (if (vector? cur)
+ (conj cur v)
+ [cur v])
+ v)))
+
+(defn- assoc-keys-with-groups [groups keys]
+ (reduce (fn [m [k v]] (assoc-conj m k v))
+ {}
+ (map vector keys groups)))
+
+(defn- request-url [request]
+ (str (name (:scheme request))
+ "://"
+ (get-in request [:headers "host"])
+ (:uri request)))
+
+(defn- path-info [request]
+ (or (:path-info request)
+ (:uri request)))
+
+(defprotocol Route
+ (route-matches [route request]
+ "If the route matches the supplied request, the matched keywords are
+ returned as a map. Otherwise, nil is returned."))
+
+(defrecord CompiledRoute [source re keys absolute?]
+ Route
+ (route-matches [_ request]
+ (let [path-info (if absolute?
+ (request-url request)
+ (path-info request))
+ matcher (re-matcher re path-info)]
+ (if (.matches matcher)
+ (assoc-keys-with-groups (re-groups* matcher) keys))))
+ Object
+ (toString [_] source))
+
+(def ^:private route-parser
+ (insta/parser
+ "route = (scheme / part) part*
+ scheme = #'(https?:)?//'
+
+ <part> = literal | escaped | wildcard | param
+ literal = #'(:[^\\p{L}_*{}\\\\]|[^:*{}\\\\])+'
+ escaped = #'\\\\.'
+ wildcard = '*'
+
+ param = key pattern?
+ key = <':'> #'([\\p{L}_][\\p{L}_0-9-]*)'
+ pattern = '{' (#'(?:[^{}\\\\]|\\\\.)+' | pattern)* '}'"
+ :no-slurp true))
+
+(defn- parse [parser text]
+ (let [result (insta/parse parser text)]
+ (if (insta/failure? result)
+ (throw (ex-info "Parse error in route string" {:failure result}))
+ result)))
+
+(defn- find-route-key [form]
+ (case (first form)
+ :wildcard :*
+ :param (-> form second second keyword)))
+
+(defn- route-keys [parse-tree]
+ (->> (rest parse-tree)
+ (filter (comp #{:param :wildcard} first))
+ (map find-route-key)))
+
+(defn- trim-pattern [pattern]
+ (some-> pattern (subs 1 (dec (count pattern)))))
+
+(defn- param-regex [regexs key & [pattern]]
+ (str "(" (or (trim-pattern pattern) (regexs key) "[^/,;?]+") ")"))
+
+(defn- route-regex [parse-tree regexs]
+ (insta/transform
+ {:route (comp re-pattern str)
+ :scheme #(if (= % "//") "https?://" %)
+ :literal re-escape
+ :escaped #(re-escape (subs % 1))
+ :wildcard (constantly "(.*?)")
+ :param (partial param-regex regexs)
+ :key keyword
+ :pattern str}
+ parse-tree))
+
+(defn- absolute-url? [path]
+ (boolean (re-matches #"(https?:)?//.*" path)))
+
+(defn route-compile
+ "Compile a route string for more efficient route matching."
+ ([path]
+ (route-compile path {}))
+ ([path regexs]
+ (let [ast (parse route-parser path)
+ ks (route-keys ast)]
+ (assert (set/subset? (set (keys regexs)) (set ks))
+ "unused keys in regular expression map")
+ (CompiledRoute.
+ path
+ (route-regex ast regexs)
+ (vec ks)
+ (absolute-url? path)))))
+
+(extend-type String
+ Route
+ (route-matches [route request]
+ (route-matches (route-compile route) request)))
diff --git a/test/clout/core_test.clj b/test/clout/core_test.clj
new file mode 100644
index 0000000..8023c54
--- /dev/null
+++ b/test/clout/core_test.clj
@@ -0,0 +1,127 @@
+(ns clout.core-test
+ (:import [clojure.lang ExceptionInfo]
+ [java.util.regex PatternSyntaxException])
+ (:require [clojure.test :refer :all]
+ [ring.mock.request :refer [request]]
+ [clout.core :refer :all]))
+
+(deftest fixed-path
+ (are [path] (route-matches path (request :get path))
+ "/"
+ "/foo"
+ "/foo/bar"
+ "/foo/bar.html"))
+
+(deftest keyword-paths
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/:x" "/foo" {:x "foo"}
+ "/foo/:x" "/foo/bar" {:x "bar"}
+ "/a/b/:c" "/a/b/c" {:c "c"}
+ "/:a/b/:c" "/a/b/c" {:a "a", :c "c"}))
+
+(deftest keywords-match-extensions
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/foo.:ext" "/foo.txt" {:ext "txt"}
+ "/:x.:y" "/foo.txt" {:x "foo", :y "txt"}))
+
+(deftest hyphen-keywords
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/:foo-bar" "/baz" {:foo-bar "baz"}
+ "/:foo-" "/baz" {:foo- "baz"}))
+
+(deftest underscore-keywords
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/:foo_bar" "/baz" {:foo_bar "baz"}
+ "/:_foo" "/baz" {:_foo "baz"}))
+
+(deftest urlencoded-keywords
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/:x" "/foo%20bar" {:x "foo%20bar"}
+ "/:x" "/foo+bar" {:x "foo+bar"}
+ "/:x" "/foo%5Cbar" {:x "foo%5Cbar"}))
+
+(deftest same-keyword-many-times
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/:x/:x/:x" "/a/b/c" {:x ["a" "b" "c"]}
+ "/:x/b/:x" "/a/b/c" {:x ["a" "c"]}))
+
+(deftest non-ascii-keywords
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/:äñßOÔ" "/abc" {:äñßOÔ "abc"}
+ "/:ÁäñßOÔ" "/abc" {:ÁäñßOÔ "abc"}
+ "/:ä/:ش" "/foo/bar" {:ä "foo" :ش "bar"}
+ "/:ä/:ä" "/foo/bar" {:ä ["foo" "bar"]}
+ "/:Ä-ü" "/baz" {:Ä-ü "baz"}
+ "/:Ä_ü" "/baz" {:Ä_ü "baz"}))
+
+(deftest wildcard-paths
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/*" "/foo" {:* "foo"}
+ "/*" "/foo.txt" {:* "foo.txt"}
+ "/*" "/foo/bar" {:* "foo/bar"}
+ "/foo/*" "/foo/bar/baz" {:* "bar/baz"}
+ "/a/*/d" "/a/b/c/d" {:* "b/c"}))
+
+(deftest escaped-chars
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/\\:foo" "/foo" nil
+ "/\\:foo" "/:foo" {}))
+
+(deftest inline-regexes
+ (are [path uri params] (= (route-matches path (request :get uri)) params)
+ "/:x{\\d+}" "/foo" nil
+ "/:x{\\d+}" "/10" {:x "10"}
+ "/:x{\\d{2}}" "/2" nil
+ "/:x{\\d{2}}" "/20" {:x "20"}
+ "/:x{\\d}/b" "/3/b" {:x "3"}
+ "/:x{\\d}/b" "/a/b" nil
+ "/a/:x{\\d}" "/a/4" {:x "4"}
+ "/a/:x{\\d}" "/a/b" nil))
+
+(deftest compiled-routes
+ (is (= (route-matches (route-compile "/foo/:id") (request :get "/foo/bar"))
+ {:id "bar"})))
+
+(deftest url-paths
+ (is (route-matches
+ "http://localhost/"
+ {:scheme :http
+ :headers {"host" "localhost"}
+ :uri "/"}))
+ (is (route-matches
+ "//localhost/"
+ {:scheme :http
+ :headers {"host" "localhost"}
+ :uri "/"}))
+ (is (route-matches
+ "//localhost/"
+ {:scheme :https
+ :headers {"host" "localhost"}
+ :uri "/"})))
+
+(deftest url-port-paths
+ (let [req (request :get "http://localhost:8080/")]
+ (is (route-matches "http://localhost:8080/" req))
+ (is (not (route-matches "http://localhost:7070/" req)))))
+
+(deftest unmatched-paths
+ (is (nil? (route-matches "/foo" (request :get "/bar")))))
+
+(deftest path-info-matches
+ (is (route-matches "/bar" (-> (request :get "/foo/bar")
+ (assoc :path-info "/bar")))))
+
+(deftest custom-matches
+ (let [route (route-compile "/foo/:bar" {:bar #"\d+"})]
+ (is (not (route-matches route (request :get "/foo/bar"))))
+ (is (not (route-matches route (request :get "/foo/1x"))))
+ (is (route-matches route (request :get "/foo/10")))))
+
+(deftest unused-regex-keys
+ (is (thrown? AssertionError (route-compile "/:foo" {:foa #"\d+"})))
+ (is (thrown? AssertionError (route-compile "/:foo" {:foo #"\d+" :bar #".*"}))))
+
+(deftest invalid-inline-patterns
+ (is (thrown? ExceptionInfo (route-compile "/:foo{")))
+ (is (thrown? ExceptionInfo (route-compile "/:foo{\\d{2}")))
+ (is (thrown? PatternSyntaxException (route-compile "/:foo{[a-z}"))))
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/clout-clojure.git
More information about the pkg-java-commits
mailing list