[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