From 4805555417a62844f7e89f68f8d136677a1317be Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Thu, 26 Oct 2017 19:25:09 +0300 Subject: [PATCH 01/12] Initial module split * metosin/reitit (all) * metosin/reitit-core (just the router) * metosin/reitit-ring (the ring stuff) --- .deps-versions.clj | 1 + lein-modules | 12 ++++++++++++ modules/reitit-core/project.clj | 7 +++++++ {src => modules/reitit-core/src}/reitit/core.cljc | 0 {src => modules/reitit-core/src}/reitit/impl.cljc | 0 {src => modules/reitit-core/src}/reitit/spec.cljc | 0 modules/reitit-ring/project.clj | 7 +++++++ .../reitit-ring/src}/reitit/coercion.cljc | 0 .../reitit-ring/src}/reitit/coercion/protocol.cljc | 0 .../reitit-ring/src}/reitit/coercion/spec.cljc | 0 .../reitit-ring/src}/reitit/middleware.cljc | 0 {src => modules/reitit-ring/src}/reitit/ring.cljc | 0 project.clj | 13 ++++++++----- 13 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 .deps-versions.clj create mode 100755 lein-modules create mode 100644 modules/reitit-core/project.clj rename {src => modules/reitit-core/src}/reitit/core.cljc (100%) rename {src => modules/reitit-core/src}/reitit/impl.cljc (100%) rename {src => modules/reitit-core/src}/reitit/spec.cljc (100%) create mode 100644 modules/reitit-ring/project.clj rename {src => modules/reitit-ring/src}/reitit/coercion.cljc (100%) rename {src => modules/reitit-ring/src}/reitit/coercion/protocol.cljc (100%) rename {src => modules/reitit-ring/src}/reitit/coercion/spec.cljc (100%) rename {src => modules/reitit-ring/src}/reitit/middleware.cljc (100%) rename {src => modules/reitit-ring/src}/reitit/ring.cljc (100%) diff --git a/.deps-versions.clj b/.deps-versions.clj new file mode 100644 index 00000000..cf72ad42 --- /dev/null +++ b/.deps-versions.clj @@ -0,0 +1 @@ +(def reitit-version "0.1.0-SNAPSHOT") diff --git a/lein-modules b/lein-modules new file mode 100755 index 00000000..2ed0c9ae --- /dev/null +++ b/lein-modules @@ -0,0 +1,12 @@ +#!/bin/bash + +# A script that walks the tree of Leiningen projects and does $* on them +# original: https://github.com/juxt/yada/blob/master/treelein + +# Modules +for ext in reitit-core reitit-ring; do + cd modules/$ext; lein $*; cd ../..; + done + +# Core +lein $* diff --git a/modules/reitit-core/project.clj b/modules/reitit-core/project.clj new file mode 100644 index 00000000..0bccf5d2 --- /dev/null +++ b/modules/reitit-core/project.clj @@ -0,0 +1,7 @@ +(load-file "../../.deps-versions.clj") +(defproject metosin/reitit-core reitit-version + :description "Snappy data-driven router for Clojure(Script)" + :url "https://github.com/metosin/reitit/tree/master/modules/reitit-core" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + :dependencies [[meta-merge "1.0.0"]]) diff --git a/src/reitit/core.cljc b/modules/reitit-core/src/reitit/core.cljc similarity index 100% rename from src/reitit/core.cljc rename to modules/reitit-core/src/reitit/core.cljc diff --git a/src/reitit/impl.cljc b/modules/reitit-core/src/reitit/impl.cljc similarity index 100% rename from src/reitit/impl.cljc rename to modules/reitit-core/src/reitit/impl.cljc diff --git a/src/reitit/spec.cljc b/modules/reitit-core/src/reitit/spec.cljc similarity index 100% rename from src/reitit/spec.cljc rename to modules/reitit-core/src/reitit/spec.cljc diff --git a/modules/reitit-ring/project.clj b/modules/reitit-ring/project.clj new file mode 100644 index 00000000..f8e9a625 --- /dev/null +++ b/modules/reitit-ring/project.clj @@ -0,0 +1,7 @@ +(load-file "../../.deps-versions.clj") +(defproject metosin/reitit-ring reitit-version + :description "Ring routing with reitit" + :url "https://github.com/metosin/reitit/tree/master/modules/reitit-ring" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + :dependencies [[metosin/reitit-core ~reitit-version]]) diff --git a/src/reitit/coercion.cljc b/modules/reitit-ring/src/reitit/coercion.cljc similarity index 100% rename from src/reitit/coercion.cljc rename to modules/reitit-ring/src/reitit/coercion.cljc diff --git a/src/reitit/coercion/protocol.cljc b/modules/reitit-ring/src/reitit/coercion/protocol.cljc similarity index 100% rename from src/reitit/coercion/protocol.cljc rename to modules/reitit-ring/src/reitit/coercion/protocol.cljc diff --git a/src/reitit/coercion/spec.cljc b/modules/reitit-ring/src/reitit/coercion/spec.cljc similarity index 100% rename from src/reitit/coercion/spec.cljc rename to modules/reitit-ring/src/reitit/coercion/spec.cljc diff --git a/src/reitit/middleware.cljc b/modules/reitit-ring/src/reitit/middleware.cljc similarity index 100% rename from src/reitit/middleware.cljc rename to modules/reitit-ring/src/reitit/middleware.cljc diff --git a/src/reitit/ring.cljc b/modules/reitit-ring/src/reitit/ring.cljc similarity index 100% rename from src/reitit/ring.cljc rename to modules/reitit-ring/src/reitit/ring.cljc diff --git a/project.clj b/project.clj index cff31f7a..d941c35b 100644 --- a/project.clj +++ b/project.clj @@ -1,17 +1,20 @@ -(defproject metosin/reitit "0.1.0-SNAPSHOT" +(load-file ".deps-versions.clj") +(defproject metosin/reitit reitit-version :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html" - :distribution :repo - :comments "same as Clojure"} + :url "http://www.eclipse.org/legal/epl-v10.html"} :test-paths ["test/clj" "test/cljc"] :deploy-repositories [["releases" :clojars]] :codox {:output-path "doc" :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} - :dependencies [[meta-merge "1.0.0"]] + :dependencies [[metosin/reitit-core ~reitit-version] + [metosin/reitit-ring ~reitit-version]] + + :source-paths ["modules/reitit-core/src" + "modules/reitit-ring/src"] :plugins [[jonase/eastwood "0.2.5"] [lein-doo "0.1.8"] From 460ba5ecc0076f860189642035f52c81d3eaed00 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Fri, 27 Oct 2017 08:14:55 +0300 Subject: [PATCH 02/12] Fix based on Miikka's comments --- lein-modules | 8 +++++--- modules/reitit-core/project.clj | 2 +- modules/reitit-ring/project.clj | 2 +- project.clj | 5 ++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lein-modules b/lein-modules index 2ed0c9ae..f9fe5708 100755 --- a/lein-modules +++ b/lein-modules @@ -3,10 +3,12 @@ # A script that walks the tree of Leiningen projects and does $* on them # original: https://github.com/juxt/yada/blob/master/treelein +set -e + # Modules for ext in reitit-core reitit-ring; do - cd modules/$ext; lein $*; cd ../..; - done + cd modules/$ext; lein $@; cd ../..; +done # Core -lein $* +lein $@ diff --git a/modules/reitit-core/project.clj b/modules/reitit-core/project.clj index 0bccf5d2..72e9d8ef 100644 --- a/modules/reitit-core/project.clj +++ b/modules/reitit-core/project.clj @@ -1,7 +1,7 @@ (load-file "../../.deps-versions.clj") (defproject metosin/reitit-core reitit-version :description "Snappy data-driven router for Clojure(Script)" - :url "https://github.com/metosin/reitit/tree/master/modules/reitit-core" + :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[meta-merge "1.0.0"]]) diff --git a/modules/reitit-ring/project.clj b/modules/reitit-ring/project.clj index f8e9a625..59e95ff6 100644 --- a/modules/reitit-ring/project.clj +++ b/modules/reitit-ring/project.clj @@ -1,7 +1,7 @@ (load-file "../../.deps-versions.clj") (defproject metosin/reitit-ring reitit-version :description "Ring routing with reitit" - :url "https://github.com/metosin/reitit/tree/master/modules/reitit-ring" + :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[metosin/reitit-core ~reitit-version]]) diff --git a/project.clj b/project.clj index d941c35b..6353b147 100644 --- a/project.clj +++ b/project.clj @@ -13,9 +13,6 @@ :dependencies [[metosin/reitit-core ~reitit-version] [metosin/reitit-ring ~reitit-version]] - :source-paths ["modules/reitit-core/src" - "modules/reitit-ring/src"] - :plugins [[jonase/eastwood "0.2.5"] [lein-doo "0.1.8"] [lein-cljsbuild "1.1.7"] @@ -24,6 +21,8 @@ [metosin/boot-alt-test "0.4.0-20171019.180106-3"]] :profiles {:dev {:jvm-opts ^:replace ["-server"] + :source-paths ["modules/reitit-core/src" + "modules/reitit-ring/src"] :dependencies [[org.clojure/clojure "1.9.0-beta2"] [org.clojure/clojurescript "1.9.946"] From 7aa36fc18b98e38d97724639dd46eb0058a70a52 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 28 Oct 2017 12:14:16 +0300 Subject: [PATCH 03/12] Fix script based on Miikka's comments --- lein-modules | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lein-modules b/lein-modules index f9fe5708..feab8f2e 100755 --- a/lein-modules +++ b/lein-modules @@ -1,14 +1,8 @@ #!/bin/bash -# A script that walks the tree of Leiningen projects and does $* on them -# original: https://github.com/juxt/yada/blob/master/treelein - set -e # Modules -for ext in reitit-core reitit-ring; do - cd modules/$ext; lein $@; cd ../..; +for ext in reitit-core reitit-ring reitit-spec reitit; do + cd modules/$ext; lein "$@"; cd ../..; done - -# Core -lein $@ From f93a4522095ef448a19708dd1d76eb0110e091e3 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 28 Oct 2017 12:17:20 +0300 Subject: [PATCH 04/12] Re-package & re-module --- modules/reitit-ring/project.clj | 2 +- modules/reitit-ring/src/reitit/ring.cljc | 10 +++++----- .../src/reitit/{ => ring}/coercion.cljc | 6 +++--- .../reitit/{ => ring}/coercion/protocol.cljc | 2 +- .../src/reitit/{ => ring}/middleware.cljc | 8 ++++---- modules/reitit-spec/project.clj | 8 ++++++++ .../src/reitit/ring}/coercion/spec.cljc | 4 ++-- modules/reitit/project.clj | 9 +++++++++ perf-test/clj/reitit/coercion_perf_test.clj | 4 ++-- .../clj/reitit/opensensors_routing_test.clj | 2 +- project.clj | 18 ++++++++++-------- test/cljc/reitit/coercion_test.cljc | 4 ++-- test/cljc/reitit/middleware_test.cljc | 2 +- test/cljc/reitit/ring_test.cljc | 4 ++-- 14 files changed, 51 insertions(+), 32 deletions(-) rename modules/reitit-ring/src/reitit/{ => ring}/coercion.cljc (98%) rename modules/reitit-ring/src/reitit/{ => ring}/coercion/protocol.cljc (95%) rename modules/reitit-ring/src/reitit/{ => ring}/middleware.cljc (95%) create mode 100644 modules/reitit-spec/project.clj rename modules/{reitit-ring/src/reitit => reitit-spec/src/reitit/ring}/coercion/spec.cljc (97%) create mode 100644 modules/reitit/project.clj diff --git a/modules/reitit-ring/project.clj b/modules/reitit-ring/project.clj index 59e95ff6..a2862352 100644 --- a/modules/reitit-ring/project.clj +++ b/modules/reitit-ring/project.clj @@ -1,6 +1,6 @@ (load-file "../../.deps-versions.clj") (defproject metosin/reitit-ring reitit-version - :description "Ring routing with reitit" + :description "Reitit: Ring routing" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} diff --git a/modules/reitit-ring/src/reitit/ring.cljc b/modules/reitit-ring/src/reitit/ring.cljc index f866b705..dfb13eb4 100644 --- a/modules/reitit-ring/src/reitit/ring.cljc +++ b/modules/reitit-ring/src/reitit/ring.cljc @@ -1,7 +1,7 @@ (ns reitit.ring (:require [meta-merge.core :refer [meta-merge]] - [reitit.middleware :as middleware] - [reitit.core :as reitit] + [reitit.ring.middleware :as middleware] + [reitit.core :as r] [reitit.impl :as impl])) (def http-methods #{:get :head :patch :delete :options :post :put}) @@ -18,7 +18,7 @@ (with-meta (fn ([request] - (if-let [match (reitit/match-by-path router (:uri request))] + (if-let [match (r/match-by-path router (:uri request))] (let [method (:request-method request :any) params (:params match) result (:result match) @@ -29,7 +29,7 @@ (cond-> (impl/fast-assoc request ::match match) (seq params) (impl/fast-assoc :path-params params))))))) ([request respond raise] - (if-let [match (reitit/match-by-path router (:uri request))] + (if-let [match (r/match-by-path router (:uri request))] (let [method (:request-method request :any) params (:params match) result (:result match) @@ -73,4 +73,4 @@ (router data nil)) ([data opts] (let [opts (meta-merge {:coerce coerce-handler, :compile compile-result} opts)] - (reitit/router data opts)))) + (r/router data opts)))) diff --git a/modules/reitit-ring/src/reitit/coercion.cljc b/modules/reitit-ring/src/reitit/ring/coercion.cljc similarity index 98% rename from modules/reitit-ring/src/reitit/coercion.cljc rename to modules/reitit-ring/src/reitit/ring/coercion.cljc index ae2fffdc..39245b12 100644 --- a/modules/reitit-ring/src/reitit/coercion.cljc +++ b/modules/reitit-ring/src/reitit/ring/coercion.cljc @@ -1,8 +1,8 @@ -(ns reitit.coercion +(ns reitit.ring.coercion (:require [clojure.walk :as walk] [spec-tools.core :as st] - [reitit.coercion.protocol :as protocol] - [reitit.middleware :as middleware] + [reitit.ring.middleware :as middleware] + [reitit.ring.coercion.protocol :as protocol] [reitit.ring :as ring] [reitit.impl :as impl])) diff --git a/modules/reitit-ring/src/reitit/coercion/protocol.cljc b/modules/reitit-ring/src/reitit/ring/coercion/protocol.cljc similarity index 95% rename from modules/reitit-ring/src/reitit/coercion/protocol.cljc rename to modules/reitit-ring/src/reitit/ring/coercion/protocol.cljc index aaacb41a..eb8a961f 100644 --- a/modules/reitit-ring/src/reitit/coercion/protocol.cljc +++ b/modules/reitit-ring/src/reitit/ring/coercion/protocol.cljc @@ -1,4 +1,4 @@ -(ns reitit.coercion.protocol +(ns reitit.ring.coercion.protocol (:refer-clojure :exclude [compile])) (defprotocol Coercion diff --git a/modules/reitit-ring/src/reitit/middleware.cljc b/modules/reitit-ring/src/reitit/ring/middleware.cljc similarity index 95% rename from modules/reitit-ring/src/reitit/middleware.cljc rename to modules/reitit-ring/src/reitit/ring/middleware.cljc index 18bceeb1..420dde6e 100644 --- a/modules/reitit-ring/src/reitit/middleware.cljc +++ b/modules/reitit-ring/src/reitit/ring/middleware.cljc @@ -1,6 +1,6 @@ -(ns reitit.middleware +(ns reitit.ring.middleware (:require [meta-merge.core :refer [meta-merge]] - [reitit.core :as reitit])) + [reitit.core :as r])) (defprotocol IntoMiddleware (into-middleware [this meta opts])) @@ -91,13 +91,13 @@ (router data nil)) ([data opts] (let [opts (meta-merge {:compile compile-result} opts)] - (reitit/router data opts)))) + (r/router data opts)))) (defn middleware-handler [router] (with-meta (fn [path] (some->> path - (reitit/match-by-path router) + (r/match-by-path router) :result :handler)) {::router router})) diff --git a/modules/reitit-spec/project.clj b/modules/reitit-spec/project.clj new file mode 100644 index 00000000..b811c5e9 --- /dev/null +++ b/modules/reitit-spec/project.clj @@ -0,0 +1,8 @@ +(load-file "../../.deps-versions.clj") +(defproject metosin/reitit-spec reitit-version + :description "Reitit: clojure.spec coercion" + :url "https://github.com/metosin/reitit" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + :dependencies [[metosin/reitit-ring ~reitit-version] + [metosin/spec-tools "0.5.0"]]) diff --git a/modules/reitit-ring/src/reitit/coercion/spec.cljc b/modules/reitit-spec/src/reitit/ring/coercion/spec.cljc similarity index 97% rename from modules/reitit-ring/src/reitit/coercion/spec.cljc rename to modules/reitit-spec/src/reitit/ring/coercion/spec.cljc index f1f2fb00..a2afa3c8 100644 --- a/modules/reitit-ring/src/reitit/coercion/spec.cljc +++ b/modules/reitit-spec/src/reitit/ring/coercion/spec.cljc @@ -1,10 +1,10 @@ -(ns reitit.coercion.spec +(ns reitit.ring.coercion.spec (:require [clojure.spec.alpha :as s] [spec-tools.core :as st #?@(:cljs [:refer [Spec]])] [spec-tools.data-spec :as ds] [spec-tools.conform :as conform] [spec-tools.swagger.core :as swagger] - [reitit.coercion.protocol :as protocol]) + [reitit.ring.coercion.protocol :as protocol]) #?(:clj (:import (spec_tools.core Spec)))) diff --git a/modules/reitit/project.clj b/modules/reitit/project.clj new file mode 100644 index 00000000..8ebf9a18 --- /dev/null +++ b/modules/reitit/project.clj @@ -0,0 +1,9 @@ +(load-file "../../.deps-versions.clj") +(defproject metosin/reitit reitit-version + :description "Snappy data-driven router for Clojure(Script)" + :url "https://github.com/metosin/reitit" + :license {:name "Eclipse Public License" + :url "http://www.eclipse.org/legal/epl-v10.html"} + :dependencies [[metosin/reitit-core ~reitit-version] + [metosin/reitit-ring ~reitit-version] + [metosin/reitit-spec ~reitit-version]]) diff --git a/perf-test/clj/reitit/coercion_perf_test.clj b/perf-test/clj/reitit/coercion_perf_test.clj index 11f161f0..d0351450 100644 --- a/perf-test/clj/reitit/coercion_perf_test.clj +++ b/perf-test/clj/reitit/coercion_perf_test.clj @@ -6,7 +6,7 @@ [spec-tools.core :as st] [reitit.core :as reitit] - [reitit.ring :as ring] + [reitit.core :as ring] [reitit.coercion :as coercion] [reitit.coercion.spec :as spec] [reitit.coercion.protocol :as protocol] @@ -145,7 +145,7 @@ (comment (do - (require '[reitit.ring :as ring]) + (require '[reitit.core :as ring]) (require '[reitit.coercion :as coercion]) (require '[reitit.coercion.spec :as spec]) diff --git a/perf-test/clj/reitit/opensensors_routing_test.clj b/perf-test/clj/reitit/opensensors_routing_test.clj index a5ee7a89..a9f194fb 100644 --- a/perf-test/clj/reitit/opensensors_routing_test.clj +++ b/perf-test/clj/reitit/opensensors_routing_test.clj @@ -5,7 +5,7 @@ [cheshire.core :as json] [clojure.string :as str] [reitit.core :as reitit] - [reitit.ring :as ring] + [reitit.core :as ring] [bidi.bidi :as bidi] diff --git a/project.clj b/project.clj index 6353b147..5f97c273 100644 --- a/project.clj +++ b/project.clj @@ -10,9 +10,6 @@ :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} - :dependencies [[metosin/reitit-core ~reitit-version] - [metosin/reitit-ring ~reitit-version]] - :plugins [[jonase/eastwood "0.2.5"] [lein-doo "0.1.8"] [lein-cljsbuild "1.1.7"] @@ -21,13 +18,18 @@ [metosin/boot-alt-test "0.4.0-20171019.180106-3"]] :profiles {:dev {:jvm-opts ^:replace ["-server"] - :source-paths ["modules/reitit-core/src" - "modules/reitit-ring/src"] + + ;; all module sources for development + :source-paths ["modules/reitit/src" + "modules/reitit-core/src" + "modules/reitit-ring/src" + "modules/reitit-spec/src"] + :dependencies [[org.clojure/clojure "1.9.0-beta2"] [org.clojure/clojurescript "1.9.946"] - [metosin/spec-tools "0.5.0"] - [org.clojure/spec.alpha "0.1.134"] + ;; all modules dependencies + [metosin/reitit ~reitit-version] [expound "0.3.1"] [orchestra "2017.08.13"] @@ -40,7 +42,7 @@ "-Xmx4096m" "-Dclojure.compiler.direct-linking=true"] :test-paths ["perf-test/clj"] - :dependencies [[metosin/compojure-api "2.0.0-alpha10"] + :dependencies [[metosin/compojure-api "2.0.0-alpha12"] [io.pedestal/pedestal.route "0.5.3"] [org.clojure/core.async "0.3.443"] [ataraxy "0.4.0"] diff --git a/test/cljc/reitit/coercion_test.cljc b/test/cljc/reitit/coercion_test.cljc index 20057b8c..1873ca57 100644 --- a/test/cljc/reitit/coercion_test.cljc +++ b/test/cljc/reitit/coercion_test.cljc @@ -1,8 +1,8 @@ (ns reitit.coercion-test (:require [clojure.test :refer [deftest testing is]] [reitit.ring :as ring] - [reitit.coercion :as coercion] - [reitit.coercion.spec :as spec]) + [reitit.ring.coercion :as coercion] + [reitit.ring.coercion.spec :as spec]) #?(:clj (:import (clojure.lang ExceptionInfo)))) diff --git a/test/cljc/reitit/middleware_test.cljc b/test/cljc/reitit/middleware_test.cljc index b77329c8..8120b101 100644 --- a/test/cljc/reitit/middleware_test.cljc +++ b/test/cljc/reitit/middleware_test.cljc @@ -1,6 +1,6 @@ (ns reitit.middleware-test (:require [clojure.test :refer [deftest testing is are]] - [reitit.middleware :as middleware] + [reitit.ring.middleware :as middleware] [clojure.set :as set] [reitit.core :as r]) #?(:clj diff --git a/test/cljc/reitit/ring_test.cljc b/test/cljc/reitit/ring_test.cljc index c9c5844a..e85707ad 100644 --- a/test/cljc/reitit/ring_test.cljc +++ b/test/cljc/reitit/ring_test.cljc @@ -1,8 +1,8 @@ (ns reitit.ring-test (:require [clojure.test :refer [deftest testing is]] - [reitit.middleware :as middleware] - [reitit.ring :as ring] [clojure.set :as set] + [reitit.ring.middleware :as middleware] + [reitit.ring :as ring] [reitit.core :as r]) #?(:clj (:import (clojure.lang ExceptionInfo)))) From a3ebb04038987c2e4ccb53f2030ef5cd9c2dd4ca Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 28 Oct 2017 12:47:55 +0300 Subject: [PATCH 05/12] Manage dependencies via lein-parent --- .deps-versions.clj | 1 - modules/reitit-core/project.clj | 10 +++++++--- modules/reitit-ring/project.clj | 10 +++++++--- modules/reitit-spec/project.clj | 12 ++++++++---- modules/reitit/project.clj | 14 +++++++++----- project.clj | 16 ++++++++++++---- 6 files changed, 43 insertions(+), 20 deletions(-) delete mode 100644 .deps-versions.clj diff --git a/.deps-versions.clj b/.deps-versions.clj deleted file mode 100644 index cf72ad42..00000000 --- a/.deps-versions.clj +++ /dev/null @@ -1 +0,0 @@ -(def reitit-version "0.1.0-SNAPSHOT") diff --git a/modules/reitit-core/project.clj b/modules/reitit-core/project.clj index 72e9d8ef..f7a4454a 100644 --- a/modules/reitit-core/project.clj +++ b/modules/reitit-core/project.clj @@ -1,7 +1,11 @@ -(load-file "../../.deps-versions.clj") -(defproject metosin/reitit-core reitit-version +(def VERSION "0.1.0-SNAPSHOT") + +(defproject metosin/reitit-core VERSION :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[meta-merge "1.0.0"]]) + :plugins [[lein-parent "0.3.2"]] + :parent-project {:path "../../project.clj" + :inherit [:deploy-repositories :managed-dependencies]} + :dependencies [[meta-merge]]) diff --git a/modules/reitit-ring/project.clj b/modules/reitit-ring/project.clj index a2862352..1c061c81 100644 --- a/modules/reitit-ring/project.clj +++ b/modules/reitit-ring/project.clj @@ -1,7 +1,11 @@ -(load-file "../../.deps-versions.clj") -(defproject metosin/reitit-ring reitit-version +(def VERSION "0.1.0-SNAPSHOT") + +(defproject metosin/reitit-ring VERSION :description "Reitit: Ring routing" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[metosin/reitit-core ~reitit-version]]) + :plugins [[lein-parent "0.3.2"]] + :parent-project {:path "../../project.clj" + :inherit [:deploy-repositories :managed-dependencies]} + :dependencies [[metosin/reitit-core]]) diff --git a/modules/reitit-spec/project.clj b/modules/reitit-spec/project.clj index b811c5e9..91745cb5 100644 --- a/modules/reitit-spec/project.clj +++ b/modules/reitit-spec/project.clj @@ -1,8 +1,12 @@ -(load-file "../../.deps-versions.clj") -(defproject metosin/reitit-spec reitit-version +(def VERSION "0.1.0-SNAPSHOT") + +(defproject metosin/reitit-spec VERSION :description "Reitit: clojure.spec coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[metosin/reitit-ring ~reitit-version] - [metosin/spec-tools "0.5.0"]]) + :plugins [[lein-parent "0.3.2"]] + :parent-project {:path "../../project.clj" + :inherit [:deploy-repositories :managed-dependencies]} + :dependencies [[metosin/reitit-ring] + [metosin/spec-tools]]) diff --git a/modules/reitit/project.clj b/modules/reitit/project.clj index 8ebf9a18..b26a813d 100644 --- a/modules/reitit/project.clj +++ b/modules/reitit/project.clj @@ -1,9 +1,13 @@ -(load-file "../../.deps-versions.clj") -(defproject metosin/reitit reitit-version +(def VERSION "0.1.0-SNAPSHOT") + +(defproject metosin/reitit VERSION :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[metosin/reitit-core ~reitit-version] - [metosin/reitit-ring ~reitit-version] - [metosin/reitit-spec ~reitit-version]]) + :plugins [[lein-parent "0.3.2"]] + :parent-project {:path "../../project.clj" + :inherit [:deploy-repositories :managed-dependencies]} + :dependencies [[metosin/reitit-core] + [metosin/reitit-ring] + [metosin/reitit-spec]]) diff --git a/project.clj b/project.clj index 5f97c273..6325e0ed 100644 --- a/project.clj +++ b/project.clj @@ -1,5 +1,6 @@ -(load-file ".deps-versions.clj") -(defproject metosin/reitit reitit-version +(def VERSION "0.1.0-SNAPSHOT") + +(defproject metosin/reitit VERSION :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" @@ -10,6 +11,13 @@ :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} + :managed-dependencies [[metosin/reitit-core ~VERSION] + [metosin/reitit-ring ~VERSION] + [metosin/reitit-spec ~VERSION] + + [meta-merge "1.0.0"] + [metosin/spec-tools "0.5.0"]] + :plugins [[jonase/eastwood "0.2.5"] [lein-doo "0.1.8"] [lein-cljsbuild "1.1.7"] @@ -29,12 +37,12 @@ [org.clojure/clojurescript "1.9.946"] ;; all modules dependencies - [metosin/reitit ~reitit-version] + [metosin/reitit] [expound "0.3.1"] [orchestra "2017.08.13"] - [criterium "0.4.4"] + [criterium] [org.clojure/test.check "0.9.0"] [org.clojure/tools.namespace "0.2.11"] [com.gfredericks/test.chuck "0.2.8"]]} From 7a730a1b7e81ce811f4d264377131814c503c126 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 28 Oct 2017 12:52:33 +0300 Subject: [PATCH 06/12] Script to setup versin * original: https://github.com/juxt/yada/blob/master/set-version --- set-version | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 set-version diff --git a/set-version b/set-version new file mode 100755 index 00000000..ddad9fa9 --- /dev/null +++ b/set-version @@ -0,0 +1,6 @@ +#!/bin/sh + +ext="sedbak$$" + +find . -name project.clj -exec sed -i.$ext "s/(def VERSION \".*\")/(def VERSION \"$1\")/g" '{}' \; +find . -name "*.$ext" -exec rm '{}' \; \ No newline at end of file From 51a5ee267b07db7f76ee6ee1d6fb48cab444dac0 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 28 Oct 2017 13:00:15 +0300 Subject: [PATCH 07/12] Try to fix .travis conf --- .travis.yml | 1 + project.clj | 5 +++-- lein-modules => scripts/lein-modules | 0 set-version => scripts/set-version | 0 4 files changed, 4 insertions(+), 2 deletions(-) rename lein-modules => scripts/lein-modules (100%) rename set-version => scripts/set-version (100%) diff --git a/.travis.yml b/.travis.yml index 79f2f2f2..9272e162 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ sudo: false language: clojure lein: 2.7.1 install: + - ./scripts/lein-modules install - lein deps - npm install script: diff --git a/project.clj b/project.clj index 6325e0ed..0ea941ea 100644 --- a/project.clj +++ b/project.clj @@ -11,7 +11,8 @@ :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} - :managed-dependencies [[metosin/reitit-core ~VERSION] + :managed-dependencies [[metosin/reitit ~VERSION] + [metosin/reitit-core ~VERSION] [metosin/reitit-ring ~VERSION] [metosin/reitit-spec ~VERSION] @@ -42,7 +43,7 @@ [expound "0.3.1"] [orchestra "2017.08.13"] - [criterium] + [criterium "0.4.4"] [org.clojure/test.check "0.9.0"] [org.clojure/tools.namespace "0.2.11"] [com.gfredericks/test.chuck "0.2.8"]]} diff --git a/lein-modules b/scripts/lein-modules similarity index 100% rename from lein-modules rename to scripts/lein-modules diff --git a/set-version b/scripts/set-version similarity index 100% rename from set-version rename to scripts/set-version From 60e0ee4872c1f9622d2268c97bf018d737c6c548 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 28 Oct 2017 13:21:25 +0300 Subject: [PATCH 08/12] Welcome reitit-parent --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 0ea941ea..2b7f3fee 100644 --- a/project.clj +++ b/project.clj @@ -1,6 +1,6 @@ (def VERSION "0.1.0-SNAPSHOT") -(defproject metosin/reitit VERSION +(defproject metosin/reitit-parent VERSION :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" From 9a7eaaa912a750eb63b9250ca363f4dc15d2d798 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sat, 28 Oct 2017 13:21:35 +0300 Subject: [PATCH 09/12] Oh, we have circeci too --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index fdfe969b..adc1033d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,6 +10,9 @@ jobs: keys: - 'v1-test-{{ checksum "project.clj" }}' - 'v1-test-' + - run: + name: Install modules + command: ./scripts/lein-modules install - run: name: Run tests command: ./scripts/test.sh clj From d44b18ad661243c5d6de65ffc80c3bb0a27d28ed Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 29 Oct 2017 09:30:48 +0200 Subject: [PATCH 10/12] Build instructions --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 589291a7..b1132ccc 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,20 @@ gitbook install gitbook serve ``` +To raise the version: + +```bash +# new version +./scripts/set-version "1.0.0" +./scripts/lein-modules install + +# works +lein test + +# deploy to clojars +./scripts/lein-modules do clean, deploy clojars +``` + ## License Copyright © 2017 [Metosin Oy](http://www.metosin.fi) From c3820239c51e6eca5f13421f2b8eccf28d837485 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Mon, 30 Oct 2017 08:46:20 +0200 Subject: [PATCH 11/12] Walk the docs, fix links, maybe better texts --- README.md | 41 ++++++-- doc/SUMMARY.md | 5 +- doc/advanced/README.md | 6 +- doc/advanced/different_routers.md | 18 ++++ doc/advanced/route_validation.md | 14 +-- doc/basics/README.md | 12 +-- doc/basics/different_routers.md | 17 ---- doc/basics/name_based_routing.md | 38 +++++++- doc/basics/path_based_routing.md | 16 +++ doc/{advanced => basics}/route_conflicts.md | 12 +-- doc/basics/route_data.md | 97 ++++++++++++++----- doc/basics/route_syntax.md | 11 ++- doc/basics/router.md | 21 +++- doc/ring/README.md | 1 + doc/ring/compiling_middleware.md | 25 +++-- .../data_driven_middleware.md} | 12 ++- doc/ring/dynamic_extensions.md | 4 +- doc/ring/parameter_coercion.md | 20 ++-- doc/ring/ring.md | 10 +- .../reitit-ring/src/reitit/ring/coercion.cljc | 2 +- 20 files changed, 265 insertions(+), 117 deletions(-) create mode 100644 doc/advanced/different_routers.md delete mode 100644 doc/basics/different_routers.md rename doc/{advanced => basics}/route_conflicts.md (61%) rename doc/{middleware_records.md => ring/data_driven_middleware.md} (52%) diff --git a/README.md b/README.md index b1132ccc..1f07ac1f 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,47 @@ -# reitit [![Build Status](https://travis-ci.org/metosin/reitit.svg?branch=master)](https://travis-ci.org/metosin/reitit) [![Dependencies Status](https://jarkeeper.com/metosin/reitit/status.svg)](https://jarkeeper.com/metosin/reitit) +# reitit [![Build Status](https://travis-ci.org/metosin/reitit.svg?branch=master)](https://travis-ci.org/metosin/reitit) A friendly data-driven router for Clojure(Script). -* Simple data-driven [route syntax](https://metosin.github.io/reitit/basics/route_syntax.md) -* [Route conflict resolution](https://metosin.github.io/reitit/advanced/route_conflicts.md) -* First-class [route meta-data](https://metosin.github.io/reitit/basics/route_data.md) +* Simple data-driven [route syntax](https://metosin.github.io/reitit/basics/route_syntax.html) +* Route [conflict resolution](https://metosin.github.io/reitit/basics/route_conflicts.html) +* First-class [route meta-data](https://metosin.github.io/reitit/basics/route_data.html) * Bi-directional routing -* [Pluggable coercion](https://metosin.github.io/reitit/ring/parameter_coercion.md) ([clojure.spec](https://clojure.org/about/spec)) -* supports both [Middleware](https://metosin.github.io/reitit/ring/compiling_middleware.md) & Interceptors +* [Ring-router](https://metosin.github.io/reitit/ring.html) with data-driven [middleware](https://metosin.github.io/reitit/ring/compiling_middleware.html) +* [Pluggable coercion](https://metosin.github.io/reitit/ring/parameter_coercion.html) ([clojure.spec](https://clojure.org/about/spec)) * Extendable * Fast -Ships with example router for [Ring](#ring). See [Issues](https://github.com/metosin/reitit/issues) for roadmap. +See [Issues](https://github.com/metosin/reitit/issues) for roadmap. ## Latest version [![Clojars Project](http://clojars.org/metosin/reitit/latest-version.svg)](http://clojars.org/metosin/reitit) +## Quick start + +```clj +(require '[reitit.core :as r]) + +(def router + (r/router + [["/api/ping" ::ping] + ["/api/orders/:id" ::order-by-id]])) + +(r/match-by-path router "/api/ping") +; #Match{:template "/api/ping" +; :meta {:name ::ping} +; :result nil +; :params {} +; :path "/api/ping"} + +(r/match-by-name router ::order-by-id {:id 2}) +; #Match{:template "/api/orders/:id", +; :meta {:name ::order-by-id}, +; :result nil, +; :params {:id 2}, +; :path "/api/orders/2"} +``` + ## Documentation [Check out the full documentation!](https://metosin.github.io/reitit/) @@ -41,7 +66,7 @@ gitbook install gitbook serve ``` -To raise the version: +To bump up version: ```bash # new version diff --git a/doc/SUMMARY.md b/doc/SUMMARY.md index feb44aba..5cbcdd34 100644 --- a/doc/SUMMARY.md +++ b/doc/SUMMARY.md @@ -7,14 +7,15 @@ * [Path-based Routing](basics/path_based_routing.md) * [Name-based Routing](basics/name_based_routing.md) * [Route data](basics/route_data.md) - * [Different Routers](basics/different_routers.md) + * [Route conflicts](basics/route_conflicts.md) * [Advanced](advanced/README.md) - * [Route conflicts](advanced/route_conflicts.md) * [Route Validation](advanced/route_validation.md) + * [Different Routers](advanced/different_routers.md) * [Configuring routers](advanced/configuring_routers.md) * [Ring](ring/README.md) * [Ring-router](ring/ring.md) * [Dynamic extensions](ring/dynamic_extensions.md) + * [Data-driven Middleware](ring/data_driven_middleware.md) * [Parameter coercion](ring/parameter_coercion.md) * [Compiling middleware](ring/compiling_middleware.md) * TODO: Swagger & OpenAPI diff --git a/doc/advanced/README.md b/doc/advanced/README.md index 6dccc442..cbea0749 100644 --- a/doc/advanced/README.md +++ b/doc/advanced/README.md @@ -1,5 +1,5 @@ # Advanced -* [Route conflicts](advanced/route_conflicts.md) -* [Route Validation](advanced/route_validation.md) -* [Configuring routers](advanced/configuring_routers.md) +* [Route Validation](route_validation.md) +* [Different Routers](different_routers.md) +* [Configuring routers](configuring_routers.md) diff --git a/doc/advanced/different_routers.md b/doc/advanced/different_routers.md new file mode 100644 index 00000000..ae742760 --- /dev/null +++ b/doc/advanced/different_routers.md @@ -0,0 +1,18 @@ +# Different Routers + +Reitit ships with several different implementations for the `Router` protocol, originally based on the [Pedestal](https://github.com/pedestal/pedestal/tree/master/route) implementation. `router` selects the most suitable implementation by inspecting the expanded routes. The implementation can be set manually using `:router` option, see [configuring routers](advanced/configuring_routers.md). + +| router | description | +| ------------------------------|-------------| +| `:linear-router` | Matches the routes one-by-one starting from the top until a match is found. Works with any kind of routes. +| `:lookup-router` | Fast router, uses hash-lookup to resolve the route. Valid if no paths have path or catch-all parameters. +| `:mixed-router` | Creates internally a `:linear-router` and a `:lookup-router` and used them to effectively get best-of-both-worlds. Valid if there are no [Route conflicts](../basics/route_conflicts.md). +| `::single-static-path-router` | Fastest possible router: valid only if there is one static route. +| `:prefix-tree-router` | TODO: https://github.com/julienschmidt/httprouter#how-does-it-work + +The router name can be asked from the router + +```clj +(r/router-name router) +; :mixed-router +``` diff --git a/doc/advanced/route_validation.md b/doc/advanced/route_validation.md index 991d5c83..80ef1bcd 100644 --- a/doc/advanced/route_validation.md +++ b/doc/advanced/route_validation.md @@ -4,12 +4,11 @@ Namespace `reitit.spec` contains [clojure.spec](https://clojure.org/about/spec) **NOTE:** Use of specs requires to use one of the following: -* `[org.clojure/clojurescript "1.9.660"]` -* `[org.clojure/clojure "1.9.0-alpha19"]` -* `[clojure-future-spec "1.9.0-alpha17"]` (Clojure 1.8) +* `[org.clojure/clojurescript "1.9.660"]` (or higher) +* `[org.clojure/clojure "1.9.0-beta2"]` (or higher) +* `[clojure-future-spec "1.9.0-alpha17"]` (if Clojure 1.8 is used) -## At runtime -If route trees are generated at runtime (e.g. from external source like the database), one can use directly the `clojure.spec` functions. +## Example ```clj (require '[clojure.spec.alpha :as s]) @@ -36,7 +35,7 @@ If route trees are generated at runtime (e.g. from external source like the data First add a `:dev` dependency to: ```clj -[expound "0.3.0"] +[expound "0.3.0"] ; or higher ``` Some bootstrapping: @@ -54,8 +53,9 @@ Some bootstrapping: And we are ready to go: ```clj +(require '[reitit.core :as r]) -(reitit/router +(r/router ["/api" ["/public" ["/ping"] diff --git a/doc/basics/README.md b/doc/basics/README.md index b92e5f81..1dec603b 100644 --- a/doc/basics/README.md +++ b/doc/basics/README.md @@ -1,8 +1,8 @@ # Basics -* [Route syntax](basics/route_syntax.md) -* [Router](basics/router.md) -* [Path-based Routing](basics/path_based_routing.md) -* [Name-based Routing](basics/name_based_routing.md) -* [Route data](basics/route_data.md) -* [Different Routers](basics/different_routers.md) +* [Route syntax](route_syntax.md) +* [Router](router.md) +* [Path-based Routing](path_based_routing.md) +* [Name-based Routing](name_based_routing.md) +* [Route data](route_data.md) +* [Route conflicts](route_conflicts.md) diff --git a/doc/basics/different_routers.md b/doc/basics/different_routers.md deleted file mode 100644 index d5a8ca1a..00000000 --- a/doc/basics/different_routers.md +++ /dev/null @@ -1,17 +0,0 @@ -# Different Routers - -Reitit ships with several different implementations for the `Router` protocol, originally based on the awesome [Pedestal](https://github.com/pedestal/pedestal/tree/master/route) implementation. `router` selects the most suitable implementation by inspecting the expanded routes. The implementation can be set manually using `:router` ROUTER OPTION. - -| router | description | -| ----------------------|-------------| -| `:linear-router` | Matches the routes one-by-one starting from the top until a match is found. Works with any kind of routes. -| `:lookup-router` | Fastest router, uses hash-lookup to resolve the route. Valid if no paths have path or catch-all parameters. -| `:mixed-router` | Creates internally a `:linear-router` and a `:lookup-router` and used them to effectively get best-of-both-worlds. Valid if there are no CONFLICTING ROUTES. -| `:prefix-tree-router` | [TODO](https://github.com/julienschmidt/httprouter#how-does-it-work) - -The router name can be asked from the router - -```clj -(r/router-name router) -; :mixed-router -``` diff --git a/doc/basics/name_based_routing.md b/doc/basics/name_based_routing.md index 7dcbe60f..68950869 100644 --- a/doc/basics/name_based_routing.md +++ b/doc/basics/name_based_routing.md @@ -1,6 +1,18 @@ -## Name-based routing +## Name-based (reverse) routing -All routes which `:name` route data defined, can be matched by name. +All routes which have `:name` route data defined, can also be matched by name. + +Given a router: + +```clj +(require '[reitit.core :as r]) + +(def router + (r/router + [["/api" + ["/ping" ::ping] + ["/user/:id" ::user]]])) +``` Listing all route names: @@ -9,7 +21,25 @@ Listing all route names: ; [:user/ping :user/user] ``` -Matching by name: +No match returns `nil`: + +```clj +(r/match-by-name router ::kikka) +nil +``` + +Matching a route: + +```clj +(r/match-by-name router ::ping) +; #Match{:template "/api/ping" +; :meta {:name :user/ping} +; :result nil +; :params {} +; :path "/api/ping"} +``` + +If not all path-parameters are set, a `PartialMatch` is returned: ```clj (r/match-by-name router ::user) @@ -23,7 +53,7 @@ Matching by name: ; true ``` -We only got a partial match as we didn't provide the needed path-parameters. Let's provide the them too: +With provided path-parameters: ```clj (r/match-by-name router ::user {:id "1"}) diff --git a/doc/basics/path_based_routing.md b/doc/basics/path_based_routing.md index aeccea00..7f61ef35 100644 --- a/doc/basics/path_based_routing.md +++ b/doc/basics/path_based_routing.md @@ -6,11 +6,27 @@ Path-based routing is done using the `reitit.core/match-by-path` function. It ta * `PartialMatch`, path matched, missing path-parameters (only in reverse-routing) * `Match`, exact match +Given a router: + +```clj +(require '[reitit.core :as r]) + +(def router + (r/router + [["/api" + ["/ping" ::ping] + ["/user/:id" ::user]]])) +``` + +No match returns `nil`: + ```clj (r/match-by-path router "/hello") ; nil ``` +Match provides the route information: + ```clj (r/match-by-path router "/api/user/1") ; #Match{:template "/api/user/:id" diff --git a/doc/advanced/route_conflicts.md b/doc/basics/route_conflicts.md similarity index 61% rename from doc/advanced/route_conflicts.md rename to doc/basics/route_conflicts.md index 41ebab19..d38e2e51 100644 --- a/doc/advanced/route_conflicts.md +++ b/doc/basics/route_conflicts.md @@ -1,13 +1,13 @@ # Route conflicts -Many routing libraries allow single path lookup could match multiple routes. Usually, first match is used. This is not good, especially if route tree is merged from multiple sources - routes might regress to be unreachable without a warning. +Many routing libraries allow multiple matches for a single path lookup. Usually, the first match is used and the rest are effecively unreachanle. This is not good, especially if route tree is merged from multiple sources. -Reitit resolves this by running explicit conflicit resolution when a `Router` is created. Conflicting routes are passed into a `:conflicts` callback. Default implementation throws `ex-info` with a descriptive message. +Reitit resolves this by running explicit conflicit resolution when a `router` is called. Conflicting routes are passed into a `:conflicts` callback. Default implementation throws `ex-info` with a descriptive message. -Examples routes with conflicts: +Examples router with conflicting routes: ```clj -(require '[reitit.core :as reitit]) +(require '[reitit.core :as r]) (def routes [["/ping"] @@ -20,7 +20,7 @@ Examples routes with conflicts: By default, `ExceptionInfo` is thrown: ```clj -(reitit/router routes) +(r/router routes) ; CompilerException clojure.lang.ExceptionInfo: Router contains conflicting routes: ; ; /:user-id/orders @@ -38,7 +38,7 @@ By default, `ExceptionInfo` is thrown: Just logging the conflicts: ```clj -(reitit/router +(r/router routes {:conflicts (comp println reitit/conflicts-str)}) ; Router contains conflicting routes: diff --git a/doc/basics/route_data.md b/doc/basics/route_data.md index 3fc4bd20..9a013956 100644 --- a/doc/basics/route_data.md +++ b/doc/basics/route_data.md @@ -1,6 +1,47 @@ # Route data -Routes can have arbitrary meta-data, interpreted by the router (via it's `:compile` hook) or the application itself. For nested routes, route data is accumulated recursively using [meta-merge](https://github.com/weavejester/meta-merge). By default, it appends collections, but it can be overridden to do `:prepend`, `:replace` or `:displace`. +Route data is the heart of this library. Routes can have any data attachted to them. Data is interpeted either by the client application or the `Router` via it's `:coerce` and `:compile` hooks. This enables co-existence of both [adaptive and principled](https://youtu.be/x9pxbnFC4aQ?t=1907) components. + +Routes can have a non-sequential route argument that is expanded into route data map when a router is created. + +```clj +(require '[reitit.core :as r]) + +(def router + (r/router + [["/ping" ::ping] + ["/pong" identity] + ["/users" {:get {:roles #{:admin} + :handler identity}}]])) +``` + +The expanded route data can be retrieved from a router with `routes` and is returned with `match-by-path` and `match-by-name` in case of a route match. + +```clj +(r/routes router) +; [["/ping" {:name :user/ping}] +; ["/pong" {:handler identity]} +; ["/users" {:get {:roles #{:admin} +; :handler identity}}]] + +(r/match-by-path router "/ping") +; #Match{:template "/ping" +; :meta {:name :user/ping} +; :result nil +; :params {} +; :path "/ping"} + +(r/match-by-name router ::ping) +; #Match{:template "/ping" +; :meta {:name :user/ping} +; :result nil +; :params {} +; :path "/ping"} +``` + +## Nested route data + +For nested route trees, route data is accumulated recursively from root towards leafs using [meta-merge](https://github.com/weavejester/meta-merge). Default behavior for colections is `:append`, but this can be overridden to `:prepend`, `:replace` or `:displace` using the target meta-data. An example router with nested data: @@ -12,41 +53,47 @@ An example router with nested data: ["/admin" {:roles #{:admin}} ["/users" ::users] ["/db" {:interceptors [::db] - :roles ^:replace #{:db-admin}} - ["/:db" {:parameters {:db String}} - ["/drop" ::drop-db] - ["/stats" ::db-stats]]]]])) + :roles ^:replace #{:db-admin}}]]])) ``` Resolved route tree: ```clj -(reitit/routes router) +(r/routes router) ; [["/api/ping" {:interceptors [::api] -; :name ::ping}] +; :name :user/ping}] ; ["/api/admin/users" {:interceptors [::api] ; :roles #{:admin} -; :name ::users}] -; ["/api/admin/db/:db/drop" {:interceptors [::api ::db] -; :roles #{:db-admin} -; :parameters {:db String} -; :name ::drop-db}] -; ["/api/admin/db/:db/stats" {:interceptors [::api ::db] -; :roles #{:db-admin} -; :parameters {:db String} -; :name ::db-stats}]] +; :name ::users} nil] +; ["/api/admin/db" {:interceptors [::api ::db] +; :roles #{:db-admin}}]] ``` -Route data is returned with `Match` and the application can act based on it. + +## Expansion + +By default, `reitit/Expand` protocol is used to expand the route arguments. It expands keywords into `:name` and functions into `:handler` key in the route data map. It's easy to add custom expanders and one can chenge the whole expand implementation via [router options](../advanced/configuring_routers.md). ```clj -(r/match-by-path router "/api/admin/db/users/drop") -; #Match{:template "/api/admin/db/:db/drop" -; :meta {:interceptors [::api ::db] -; :roles #{:db-admin} -; :parameters {:db String} -; :name ::drop-db} +(require '[reitit.core :as r]) + +(def router + (r/router + [["/ping" ::ping] + ["/pong" identity] + ["/users" {:get {:roles #{:admin} + :handler identity}}]])) + +(r/routes router) +; [["/ping" {:name :user/ping}] +; ["/pong" {:handler identity]} +; ["/users" {:get {:roles #{:admin} +; :handler identity}}]] + +(r/match-by-path router "/ping") +; #Match{:template "/ping" +; :meta {:name :user/ping} ; :result nil -; :params {:db "users"} -; :path "/api/admin/db/users/drop"} +; :params {} +; :path "/ping"} ``` diff --git a/doc/basics/route_syntax.md b/doc/basics/route_syntax.md index 7c3a26e1..24b2c23b 100644 --- a/doc/basics/route_syntax.md +++ b/doc/basics/route_syntax.md @@ -1,6 +1,12 @@ # Route Syntax -Raw routes are defined as vectors, which have a String path, optional (non-sequential) route argument and optional child routes. Routes can be wrapped in vectors and lists and `nil` routes are ignored. Paths can have path-parameters (`:id`) or catch-all-parameters (`*path`). +Routes are defined as vectors of String path and optional (non-sequential) route argument child routes. + +Routes can be wrapped in vectors and lists and `nil` routes are ignored. + +Paths can have path-parameters (`:id`) or catch-all-parameters (`*path`). + +### Examples Simple route: @@ -53,7 +59,8 @@ Same routes flattened: ["/api/ping" {:name ::ping}]] ``` -As routes are just data, it's easy to create them programamtically: +### Generating routes +As routes are just data, it's easy to create them programmatically: ```clj (defn cqrs-routes [actions dev-mode?] diff --git a/doc/basics/router.md b/doc/basics/router.md index 55bfce4d..38ecbdda 100644 --- a/doc/basics/router.md +++ b/doc/basics/router.md @@ -1,8 +1,8 @@ # Router -Routes are just data and to do actual routing, we need a Router satisfying the `reitit.core/Router` protocol. Routers are created with `reitit.core/router` function, taking the raw routes and optionally an options map. Raw routes gets expanded and optionally coerced and compiled. +Routes are just data and for routing, we need a router instance satisfying the `reitit.core/Router` protocol. Routers are created with `reitit.core/router` function, taking the raw routes and optionally an options map. -`Router` protocol: +The `Router` protocol: ```clj (defprotocol Router @@ -26,10 +26,25 @@ Creating a router: ["/user/:id" ::user]]])) ``` -Router flattens the raw routes and expands the route arguments using `reitit.core/Expand` protocol. By default, `Keyword`s are expanded to `:name` and functions are expaned to `:handler`. `nil` routes are removed. The expanded routes can be retrieved with router: +Name of the created router: + +```clj +(r/router-name router) +; :mixed-router +``` + +The flattened route tree: ```clj (r/routes router) ; [["/api/ping" {:name :user/ping}] ; ["/api/user/:id" {:name :user/user}]] ``` + +### Behind the scenes +When router is created, the following steps are done: +* route tree is flattened +* route arguments are expanded (via `reitit.core/Expand` protocol) and optionally coerced +* [route conflicts](advanced/route_conflicts.md) are resolved +* actual [router implementation](../advanced/different_routers.md) is selected and created +* optionally route meta-data gets compiled diff --git a/doc/ring/README.md b/doc/ring/README.md index 69ae9e80..9bbe9b59 100644 --- a/doc/ring/README.md +++ b/doc/ring/README.md @@ -2,5 +2,6 @@ * [Ring-router](ring.md) * [Dynamic extensions](dynamic_extensions.md) +* [Data-driven Middleware](data_driven_middleware.md) * [Parameter coercion](parameter_coercion.md) * [Compiling middleware](compiling_middleware.md) diff --git a/doc/ring/compiling_middleware.md b/doc/ring/compiling_middleware.md index da6d442d..13d82756 100644 --- a/doc/ring/compiling_middleware.md +++ b/doc/ring/compiling_middleware.md @@ -1,12 +1,12 @@ # Compiling Middleware -The [meta-data extensions](ring.md#meta-data-based-extensions) are a easy way to extend the system. Routes meta-data can be transformed into any shape (records, functions etc.) in route compilation, enabling fast access at request-time. +The [dynamic extensions](dynamic_extensions.md) is a easy way to extend the system. To enable fast lookups into route data, we can compile them into any shape (records, functions etc.) we want, enabling fast access at request-time. -Still, we can do better. As we know the exact route that interceptor/middleware is linked to, we can pass the (compiled) route information into the interceptor/middleware at creation-time. It can extract and transform relevant data just for it and pass it into the actual request-handler via a closure - yielding faster runtime processing. +Still, we can do better. As we know the exact route that middleware/interceptor is linked to, we can pass the (compiled) route information into the middleware/interceptor at creation-time. It can do local reasoning: extract and transform relevant data just for it and pass it into the actual request-handler via a closure - yielding much faster runtime processing. Middleware/interceptor can also decide not to mount itself. Why mount a `wrap-enforce-roles` middleware for a route if there are no roles required for it? -To do this we use [middleware records](ring.md#middleware-records) `:gen` hook instead of the normal `:wrap`. `:gen` expects a function of `route-meta router-opts => wrap`. Middleware can also return `nil`, which effective unmounts the middleware. Why mount a `wrap-enforce-roles` middleware for a route if there are no roles required for it? +To enable this we use [middleware records](data_driven_middleware.md) `:gen` hook instead of the normal `:wrap`. `:gen` expects a function of `route-meta router-opts => wrap`. Middleware can also return `nil`, which effective unmounts the middleware. -To demonstrate the two approaches, below are response coercion middleware written as normal ring middleware function and as middleware record with `:gen`. These are the actual codes are from [`reitit.coercion`](https://github.com/metosin/reitit/blob/master/src/reitit/coercion.cljc): +To demonstrate the two approaches, below are response coercion middleware written as normal ring middleware function and as middleware record with `:gen`. These are the actual codes are from [`reitit.ring.coercion`](https://github.com/metosin/reitit/blob/master/src/reitit/ring/coercion.cljc): ## Naive @@ -16,7 +16,7 @@ To demonstrate the two approaches, below are response coercion middleware writte (defn wrap-coerce-response "Pluggable response coercion middleware. Expects a :coercion of type `reitit.coercion.protocol/Coercion` - and :responses from route meta, otherwise does not mount." + and :responses from route meta, otherwise will do nothing." [handler] (fn ([request] @@ -27,20 +27,17 @@ To demonstrate the two approaches, below are response coercion middleware writte coercion (-> match :meta :coercion) opts (-> match :meta :opts)] (if (and coercion responses) - (let [coercers (response-coercers coercion responses opts) - coerced (coerce-response coercers request response)] - (coerce-response coercers request (handler request))) - (handler request)))) + (let [coercers (response-coercers coercion responses opts)] + (coerce-response coercers request response)) + response))) ([request respond raise] - (let [response (handler request) - method (:request-method request) + (let [method (:request-method request) match (ring/get-match request) responses (-> match :result method :meta :responses) coercion (-> match :meta :coercion) opts (-> match :meta :opts)] (if (and coercion responses) - (let [coercers (response-coercers coercion responses opts) - coerced (coerce-response coercers request response)] + (let [coercers (response-coercers coercion responses opts)] (handler request #(respond (coerce-response coercers request %)))) (handler request respond raise)))))) ``` @@ -69,4 +66,4 @@ To demonstrate the two approaches, below are response coercion middleware writte (handler request #(respond (coerce-response coercers request %)) raise)))))))})) ``` -The `:gen` -version has 50% less code, is easier to reason about and is 2-4x faster on basic perf tests. +The `:gen` -version has 50% less code, is easier to reason about and is twice as faster on basic perf tests. diff --git a/doc/middleware_records.md b/doc/ring/data_driven_middleware.md similarity index 52% rename from doc/middleware_records.md rename to doc/ring/data_driven_middleware.md index 784d0485..572e96ff 100644 --- a/doc/middleware_records.md +++ b/doc/ring/data_driven_middleware.md @@ -1,14 +1,14 @@ -# Middleware Records +# Data-driven Middleware -Reitit supports first-class data-driven middleware via `reitit.middleware/Middleware` records, created with `reitit.middleware/create` function. The following keys have special purpose: +Reitit supports first-class data-driven middleware via `reitit.ring.middleware/Middleware` records, created with `reitit.ring.middleware/create` function. The following keys have special purpose: | key | description | | -----------|-------------| | `:name` | Name of the middleware as qualified keyword (optional,recommended for libs) | `:wrap` | The actual middleware function of `handler args? => request => response` -| `:gen` | Middleware compile function, see [compiling middleware](#compiling-middleware). +| `:gen` | Middleware compile function, see [compiling middleware](compiling_middleware.md). -When routes are compiled, all middleware are expanded (and optionally compiled) into `Middleware` and stored in compilation results for later use (api-docs etc). For actual request processing, they are unwrapped into normal middleware functions producing zero runtime performance penalty. Middleware expansion is backed by `reitit.middleware/IntoMiddleware` protocol, enabling plain clojure(script) maps to be used. +When routes are compiled, all middleware are expanded (and optionally compiled) into `Middleware` Records and stored in compilation results for later use (api-docs etc). For actual request processing, they are unwrapped into normal middleware functions and composed together producing zero runtime performance penalty. Middleware expansion is backed by `reitit.middleware/IntoMiddleware` protocol, enabling plain clojure(script) maps to be used. A Record: @@ -32,3 +32,7 @@ As plain map: :wrap (fn [handler] (wrap handler :api))}) ``` + +### TODO + +more! diff --git a/doc/ring/dynamic_extensions.md b/doc/ring/dynamic_extensions.md index 755a382c..4aa7d4c2 100644 --- a/doc/ring/dynamic_extensions.md +++ b/doc/ring/dynamic_extensions.md @@ -1,6 +1,6 @@ # Dynamic extensions -`ring-handler` injects the `Match` into a request and it can be extracted at runtime with `reitit.ring/get-match`. This can be used to build dynamic extensions to the system. +`ring-handler` injects the `Match` into a request and it can be extracted at runtime with `reitit.ring/get-match`. This can be used to build ad-hoc extensions to the system. Example middleware to guard routes based on user roles: @@ -10,7 +10,7 @@ Example middleware to guard routes based on user roles: (defn wrap-enforce-roles [handler] (fn [{:keys [::roles] :as request}] (let [required (some-> request (ring/get-match) :meta ::roles)] - (if (and (seq required) (not (set/intersection required roles))) + (if (and (seq required) (not (set/subset? required roles))) {:status 403, :body "forbidden"} (handler request))))) ``` diff --git a/doc/ring/parameter_coercion.md b/doc/ring/parameter_coercion.md index 6bd92452..73b73f84 100644 --- a/doc/ring/parameter_coercion.md +++ b/doc/ring/parameter_coercion.md @@ -1,13 +1,13 @@ # Parameter coercion -Reitit provides pluggable parameter coercion via `reitit.coercion.protocol/Coercion` protocol, originally introduced in [compojure-api](https://clojars.org/metosin/compojure-api). Reitit ships with `reitit.coercion.spec/SpecCoercion` providing implemenation for [clojure.spec](https://clojure.org/about/spec) and [data-specs](https://github.com/metosin/spec-tools#data-specs). +Reitit provides pluggable parameter coercion via `reitit.ring.coercion.protocol/Coercion` protocol, originally introduced in [compojure-api](https://clojars.org/metosin/compojure-api). Reitit ships with `reitit.ring.coercion.spec/SpecCoercion` providing implemenation for [clojure.spec](https://clojure.org/about/spec) and [data-specs](https://github.com/metosin/spec-tools#data-specs). **NOTE**: Before Clojure 1.9.0 is shipped, to use the spec-coercion, one needs to add the following dependencies manually to the project: ```clj -[org.clojure/clojure "1.9.0-alpha20"] +[org.clojure/clojure "1.9.0-beta2"] [org.clojure/spec.alpha "0.1.123"] -[metosin/spec-tools "0.3.3"] +[metosin/spec-tools "0.4.0"] ``` ### Ring request and response coercion @@ -18,7 +18,9 @@ To use `Coercion` with Ring, one needs to do the following: * `:parameters` map, with submaps for different parameters: `:query`, `:body`, `:form`, `:header` and `:path`. Parameters are defined in the format understood by the `Coercion`. * `:responses` map, with response status codes as keys (or `:default` for "everything else") with maps with `:schema` and optionally `:description` as values. 2. Define a `Coercion` to route meta-data under `:coercion` -3. Mount request & response coercion middleware to the routes. +3. Mount request & response coercion middleware to the routes (recommended to mount to all routes under router as they mounted only to routes which have the parameters / responses defined): + * `reitit.ring.coercion/gen-wrap-coerce-parameters` + * `gen-wrap-coerce-parameters/gen-wrap-coerce-responses` If the request coercion succeeds, the coerced parameters are injected into request under `:parameters`. @@ -28,8 +30,8 @@ If either request or response coercion fails, an descriptive error is thrown. ```clj (require '[reitit.ring :as ring]) -(require '[reitit.coercion :as coercion]) -(require '[reitit.coercion.spec :as spec]) +(require '[reitit.ring.coercion :as coercion]) +(require '[reitit.ring.coercion.spec :as spec]) (def app (ring/ring-handler @@ -56,10 +58,12 @@ If either request or response coercion fails, an descriptive error is thrown. #### Example with specs +Currently, `clojure.spec` [doesn't support runtime transformations via conforming](https://dev.clojure.org/jira/browse/CLJ-2116), so one needs to wrap all specs with `spec-tools.core/spec`. + ```clj (require '[reitit.ring :as ring]) -(require '[reitit.coercion :as coercion]) -(require '[reitit.coercion.spec :as spec]) +(require '[reitit.ring.coercion :as coercion]) +(require '[reitit.ring.coercion.spec :as spec]) (require '[clojure.spec.alpha :as s]) (require '[spec-tools.core :as st]) diff --git a/doc/ring/ring.md b/doc/ring/ring.md index 8e32c094..0ac7aea7 100644 --- a/doc/ring/ring.md +++ b/doc/ring/ring.md @@ -26,7 +26,7 @@ Applying the handler: ; {:status 200, :body "ok"} ``` -The expanded routes: +The expanded routes shows the compilation results: ```clj (-> app (ring/get-router) (reitit/routes)) @@ -58,7 +58,7 @@ Handler are also looked under request-method keys: `:get`, `:head`, `:patch`, `: ; nil ``` -Reverse routing: +Name-based reverse routing: ```clj (-> app @@ -70,9 +70,9 @@ Reverse routing: # Middleware -Middleware can be added with a `:middleware` key, with a vector value of the following: +Middleware can be added with a `:middleware` key, either to top-level or under `:request-method` submap. It's value should be a vector value of the following: -1. ring middleware function `handler -> request -> response` +1. normal ring middleware function `handler -> request -> response` 2. vector of middleware function `handler ?args -> request -> response` and optinally it's args. A middleware and a handler: @@ -96,7 +96,7 @@ App with nested middleware: ["/ping" handler] ["/admin" {:middleware [[wrap :admin]]} ["/db" {:middleware [[wrap :db]] - :delete {:middleware [#(wrap % :delete)] + :delete {:middleware [[wrap :delete]] :handler handler}}]]]))) ``` diff --git a/modules/reitit-ring/src/reitit/ring/coercion.cljc b/modules/reitit-ring/src/reitit/ring/coercion.cljc index 39245b12..e015486f 100644 --- a/modules/reitit-ring/src/reitit/ring/coercion.cljc +++ b/modules/reitit-ring/src/reitit/ring/coercion.cljc @@ -107,7 +107,7 @@ (defn wrap-coerce-parameters "Pluggable request coercion middleware. Expects a :coercion of type `reitit.coercion.protocol/Coercion` - and :parameters from route meta, otherwise does not mount." + and :parameters from route meta, otherwise will do nothing." [handler] (fn ([request] From 2ae8fd27a8ffeaedac4c2cd6f75433aaa33b0be7 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Mon, 30 Oct 2017 21:39:35 +0200 Subject: [PATCH 12/12] Replace the version in place --- modules/reitit-core/project.clj | 4 +--- modules/reitit-ring/project.clj | 4 +--- modules/reitit-spec/project.clj | 4 +--- modules/reitit/project.clj | 4 +--- project.clj | 12 +++++------- scripts/set-version | 5 +++-- 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/modules/reitit-core/project.clj b/modules/reitit-core/project.clj index f7a4454a..b2017f3e 100644 --- a/modules/reitit-core/project.clj +++ b/modules/reitit-core/project.clj @@ -1,6 +1,4 @@ -(def VERSION "0.1.0-SNAPSHOT") - -(defproject metosin/reitit-core VERSION +(defproject metosin/reitit-core "0.1.0-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-ring/project.clj b/modules/reitit-ring/project.clj index 1c061c81..289073f0 100644 --- a/modules/reitit-ring/project.clj +++ b/modules/reitit-ring/project.clj @@ -1,6 +1,4 @@ -(def VERSION "0.1.0-SNAPSHOT") - -(defproject metosin/reitit-ring VERSION +(defproject metosin/reitit-ring "0.1.0-SNAPSHOT" :description "Reitit: Ring routing" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit-spec/project.clj b/modules/reitit-spec/project.clj index 91745cb5..c000fa46 100644 --- a/modules/reitit-spec/project.clj +++ b/modules/reitit-spec/project.clj @@ -1,6 +1,4 @@ -(def VERSION "0.1.0-SNAPSHOT") - -(defproject metosin/reitit-spec VERSION +(defproject metosin/reitit-spec "0.1.0-SNAPSHOT" :description "Reitit: clojure.spec coercion" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/modules/reitit/project.clj b/modules/reitit/project.clj index b26a813d..b0f4404b 100644 --- a/modules/reitit/project.clj +++ b/modules/reitit/project.clj @@ -1,6 +1,4 @@ -(def VERSION "0.1.0-SNAPSHOT") - -(defproject metosin/reitit VERSION +(defproject metosin/reitit "0.1.0-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" diff --git a/project.clj b/project.clj index 2b7f3fee..e0c03553 100644 --- a/project.clj +++ b/project.clj @@ -1,6 +1,4 @@ -(def VERSION "0.1.0-SNAPSHOT") - -(defproject metosin/reitit-parent VERSION +(defproject metosin/reitit-parent "0.1.0-SNAPSHOT" :description "Snappy data-driven router for Clojure(Script)" :url "https://github.com/metosin/reitit" :license {:name "Eclipse Public License" @@ -11,10 +9,10 @@ :source-uri "https://github.com/metosin/reitit/{version}/{filepath}#L{line}" :metadata {:doc/format :markdown}} - :managed-dependencies [[metosin/reitit ~VERSION] - [metosin/reitit-core ~VERSION] - [metosin/reitit-ring ~VERSION] - [metosin/reitit-spec ~VERSION] + :managed-dependencies [[metosin/reitit "0.1.0-SNAPSHOT"] + [metosin/reitit-core "0.1.0-SNAPSHOT"] + [metosin/reitit-ring "0.1.0-SNAPSHOT"] + [metosin/reitit-spec "0.1.0-SNAPSHOT"] [meta-merge "1.0.0"] [metosin/spec-tools "0.5.0"]] diff --git a/scripts/set-version b/scripts/set-version index ddad9fa9..1dd5714b 100755 --- a/scripts/set-version +++ b/scripts/set-version @@ -2,5 +2,6 @@ ext="sedbak$$" -find . -name project.clj -exec sed -i.$ext "s/(def VERSION \".*\")/(def VERSION \"$1\")/g" '{}' \; -find . -name "*.$ext" -exec rm '{}' \; \ No newline at end of file +find . -name project.clj -exec sed -i.$ext "s/\[metosin\/reitit\(.*\) \".*\"\]/[metosin\/reitit\1 \"$1\"\]/g" '{}' \; +find . -name project.clj -exec sed -i.$ext "s/defproject metosin\/reitit\(.*\) \".*\"/defproject metosin\/reitit\1 \"$1\"/g" '{}' \; +find . -name "*.$ext" -exec rm '{}' \;