diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..ee0f196c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,44 @@ +name: Test + +on: + push: + branches: + - master + pull_request: + schedule: + # monthly + - cron: "0 0 1 * *" + +env: + #bump to clear caches + ACTION_CACHE_VERSION: 'v1' + +jobs: + test: + strategy: + matrix: + java: ['8', '11', '17'] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven-${{ hashFiles('**/project.clj') }}-${{ matrix.java }} + restore-keys: | + ${{ env.ACTION_CACHE_VERSION }}-${{ runner.os }}-maven-${{ hashFiles('**/project.clj') }}- + - name: Prepare java + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: ${{ matrix.java }} + - uses: actions/setup-node@v2 + with: + node-version: '10.13.0' + - name: Install clojure tools + uses: DeLaGuardo/setup-clojure@3.5 + with: + lein: 2.9.7 + - name: Run tests + run: lein all test diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fbcdd63..1f0b67c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## NEXT + * **BREAKING** use `cljc` instead of `cljx`, which requires Clojure 1.7 or later. (#425) + ## 1.1.12 (`2019-08-10`) * Fixes a "wrong number of arguments" warning in clojurescript (#418) * Fixes an issue with function name inference introduced in the previous diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d76599d7..b56c74b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,8 +8,6 @@ For questions, feature requests, or discussion, please post on the Plumbing [mai Contributions are preferred as GitHub pull requests on topic branches. If you want to discuss a potential change before coding it up, please post on the mailing list. -Schema uses the excellent [cljx](https://github.com/lynaghk/cljx) project to share source between Clojure and ClojureScript. For any in-depth changes to Schema, you will probably want to be familiar with its feature expressions (`#clj` and `#cljx`), and the inherent differences between Clojure and ClojureScript. In particular, if you're wondering why the code is divided the way it is, this is probably the answer. If you develop with Emacs, the included `:nrepl-middleware` should allow you to work at the REPL as you're used to. - Schema is relatively well-tested, on both Clojure and ClojureScript. Before submitting a pull request, we ask that you: * please try to follow the conventions in the existing code, including standard Emacs indentation, no trailing whitespace, and a max width of 95 columns @@ -17,5 +15,5 @@ Schema is relatively well-tested, on both Clojure and ClojureScript. Before sub * ensure any new code is well-tested, and if possible, any issue fixed is covered by one or more new tests * check that all of the tests pass **in both Clojure and ClojureScript** -To run the Clojure and ClojureScript tests, first run `lein cljx`, then run `lein test`. You must have phantomjs installed for the ClojureScript tests to run. +To run the Clojure and ClojureScript tests, run `lein test`. You must have phantomjs installed for the ClojureScript tests to run. diff --git a/README.md b/README.md index 1a3be061..820e3b62 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ Finally, we use validation with coercion for API inputs and outputs. See the co ## More examples -The source code in [schema/core.cljx](https://github.com/plumatic/schema/blob/master/src/cljx/schema/core.cljx) provides a wealth of extra tools for defining schemas, which are described in docstrings. The file [schema/core_test.cljx](https://github.com/plumatic/schema/blob/master/test/cljx/schema/core_test.cljx) demonstrates a variety of sample schemas and many examples of passing & failing clojure data. We'll just touch on a few more examples here, and refer the reader to the code for more details and examples (for now). +The source code in [schema/core.cljc](https://github.com/plumatic/schema/blob/master/src/cljc/schema/core.cljc) provides a wealth of extra tools for defining schemas, which are described in docstrings. The file [schema/core_test.cljc](https://github.com/plumatic/schema/blob/master/test/cljc/schema/core_test.cljc) demonstrates a variety of sample schemas and many examples of passing & failing clojure data. We'll just touch on a few more examples here, and refer the reader to the code for more details and examples (for now). ### Map schema details @@ -270,7 +270,7 @@ Similarly, you can also write sequence schemas that expect particular values in ### Other schema types -[`schema.core`](https://github.com/plumatic/schema/blob/master/src/cljx/schema/core.cljx) provides many more utilities for building schemas, including `maybe`, `eq`, `enum`, `pred`, `conditional`, `cond-pre`, `constrained`, and more. Here are a few of our favorites: +[`schema.core`](https://github.com/plumatic/schema/blob/master/src/cljc/schema/core.cljc) provides many more utilities for building schemas, including `maybe`, `eq`, `enum`, `pred`, `conditional`, `cond-pre`, `constrained`, and more. Here are a few of our favorites: ```clojure ;; anything @@ -404,7 +404,7 @@ If you make something new, please feel free to PR to add it here! ## Supported Clojure versions -Schema is currently supported on 1.6 through 1.8 and the latest version of ClojureScript. +Schema is currently supported on 1.7 through 1.10 and the latest version of ClojureScript. ## License diff --git a/deps.edn b/deps.edn new file mode 100644 index 00000000..8bf9cebf --- /dev/null +++ b/deps.edn @@ -0,0 +1 @@ +{:paths ["src/clj" "src/cljc"]} diff --git a/project.clj b/project.clj index 086e9b72..3996dc61 100644 --- a/project.clj +++ b/project.clj @@ -9,69 +9,51 @@ [org.clojure/tools.nrepl "0.2.5"] [org.clojure/test.check "0.9.0"] [potemkin "0.4.1"]] - :plugins [[com.keminglabs/cljx "0.6.0" :exclusions [org.clojure/clojure]] - [codox "0.8.8"] + :plugins [[codox "0.8.8"] [lein-cljsbuild "1.1.7"] [lein-release/lein-release "1.0.4"] - [lein-doo "0.1.10"]] - :cljx {:builds [{:source-paths ["src/cljx"] - :output-path "target/generated/src/clj" - :rules :clj} - {:source-paths ["src/cljx"] - :output-path "target/generated/src/cljs" - :rules :cljs} - {:source-paths ["test/cljx"] - :output-path "target/generated/test/clj" - :rules :clj} - {:source-paths ["test/cljx"] - :output-path "target/generated/test/cljs" - :rules :cljs}]}} + [lein-doo "0.1.10"]]} :1.9 {:dependencies [[org.clojure/clojure "1.9.0"] [org.clojure/clojurescript "1.10.520"]]} :1.10 {:dependencies [[org.clojure/clojure "1.10.0"] [org.clojure/clojurescript "1.10.520"]]}} :aliases {"all" ["with-profile" "dev:dev,1.9:dev,1.10"] - "deploy" ["do" "clean," "cljx" "once," "deploy" "clojars"] - "test" ["do" "clean," "cljx" "once," "test," "with-profile" "dev" "doo" "node" "test" "once"]} + "deploy" ["do" "clean," "deploy" "clojars"] + "test" ["do" "clean," "test," "with-profile" "dev" "doo" "node" "test" "once"]} - :jar-exclusions [#"\.cljx|\.swp|\.swo|\.DS_Store"] + :jar-exclusions [#"\.swp|\.swo|\.DS_Store"] :lein-release {:deploy-via :shell :shell ["lein" "deploy"]} :auto-clean false - :source-paths ["target/generated/src/clj" "src/clj"] + :source-paths ["src/clj" "src/cljc"] - :resource-paths ["target/generated/src/cljs"] - - :test-paths ["target/generated/test/clj" "test/clj" "test/cljs"] + :test-paths ["test/clj" "test/cljc" "test/cljs"] :cljsbuild {:builds [{:id "dev" - :source-paths ["src/clj" "target/generated/src/cljs"] + :source-paths ["src/clj" "src/cljc"] :compiler {:output-to "target/main.js" :optimizations :whitespace :pretty-print true}} {:id "test" - :source-paths ["src/clj" "test/clj" "test/cljs" - "target/generated/src/cljs" - "target/generated/test/cljs"] + :source-paths ["src/clj" "src/cljc" + "test/clj" "test/cljc" "test/cljs"] :compiler {:output-to "target/unit-test.js" :main schema.test-runner :target :nodejs :pretty-print true}} {:id "test-no-assert" - :source-paths ["src/clj" "test/clj" "test/cljs" - "target/generated/src/cljs" - "target/generated/test/cljs"] + :source-paths ["src/clj" "src/cljc" + "test/clj" "test/cljc" "test/cljs"] :assert false :compiler {:output-to "target/unit-test.js" :main schema.test-runner :target :nodejs :pretty-print true}}]} - :codox {:src-uri-mapping {#"target/generated/src/clj" #(str "src/cljx/" % "x")} - :src-dir-uri "http://github.com/plumatic/schema/blob/master/" + :codox {:src-dir-uri "http://github.com/plumatic/schema/blob/master/" :src-linenum-anchor-prefix "L"} :signing {:gpg-key "66E0BF75"}) diff --git a/src/clj/schema/macros.clj b/src/clj/schema/macros.clj index 2de986fe..269fb290 100644 --- a/src/clj/schema/macros.clj +++ b/src/clj/schema/macros.clj @@ -53,8 +53,8 @@ (throw (clojure.lang.ExceptionInfo. ~(with-meta s `{:tag java.lang.String}) ~m)))))) (defmacro safe-get - "Like get but throw an exception if not found. A macro just to work around cljx function - placement restrictions. " + "Like get but throw an exception if not found. A macro for historical reasons (to + work around cljx function placement restrictions)." [m k] `(let [m# ~m k# ~k] (if-let [pair# (find m# k#)] diff --git a/src/cljx/schema/coerce.cljx b/src/cljc/schema/coerce.cljc similarity index 75% rename from src/cljx/schema/coerce.cljx rename to src/cljc/schema/coerce.cljc index c79a1379..c0bbe2e0 100644 --- a/src/cljx/schema/coerce.cljx +++ b/src/cljc/schema/coerce.cljc @@ -1,14 +1,15 @@ (ns schema.coerce "Extension of schema for input coercion (coercing an input to match a schema)" (:require - #+cljs [cljs.reader :as reader] - #+clj [clojure.edn :as edn] - #+clj [schema.macros :as macros] - [schema.core :as s :include-macros true] + #?(:cljs [cljs.reader :as reader]) + #?(:clj [clojure.edn :as edn]) + #?(:clj [schema.macros :as macros]) + #?(:clj [schema.core :as s] + :cljs [schema.core :as s :include-macros true]) [schema.spec.core :as spec] [schema.utils :as utils] [clojure.string :as str]) - #+cljs (:require-macros [schema.macros :as macros])) + #?(:cljs (:require-macros [schema.macros :as macros]))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Generic input coercion @@ -71,14 +72,14 @@ (if (string? s) (= "true" (str/lower-case s)) s)) (defn keyword-enum-matcher [schema] - (when (or (and (instance? #+clj schema.core.EnumSchema #+cljs s/EnumSchema schema) + (when (or (and (instance? #?(:clj schema.core.EnumSchema :cljs s/EnumSchema) schema) (every? keyword? (.-vs ^schema.core.EnumSchema schema))) - (and (instance? #+clj schema.core.EqSchema #+cljs s/EqSchema schema) + (and (instance? #?(:clj schema.core.EqSchema :cljs s/EqSchema) schema) (keyword? (.-v ^schema.core.EqSchema schema)))) string->keyword)) (defn set-matcher [schema] - (if (instance? #+clj clojure.lang.APersistentSet #+cljs cljs.core.PersistentHashSet schema) + (if (instance? #?(:clj clojure.lang.APersistentSet :cljs cljs.core.PersistentHashSet) schema) (fn [x] (if (sequential? x) (set x) x)))) (defn safe @@ -89,23 +90,23 @@ [f] (fn [x] (macros/try-catchall (f x) (catch e x)))) -#+clj (def safe-long-cast - "Coerce x to a long if this can be done without losing precision, otherwise return x." - (safe - (fn [x] - (let [l (long x)] - (if (== l x) - l - x))))) +#?(:clj (def safe-long-cast + "Coerce x to a long if this can be done without losing precision, otherwise return x." + (safe + (fn [x] + (let [l (long x)] + (if (== l x) + l + x)))))) (def string->uuid "Returns instance of UUID if input is a string. Note: in CLJS, this does not guarantee a specific UUID string representation, similar to #uuid reader" - #+clj - (safe #(java.util.UUID/fromString ^String %)) - #+cljs - #(if (string? %) (uuid %) %)) + #?(:clj + (safe #(java.util.UUID/fromString ^String %)) + :cljs + #(if (string? %) (uuid %) %))) (def ^:no-doc +json-coercions+ @@ -113,12 +114,12 @@ {s/Keyword string->keyword s/Bool string->boolean s/Uuid string->uuid} - #+clj {clojure.lang.Keyword string->keyword - s/Int safe-long-cast - Long safe-long-cast - Double (safe double) - Float (safe float) - Boolean string->boolean})) + #?(:clj {clojure.lang.Keyword string->keyword + s/Int safe-long-cast + Long safe-long-cast + Double (safe double) + Float (safe float) + Boolean string->boolean}))) (defn json-coercion-matcher "A matcher that coerces keywords and keyword eq/enums from strings, and longs and doubles @@ -130,16 +131,16 @@ (def edn-read-string "Reads one object from a string. Returns nil when string is nil or empty" - #+clj edn/read-string #+cljs reader/read-string) + #?(:clj edn/read-string :cljs reader/read-string)) (def ^:no-doc +string-coercions+ (merge +json-coercions+ {s/Num (safe edn-read-string) s/Int (safe edn-read-string)} - #+clj {s/Int (safe #(safe-long-cast (edn-read-string %))) - Long (safe #(safe-long-cast (edn-read-string %))) - Double (safe #(Double/parseDouble %))})) + #?(:clj {s/Int (safe #(safe-long-cast (edn-read-string %))) + Long (safe #(safe-long-cast (edn-read-string %))) + Double (safe #(Double/parseDouble %))}))) (defn string-coercion-matcher "A matcher that coerces keywords, keyword eq/enums, s/Num and s/Int, diff --git a/src/cljx/schema/core.cljx b/src/cljc/schema/core.cljc similarity index 90% rename from src/cljx/schema/core.cljx rename to src/cljc/schema/core.cljc index b959b728..49a1d9df 100644 --- a/src/cljx/schema/core.cljx +++ b/src/cljc/schema/core.cljc @@ -77,32 +77,32 @@ ;; don't exclude def because it's not a var. (:refer-clojure :exclude [Keyword Symbol Inst atom defrecord defn letfn defmethod fn MapEntry ->MapEntry]) (:require - #+clj [clojure.pprint :as pprint] + #?(:clj [clojure.pprint :as pprint]) [clojure.string :as str] - #+clj [schema.macros :as macros] + #?(:clj [schema.macros :as macros]) [schema.utils :as utils] [schema.spec.core :as spec :include-macros true] [schema.spec.leaf :as leaf] [schema.spec.variant :as variant] [schema.spec.collection :as collection]) - #+cljs (:require-macros [schema.macros :as macros] - schema.core)) + #?(:cljs (:require-macros [schema.macros :as macros] + schema.core))) -#+clj (def clj-1195-fixed? - (do (defprotocol CLJ1195Check - (dummy-method [this])) - (try - (eval '(extend-protocol CLJ1195Check nil - (dummy-method [_]))) - true - (catch RuntimeException _ - false)))) +#?(:clj (def clj-1195-fixed? + (do (defprotocol CLJ1195Check + (dummy-method [this])) + (try + (eval '(extend-protocol CLJ1195Check nil + (dummy-method [_]))) + true + (catch RuntimeException _ + false))))) -#+clj (when-not clj-1195-fixed? - ;; don't exclude fn because of bug in extend-protocol - (refer-clojure :exclude '[Keyword Symbol Inst atom defrecord defn letfn defmethod])) +#?(:clj (when-not clj-1195-fixed? + ;; don't exclude fn because of bug in extend-protocol + (refer-clojure :exclude '[Keyword Symbol Inst atom defrecord defn letfn defmethod]))) -#+clj (set! *warn-on-reflection* true) +#?(:clj (set! *warn-on-reflection* true)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Schema protocol @@ -119,7 +119,7 @@ {:a Keyword, :b [Int]}")) ;; Schemas print as their explains -#+clj +#?(:clj (do (clojure.core/defmethod print-method schema.core.Schema [s writer] (print-method (explain s) writer)) (clojure.core/defmethod pprint/simple-dispatch schema.core.Schema [s] @@ -127,7 +127,7 @@ (doseq [m [print-method pprint/simple-dispatch]] (prefer-method m schema.core.Schema clojure.lang.IRecord) (prefer-method m schema.core.Schema java.util.Map) - (prefer-method m schema.core.Schema clojure.lang.IPersistentMap))) + (prefer-method m schema.core.Schema clojure.lang.IPersistentMap)))) (clojure.core/defn checker "Compile an efficient checker for schema, which returns nil for valid values and @@ -172,15 +172,15 @@ (clojure.core/defn instance-precondition [s klass] (spec/precondition s - #+clj #(instance? klass %) - #+cljs #(and (not (nil? %)) - (or (identical? klass (.-constructor %)) - (js* "~{} instanceof ~{}" % klass))) + #?(:clj #(instance? klass %) + :cljs #(and (not (nil? %)) + (or (identical? klass (.-constructor %)) + (js* "~{} instanceof ~{}" % klass)))) #(list 'instance? klass %))) (extend-protocol Schema - #+clj Class - #+cljs function + #?(:clj Class + :cljs function) (spec [this] (let [pre (instance-precondition this this)] (if-let [class-schema (utils/class-schema this)] @@ -190,19 +190,19 @@ (if-let [more-schema (utils/class-schema this)] (explain more-schema) (condp = this - #+clj java.lang.String #+cljs nil 'Str - #+clj java.lang.Boolean #+cljs js/Boolean 'Bool - #+clj java.lang.Number #+cljs js/Number 'Num - #+clj java.util.regex.Pattern #+cljs nil 'Regex - #+clj java.util.Date #+cljs js/Date 'Inst - #+clj java.util.UUID #+cljs cljs.core/UUID 'Uuid - #+clj (symbol (.getName ^Class this)) #+cljs this)))) + #?(:clj java.lang.String :cljs nil) 'Str + #?(:clj java.lang.Boolean :cljs js/Boolean) 'Bool + #?(:clj java.lang.Number :cljs js/Number) 'Num + #?(:clj java.util.regex.Pattern :cljs nil) 'Regex + #?(:clj java.util.Date :cljs js/Date) 'Inst + #?(:clj java.util.UUID :cljs cljs.core/UUID) 'Uuid + #?(:clj (symbol (.getName ^Class this)) :cljs this))))) ;; On the JVM, the primitive coercion functions (double, long, etc) ;; alias to the corresponding boxed number classes -#+clj +#?(:clj (do (defmacro extend-primitive [cast-sym class-sym] (let [qualified-cast-sym `(class @(resolve '~cast-sym))] @@ -229,7 +229,7 @@ (extend-primitive shorts (Class/forName "[S")) (extend-primitive chars (Class/forName "[C")) (extend-primitive bytes (Class/forName "[B")) - (extend-primitive booleans (Class/forName "[Z"))) + (extend-primitive booleans (Class/forName "[Z")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Cross-platform Schema leaves @@ -334,6 +334,7 @@ (explain [this] (list 'protocol (protocol-name this)))) ;; The cljs version is macros/protocol by necessity, since cljs `satisfies?` is a macro. +#?(:clj (defmacro protocol "A value that must satsify? protocol p. @@ -345,22 +346,22 @@ [p] `(with-meta (->Protocol ~p) {:proto-pred #(satisfies? ~p %) - :proto-sym '~p})) + :proto-sym '~p}))) ;;; regex (validates matching Strings) (extend-protocol Schema - #+clj java.util.regex.Pattern - #+cljs js/RegExp + #?(:clj java.util.regex.Pattern + :cljs js/RegExp) (spec [this] (leaf/leaf-spec (some-fn (spec/simple-precondition this string?) (spec/precondition this #(re-find this %) #(list 're-find (explain this) %))))) (explain [this] - #+clj (symbol (str "#\"" this "\"")) - #+cljs (symbol (str "#\"" (.slice (str this) 1 -1) "\"")))) + #?(:clj (symbol (str "#\"" this "\"")) + :cljs (symbol (str "#\"" (.slice (str this) 1 -1) "\""))))) ;;; Cross-platform Schemas for atomic value types @@ -368,15 +369,15 @@ (def Str "Satisfied only by String. Is (pred string?) and not js/String in cljs because of keywords." - #+clj java.lang.String #+cljs (pred string? 'string?)) + #?(:clj java.lang.String :cljs (pred string? 'string?))) (def Bool "Boolean true or false" - #+clj java.lang.Boolean #+cljs js/Boolean) + #?(:clj java.lang.Boolean :cljs js/Boolean)) (def Num "Any number" - #+clj java.lang.Number #+cljs js/Number) + #?(:clj java.lang.Number :cljs js/Number)) (def Int "Any integral number" @@ -392,20 +393,20 @@ (def Regex "A regular expression" - #+clj java.util.regex.Pattern - #+cljs (reify Schema ;; Closure doesn't like if you just def as js/RegExp - (spec [this] - (leaf/leaf-spec - (spec/precondition this #(instance? js/RegExp %) #(list 'instance? 'js/RegExp %)))) - (explain [this] 'Regex))) + #?(:clj java.util.regex.Pattern + :cljs (reify Schema ;; Closure doesn't like if you just def as js/RegExp + (spec [this] + (leaf/leaf-spec + (spec/precondition this #(instance? js/RegExp %) #(list 'instance? 'js/RegExp %)))) + (explain [this] 'Regex)))) (def Inst "The local representation of #inst ..." - #+clj java.util.Date #+cljs js/Date) + #?(:clj java.util.Date :cljs js/Date)) (def Uuid "The local representation of #uuid ..." - #+clj java.util.UUID #+cljs cljs.core/UUID) + #?(:clj java.util.UUID :cljs cljs.core/UUID)) @@ -646,28 +647,32 @@ (clojure.core/defn var-name [v] (let [{:keys [ns name]} (meta v)] - (symbol (str #+clj (ns-name ns) #+cljs ns "/" name)))) + (symbol (str #?(:clj (ns-name ns) + :cljs ns) + "/" name)))) (clojure.core/defrecord Recursive [derefable] Schema (spec [this] (variant/variant-spec spec/+no-precondition+ [{:schema @derefable}])) (explain [this] (list 'recursive - (if #+clj (var? derefable) #+cljs (instance? Var derefable) - (list 'var (var-name derefable)) - #+clj - (format "%s@%x" - (.getName (class derefable)) - (System/identityHashCode derefable)) - #+cljs - '...)))) + (if #?(:clj (var? derefable) + :cljs (instance? Var derefable)) + (list 'var (var-name derefable)) + #?(:clj + (format "%s@%x" + (.getName (class derefable)) + (System/identityHashCode derefable)) + :cljs + '...))))) (clojure.core/defn recursive "Support for (mutually) recursive schemas by passing a var that points to a schema, e.g (recursive #'ExampleRecursiveSchema)." [schema] - (when-not #+clj (instance? clojure.lang.IDeref schema) #+cljs (satisfies? IDeref schema) - (macros/error! (utils/format* "Not an IDeref: %s" schema))) + (when-not #?(:clj (instance? clojure.lang.IDeref schema) + :cljs (satisfies? IDeref schema)) + (macros/error! (utils/format* "Not an IDeref: %s" schema))) (Recursive. schema)) @@ -675,8 +680,8 @@ ;;; Atom schema (defn- atom? [x] - #+clj (instance? clojure.lang.Atom x) - #+cljs (satisfies? IAtom x)) + #?(:clj (instance? clojure.lang.Atom x) + :cljs (satisfies? IAtom x))) (clojure.core/defrecord Atomic [schema] Schema @@ -752,8 +757,8 @@ (optional-key? ks))) (clojure.core/defn map-entry-ctor [[k v :as coll]] - #+clj (clojure.lang.MapEntry. k v) - #+cljs (cljs.core.MapEntry. k v nil)) + #?(:clj (clojure.lang.MapEntry. k v) + :cljs (cljs.core.MapEntry. k v nil))) ;; A schema for a single map entry. (clojure.core/defrecord MapEntry [key-schema val-schema] @@ -816,7 +821,8 @@ (cond e (item-fn e) required? (item-fn (utils/error [rk 'missing-required-key]))) (if e - (dissoc #+clj (if (instance? clojure.lang.PersistentStructMap m) (into {} m) m) #+cljs m + (dissoc #?(:clj (if (instance? clojure.lang.PersistentStructMap m) (into {} m) m) + :cljs m) rk) m)))))) (when extra-keys-schema @@ -840,13 +846,13 @@ (into {} (for [[k v] this] [(explain-kspec k) (explain v)]))) (extend-protocol Schema - #+clj clojure.lang.APersistentMap - #+cljs cljs.core.PersistentArrayMap + #?(:clj clojure.lang.APersistentMap + :cljs cljs.core.PersistentArrayMap) (spec [this] (map-spec this)) (explain [this] (map-explain this)) - #+cljs cljs.core.PersistentHashMap - #+cljs (spec [this] (map-spec this)) - #+cljs (explain [this] (map-explain this))) + #?(:cljs cljs.core.PersistentHashMap) + #?(:cljs (spec [this] (map-spec this))) + #?(:cljs (explain [this] (map-explain this)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -855,8 +861,8 @@ ;; A set schema is a Clojure set with a single element, a schema that all values must satisfy (extend-protocol Schema - #+clj clojure.lang.APersistentSet - #+cljs cljs.core.PersistentHashSet + #?(:clj clojure.lang.APersistentSet + :cljs cljs.core.PersistentHashSet) (spec [this] (macros/assert! (= (count this) 1) "Set schema must have exactly one element") (collection/collection-spec @@ -874,15 +880,15 @@ (clojure.core/defn queue? [x] (instance? - #+clj clojure.lang.PersistentQueue - #+cljs cljs.core/PersistentQueue + #?(:clj clojure.lang.PersistentQueue + :cljs cljs.core/PersistentQueue) x)) (clojure.core/defn as-queue [col] (reduce conj - #+clj clojure.lang.PersistentQueue/EMPTY - #+cljs cljs.core/PersistentQueue.EMPTY + #?(:clj clojure.lang.PersistentQueue/EMPTY + :cljs cljs.core/PersistentQueue.EMPTY) col)) (clojure.core/defrecord Queue [schema] @@ -938,13 +944,13 @@ [(concat required optional) (first more)])) (extend-protocol Schema - #+clj clojure.lang.APersistentVector - #+cljs cljs.core.PersistentVector + #?(:clj clojure.lang.APersistentVector + :cljs cljs.core.PersistentVector) (spec [this] (collection/collection-spec (spec/precondition this - (clojure.core/fn [x] (or (nil? x) (sequential? x) #+clj (instance? java.util.List x))) + (clojure.core/fn [x] (or (nil? x) (sequential? x) #?(:clj (instance? java.util.List x)))) #(list 'sequential? %)) vec (let [[singles multi] (parse-sequence-schema this)] @@ -1013,13 +1019,16 @@ (map-elements schema) (map-error))) (explain [this] - (list 'record #+clj (symbol (.getName ^Class klass)) #+cljs (symbol (pr-str klass)) (explain schema)))) + (list 'record #?(:clj (symbol (.getName ^Class klass)) + :cljs (symbol (pr-str klass))) + (explain schema)))) (clojure.core/defn record* [klass schema map-constructor] - #+clj (macros/assert! (class? klass) "Expected record class, got %s" (utils/type-of klass)) + #?(:clj (macros/assert! (class? klass) "Expected record class, got %s" (utils/type-of klass))) (macros/assert! (map? schema) "Expected map, got %s" (utils/type-of schema)) (with-meta (Record. klass schema) {:constructor map-constructor})) +#?(:clj (defmacro record "A Record instance of type klass, whose elements match map schema 'schema'. @@ -1033,7 +1042,7 @@ (symbol (str/join "/" (concat (butlast bits) [(str "map->" (last bits))])))) #(~(symbol (str (name klass) "/create")) %)))) ([klass schema map-constructor] - `(record* ~klass ~schema #(~map-constructor (into {} %))))) + `(record* ~klass ~schema #(~map-constructor (into {} %)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1063,7 +1072,8 @@ (if (seq input-schema) (if (instance? One (last input-schema)) (count input-schema) - #+clj Long/MAX_VALUE #+cljs js/Number.MAX_VALUE) + #?(:clj Long/MAX_VALUE + :cljs js/Number.MAX_VALUE)) 0)) (clojure.core/defn make-fn-schema @@ -1077,7 +1087,7 @@ (macros/assert! (apply distinct? (map arity input-schemas)) "Arities must be distinct") (FnSchema. output-schema (sort-by arity input-schemas))) - +#?(:clj (defmacro =>* "Produce a function schema from an output schema and a list of arity input schema specs, each of which is a vector of argument schemas, ending with an optional '& more-schema' @@ -1086,13 +1096,14 @@ Currently function schemas are purely descriptive; there is no validation except for functions defined directly by s/fn or s/defn" [output-schema & arity-schema-specs] - `(make-fn-schema ~output-schema ~(mapv macros/parse-arity-spec arity-schema-specs))) + `(make-fn-schema ~output-schema ~(mapv macros/parse-arity-spec arity-schema-specs)))) +#?(:clj (defmacro => "Convenience macro for defining function schemas with a single arity; like =>*, but there is no vector around the argument schemas for this arity." [output-schema & arg-schemas] - `(=>* ~output-schema ~(vec arg-schemas))) + `(=>* ~output-schema ~(vec arg-schemas)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1113,6 +1124,7 @@ [schema] (-> schema meta :ns)) +#?(:clj (defmacro defschema "Convenience macro to make it clear to reader that body is meant to be used as a schema. The name of the schema is recorded in the metadata." @@ -1122,12 +1134,13 @@ `(def ~name ~docstring (vary-meta (schema-with-name ~form '~name) - assoc :ns '~(ns-name *ns*))))) + assoc :ns '~(ns-name *ns*)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Schematized defrecord and (de,let)fn macros +#?(:clj (defmacro defrecord "Define a record with a schema. @@ -1164,34 +1177,36 @@ record base." {:arglists '([name field-schema extra-key-schema? extra-validator-fn? & opts+specs])} [name field-schema & more-args] - (apply macros/emit-defrecord 'clojure.core/defrecord &env name field-schema more-args)) + (apply macros/emit-defrecord 'clojure.core/defrecord &env name field-schema more-args))) -#+clj +#?(:clj (defmacro defrecord+ "DEPRECATED -- canonical version moved to schema.potemkin Like defrecord, but emits a record using potemkin/defrecord+. You must provide your own dependency on potemkin to use this." {:arglists '([name field-schema extra-key-schema? extra-validator-fn? & opts+specs])} [name field-schema & more-args] - (apply macros/emit-defrecord 'potemkin/defrecord+ &env name field-schema more-args)) + (apply macros/emit-defrecord 'potemkin/defrecord+ &env name field-schema more-args))) +#?(:clj (defmacro set-compile-fn-validation! [on?] (macros/set-compile-fn-validation! on?) - nil) + nil)) (clojure.core/defn fn-validation? "Get the current global schema validation setting." [] - #+clj (.get ^java.util.concurrent.atomic.AtomicReference utils/use-fn-validation) - #+cljs @utils/use-fn-validation) + #?(:clj (.get ^java.util.concurrent.atomic.AtomicReference utils/use-fn-validation) + :cljs @utils/use-fn-validation)) (clojure.core/defn set-fn-validation! "Globally turn on (or off) schema validation for all s/fn and s/defn instances." [on?] - #+clj (.set ^java.util.concurrent.atomic.AtomicReference utils/use-fn-validation on?) - #+cljs (reset! utils/use-fn-validation on?)) + #?(:clj (.set ^java.util.concurrent.atomic.AtomicReference utils/use-fn-validation on?) + :cljs (reset! utils/use-fn-validation on?))) +#?(:clj (defmacro with-fn-validation "Execute body with input and output schema validation turned on for all s/defn and s/fn instances globally (across all threads). After @@ -1203,8 +1218,9 @@ (body#) (do (set-fn-validation! true) - (try (body#) (finally (set-fn-validation! false))))))) + (try (body#) (finally (set-fn-validation! false)))))))) +#?(:clj (defmacro without-fn-validation "Execute body with input and output schema validation turned off for all s/defn and s/fn instances globally (across all threads). After @@ -1216,7 +1232,7 @@ (do (set-fn-validation! false) (try (body#) (finally (set-fn-validation! true)))) - (body#)))) + (body#))))) (def fn-validator "A var that can be rebound to a function to customize the behavior @@ -1247,8 +1263,9 @@ (macros/safe-get (meta f) :schema))) ;; work around bug in extend-protocol (refers to bare 'fn, so we can't exclude it). -#+clj (when-not clj-1195-fixed? (ns-unmap *ns* 'fn)) +#?(:clj (when-not clj-1195-fixed? (ns-unmap *ns* 'fn))) +#?(:clj (defmacro fn "s/fn : s/defn :: clojure.core/fn : clojure.core/defn @@ -1272,8 +1289,9 @@ `(let ~outer-bindings (schematize-fn ~(vary-meta `(clojure.core/fn ~name ~@fn-body) #(merge (meta &form) %)) - ~schema-form)))) + ~schema-form))))) +#?(:clj (defmacro defn "Like clojure.core/defn, except that schema-style typehints can be given on the argument symbols and on the function name (for the return value). @@ -1348,8 +1366,9 @@ :schema schema-form) ~@fn-body)] (utils/declare-class-schema! (utils/fn-schema-bearer ~name) ~schema-form) - ret#)))) + ret#))))) +#?(:clj (defmacro defmethod "Like clojure.core/defmethod, except that schema-style typehints can be given on the argument symbols and after the dispatch-val (for the return value). @@ -1373,16 +1392,18 @@ (. ~(with-meta multifn {:tag 'clojure.lang.MultiFn}) addMethod ~dispatch-val - (fn ~(with-meta (gensym (str (name multifn) "__")) (meta multifn)) ~@fn-tail)))) + (fn ~(with-meta (gensym (str (name multifn) "__")) (meta multifn)) ~@fn-tail))))) +#?(:clj (defmacro letfn "s/letfn : s/fn :: clojure.core/letfn : clojure.core/fn" [fnspecs & body] (list `let (vec (interleave (map first fnspecs) (map #(cons `fn %) fnspecs))) - `(do ~@body))) + `(do ~@body)))) +#?(:clj (defmacro def "Like def, but takes a schema on the var name (with the same format as the output schema of s/defn), requires an initial value, and @@ -1405,10 +1426,10 @@ `(let [output-schema# ~(macros/extract-schema-form name)] (def ~name ~@(when doc-string? [doc-string?]) - (validate output-schema# ~init))))) + (validate output-schema# ~init)))))) -#+clj -(set! *warn-on-reflection* false) +#?(:clj +(set! *warn-on-reflection* false)) (clojure.core/defn set-max-value-length! "Sets the maximum length of value to be output before it is contracted to a prettier name." diff --git a/src/cljx/schema/experimental/abstract_map.cljx b/src/cljc/schema/experimental/abstract_map.cljc similarity index 95% rename from src/cljx/schema/experimental/abstract_map.cljx rename to src/cljc/schema/experimental/abstract_map.cljc index 4d06eee7..8cce7a23 100644 --- a/src/cljx/schema/experimental/abstract_map.cljx +++ b/src/cljc/schema/experimental/abstract_map.cljc @@ -2,7 +2,8 @@ "Schemas representing abstract classes and subclasses" (:require [clojure.string :as str] - [schema.core :as s :include-macros true] + #?(:clj [schema.core :as s] + :cljs [schema.core :as s :include-macros true]) [schema.spec.core :as spec] [schema.spec.variant :as variant])) @@ -65,10 +66,11 @@ [dispatch-key :- s/Keyword schema :- (s/pred map?)] (AbstractSchema. (atom {}) dispatch-key schema true)) +#?(:clj (defmacro extend-schema [schema-name extensible-schema dispatch-values extension] `(def ~schema-name - (extend-schema! ~extensible-schema ~extension '~schema-name ~dispatch-values))) + (extend-schema! ~extensible-schema ~extension '~schema-name ~dispatch-values)))) (defn sub-schemas [abstract-schema] @(.-sub-schemas ^AbstractSchema abstract-schema)) diff --git a/src/cljx/schema/spec/collection.cljx b/src/cljc/schema/spec/collection.cljc similarity index 84% rename from src/cljx/schema/spec/collection.cljx rename to src/cljc/schema/spec/collection.cljc index de66d7c8..1e691f16 100644 --- a/src/cljx/schema/spec/collection.cljx +++ b/src/cljc/schema/spec/collection.cljc @@ -2,10 +2,10 @@ "A collection spec represents a collection of elements, each of which is itself schematized." (:require - #+clj [schema.macros :as macros] + #?(:clj [schema.macros :as macros]) [schema.utils :as utils] [schema.spec.core :as spec]) - #+cljs (:require-macros [schema.macros :as macros])) + #?(:cljs (:require-macros [schema.macros :as macros]))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -22,20 +22,20 @@ ::remaining (let [_ (macros/assert! (= 2 (count e)) "remaining can have only one schema.") c (spec/sub-checker (second e) params)] - #+clj (fn [^java.util.List res x] - (doseq [i x] - (.add res (c i))) - (then res nil)) - #+cljs (fn [res x] - (swap! res into (map c x)) - (then res nil)))) + #?(:clj (fn [^java.util.List res x] + (doseq [i x] + (.add res (c i))) + (then res nil)) + :cljs (fn [res x] + (swap! res into (map c x)) + (then res nil))))) (let [parser (:parser e) c (spec/sub-checker e params)] - #+clj (fn [^java.util.List res x] - (then res (parser (fn [t] (.add res (if (utils/error? t) t (c t)))) x))) - #+cljs (fn [res x] - (then res (parser (fn [t] (swap! res conj (if (utils/error? t) t (c t)))) x)))))) + #?(:clj (fn [^java.util.List res x] + (then res (parser (fn [t] (.add res (if (utils/error? t) t (c t)))) x))) + :cljs (fn [res x] + (then res (parser (fn [t] (swap! res conj (if (utils/error? t) t (c t)))) x))))))) (defn- sequence-transformer [elts params then] (macros/assert! (not-any? #(and (vector? %) (= (first %) ::remaining)) (butlast elts)) @@ -46,7 +46,7 @@ then (reverse elts))) -#+clj ;; for performance +#?(:clj ;; for performance (defn- has-error? [^java.util.List l] (let [it (.iterator l)] (loop [] @@ -56,9 +56,9 @@ (recur)) false)))) -#+cljs +:cljs (defn- has-error? [l] - (some utils/error? l)) + (some utils/error? l))) (defn subschemas [elt] (if (map? elt) @@ -75,9 +75,9 @@ t (sequence-transformer elements params (fn [_ x] x))] (fn [x] (or (pre x) - (let [res #+clj (java.util.ArrayList.) #+cljs (atom []) + (let [res #?(:clj (java.util.ArrayList.) :cljs (atom [])) remaining (t res x) - res #+clj res #+cljs @res] + res #?(:clj res :cljs @res)] (if (or (seq remaining) (has-error? res)) (utils/error (on-error x res remaining)) (constructor res)))))))) diff --git a/src/cljx/schema/spec/core.cljx b/src/cljc/schema/spec/core.cljc similarity index 83% rename from src/cljx/schema/spec/core.cljx rename to src/cljc/schema/spec/core.cljc index fb53ff71..f804e64e 100644 --- a/src/cljx/schema/spec/core.cljx +++ b/src/cljc/schema/spec/core.cljc @@ -2,9 +2,9 @@ "Protocol and preliminaries for Schema 'specs', which are a common language for schemas to use to express their structure." (:require - #+clj [schema.macros :as macros] + #?(:clj [schema.macros :as macros]) [schema.utils :as utils]) - #+cljs (:require-macros [schema.macros :as macros])) + #?(:cljs (:require-macros [schema.macros :as macros]))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Core spec protocol @@ -53,10 +53,11 @@ (when-let [reason (macros/try-catchall (when-not (p x) 'not) (catch e# 'throws?))] (macros/validation-error s x (err-f (utils/value-name x)) reason)))) +#?(:clj (defmacro simple-precondition "A simple precondition where f-sym names a predicate (e.g. (simple-precondition s map?))" [s f-sym] - `(precondition ~s ~f-sym #(list (quote ~f-sym) %))) + `(precondition ~s ~f-sym #(list (quote ~f-sym) %)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -70,16 +71,20 @@ s {:subschema-checker f :return-walked? return-walked? - :cache #+clj (java.util.IdentityHashMap.) #+cljs (atom {})})) + :cache #?(:clj (java.util.IdentityHashMap.) :cljs (atom {}))})) (defn with-cache [cache cache-key wrap-recursive-delay result-fn] - (if-let [w #+clj (.get ^java.util.Map cache cache-key) #+cljs (@cache cache-key)] + (if-let [w #?(:clj (.get ^java.util.Map cache cache-key) + :cljs (@cache cache-key))] (if (= ::in-progress w) ;; recursive - (wrap-recursive-delay (delay #+clj (.get ^java.util.Map cache cache-key) #+cljs (@cache cache-key))) + (wrap-recursive-delay (delay #?(:clj (.get ^java.util.Map cache cache-key) + :cljs (@cache cache-key)))) w) - (do #+clj (.put ^java.util.Map cache cache-key ::in-progress) #+cljs (swap! cache assoc cache-key ::in-progress) + (do #?(:clj (.put ^java.util.Map cache cache-key ::in-progress) + :cljs (swap! cache assoc cache-key ::in-progress)) (let [res (result-fn)] - #+clj (.put ^java.util.Map cache cache-key res) #+cljs (swap! cache assoc cache-key res) + #?(:clj (.put ^java.util.Map cache cache-key res) + :cljs (swap! cache assoc cache-key res)) res)))) (defn sub-checker diff --git a/src/cljx/schema/spec/leaf.cljx b/src/cljc/schema/spec/leaf.cljc similarity index 100% rename from src/cljx/schema/spec/leaf.cljx rename to src/cljc/schema/spec/leaf.cljc diff --git a/src/cljx/schema/spec/variant.cljx b/src/cljc/schema/spec/variant.cljc similarity index 96% rename from src/cljx/schema/spec/variant.cljx rename to src/cljc/schema/spec/variant.cljc index 915cc7da..571b739b 100644 --- a/src/cljx/schema/spec/variant.cljx +++ b/src/cljc/schema/spec/variant.cljc @@ -1,9 +1,9 @@ (ns schema.spec.variant (:require - #+clj [schema.macros :as macros] + #?(:clj [schema.macros :as macros]) [schema.utils :as utils] [schema.spec.core :as spec]) - #+cljs (:require-macros [schema.macros :as macros])) + #?(:cljs (:require-macros [schema.macros :as macros]))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/cljx/schema/test.cljx b/src/cljc/schema/test.cljc similarity index 74% rename from src/cljx/schema/test.cljx rename to src/cljc/schema/test.cljc index 358d609d..fc502e88 100644 --- a/src/cljx/schema/test.cljx +++ b/src/cljc/schema/test.cljc @@ -1,7 +1,8 @@ (ns schema.test "Utilities for testing with schemas" - (:require [schema.core :as s :include-macros true] - #+clj clojure.test)) + (:require #?(:clj [schema.core :as s] + :cljs [schema.core :as s :include-macros true]) + #?(:clj clojure.test))) (defn validate-schemas "A fixture for tests: put @@ -10,10 +11,10 @@ [fn-test] (s/with-fn-validation (fn-test))) -#+clj +#?(:clj (defmacro deftest "A test with schema validation turned on globally during execution of the body." [name & body] `(clojure.test/deftest ~name (s/with-fn-validation - ~@body))) + ~@body)))) diff --git a/src/cljx/schema/utils.cljx b/src/cljc/schema/utils.cljc similarity index 69% rename from src/cljx/schema/utils.cljx rename to src/cljc/schema/utils.cljc index 43823033..29ab8d17 100644 --- a/src/cljx/schema/utils.cljx +++ b/src/cljc/schema/utils.cljc @@ -1,13 +1,13 @@ (ns schema.utils "Private utilities used in schema implementation." (:refer-clojure :exclude [record?]) - #+clj (:require [clojure.string :as string]) - #+cljs (:require - goog.string.format - [goog.object :as gobject] - [goog.string :as gstring] - [clojure.string :as string]) - #+cljs (:require-macros [schema.utils :refer [char-map]])) + #?(:clj (:require [clojure.string :as string]) + :cljs (:require + goog.string.format + [goog.object :as gobject] + [goog.string :as gstring] + [clojure.string :as string])) + #?(:cljs (:require-macros [schema.utils :refer [char-map]]))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Miscellaneous helpers @@ -23,18 +23,18 @@ [k v]))) (defn type-of [x] - #+clj (class x) - #+cljs (js* "typeof ~{}" x)) + #?(:clj (class x) + :cljs (js* "typeof ~{}" x))) (defn fn-schema-bearer "What class can we associate the fn schema with? In Clojure use the class of the fn; in cljs just use the fn itself." [f] - #+clj (class f) - #+cljs f) + #?(:clj (class f) + :cljs f)) (defn format* [fmt & args] - (apply #+clj format #+cljs gstring/format fmt args)) + (apply #?(:clj format :cljs gstring/format) fmt args)) (def max-value-length (atom 19)) @@ -44,37 +44,39 @@ (let [t (type-of value)] (if (<= (count (str value)) @max-value-length) value - (symbol (str "a-" #+clj (.getName ^Class t) #+cljs t))))) + (symbol (str "a-" #?(:clj (.getName ^Class t) :cljs t)))))) +#?(:clj (defmacro char-map [] - clojure.lang.Compiler/CHAR_MAP) + clojure.lang.Compiler/CHAR_MAP)) +#?(:clj (defn unmunge "TODO: eventually use built in demunge in latest cljs." [s] (->> (char-map) (sort-by #(- (count (second %)))) - (reduce (fn [^String s [to from]] (string/replace s from (str to))) s))) + (reduce (fn [^String s [to from]] (string/replace s from (str to))) s)))) (defn fn-name "A meaningful name for a function that looks like its symbol, if applicable." [f] - #+cljs - (let [[_ s] (re-matches #"#object\[(.*)\]" (pr-str f))] - (if (= "Function" s) - "function" - (->> s demunge (re-find #"[^/]+(?:$|(?=/+$))")))) - #+clj (let [s (.getName (class f)) - slash (.lastIndexOf s "$") - raw (unmunge - (if (>= slash 0) - (str (subs s 0 slash) "/" (subs s (inc slash))) - s))] - (string/replace raw #"^clojure.core/" ""))) + #?(:cljs + (let [[_ s] (re-matches #"#object\[(.*)\]" (pr-str f))] + (if (= "Function" s) + "function" + (->> s demunge (re-find #"[^/]+(?:$|(?=/+$))")))) + :clj (let [s (.getName (class f)) + slash (.lastIndexOf s "$") + raw (unmunge + (if (>= slash 0) + (str (subs s 0 slash) "/" (subs s (inc slash))) + s))] + (string/replace raw #"^clojure.core/" "")))) (defn record? [x] - #+clj (instance? clojure.lang.IRecord x) - #+cljs (satisfies? IRecord x)) + #?(:clj (instance? clojure.lang.IRecord x) + :cljs (satisfies? IRecord x))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -87,16 +89,16 @@ (declare validation-error-explain) (deftype ValidationError [schema value expectation-delay fail-explanation] - #+cljs IPrintWithWriter - #+cljs (-pr-writer [this writer opts] - (-pr-writer (validation-error-explain this) writer opts))) + #?(:cljs IPrintWithWriter) + #?(:cljs (-pr-writer [this writer opts] + (-pr-writer (validation-error-explain this) writer opts)))) (defn validation-error-explain [^ValidationError err] (list (or (.-fail-explanation err) 'not) @(.-expectation-delay err))) -#+clj ;; Validation errors print like forms that would return false +#?(:clj ;; Validation errors print like forms that would return false (defmethod print-method ValidationError [err writer] - (print-method (validation-error-explain err) writer)) + (print-method (validation-error-explain err) writer))) (defn make-ValidationError "for cljs sake (easier than normalizing imports in macros.clj)" @@ -108,16 +110,16 @@ (declare named-error-explain) (deftype NamedError [name error] - #+cljs IPrintWithWriter - #+cljs (-pr-writer [this writer opts] - (-pr-writer (named-error-explain this) writer opts))) + #?(:cljs IPrintWithWriter) + #?(:cljs (-pr-writer [this writer opts] + (-pr-writer (named-error-explain this) writer opts)))) (defn named-error-explain [^NamedError err] (list 'named (.-error err) (.-name err))) -#+clj ;; Validation errors print like forms that would return false +#?(:clj ;; Validation errors print like forms that would return false (defmethod print-method NamedError [err writer] - (print-method (named-error-explain err) writer)) + (print-method (named-error-explain err) writer))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -140,7 +142,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Registry for attaching schemas to classes, used for defn and defrecord -#+clj +#?(:clj (let [^java.util.Map +class-schemata+ (java.util.Collections/synchronizedMap (java.util.WeakHashMap.))] (defn declare-class-schema! [klass schema] "Globally set the schema for a class (above and beyond a simple instance? check). @@ -153,15 +155,15 @@ (defn class-schema [klass] "The last schema for a class set by declare-class-schema!, or nil." - (.get +class-schemata+ klass))) + (.get +class-schemata+ klass)))) -#+cljs +#?(:cljs (do (defn declare-class-schema! [klass schema] (gobject/set klass "schema$utils$schema" schema)) (defn class-schema [klass] - (gobject/get klass "schema$utils$schema"))) + (gobject/get klass "schema$utils$schema")))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -172,5 +174,5 @@ s/compile-fn-validation was true -- has no effect for functions compiled when it is false." ;; specialize in Clojure for performance - #+clj (java.util.concurrent.atomic.AtomicReference. false) - #+cljs (atom false)) + #?(:clj (java.util.concurrent.atomic.AtomicReference. false) + :cljs (atom false))) diff --git a/test/cljx/schema/coerce_test.cljx b/test/cljc/schema/coerce_test.cljc similarity index 64% rename from test/cljx/schema/coerce_test.cljx rename to test/cljc/schema/coerce_test.cljc index 835d85bf..d7854281 100644 --- a/test/cljx/schema/coerce_test.cljx +++ b/test/cljc/schema/coerce_test.cljc @@ -1,12 +1,12 @@ (ns schema.coerce-test - #+clj (:use clojure.test) - #+cljs (:use-macros - [cljs.test :only [is deftest]]) + #?(:clj (:use clojure.test) + :cljs (:use-macros + [cljs.test :only [is deftest]])) (:require [schema.core :as s] [schema.utils :as utils] [schema.coerce :as coerce] - #+cljs cljs.test)) + #?(:cljs cljs.test))) ;; s/Num s/Int @@ -25,13 +25,13 @@ (def JSON {(s/optional-key :is) [s/Int]}) -#+clj +#?(:clj (def JVM {(s/optional-key :jb) Boolean (s/optional-key :l) long (s/optional-key :d) Double (s/optional-key :f) Float - (s/optional-key :jk) clojure.lang.Keyword}) + (s/optional-key :jk) clojure.lang.Keyword})) (defn err-ks [res] (set (keys (utils/error-val res)))) @@ -48,20 +48,20 @@ (is (= {:i 1 :b false} (coercer {:i 1.0 :b "Yes"}))) (is (= #{:i :set} (err-ks (coercer {:i 1.1 :n 3 :set "a"}))))) - #+clj (testing "jvm specific" - (let [coercer (coerce/coercer JVM coerce/json-coercion-matcher) - res {:l 1 :d 1.0 :jk :asdf :f (float 0.1)}] - (is (= res (coercer {:l 1.0 :d 1 :jk "asdf" :f 0.1}) )) - (is (= res (coercer res))) - (is (= {:jb true} (coercer {:jb "TRUE"}))) - (is (= {:jb false} (coercer {:jb "Yes"}))) - (is (= #{:l :jk :f} (err-ks (coercer {:l 1.2 :jk 1.0 :f "0"})))) - (is (= #{:f} (err-ks (coercer {:f nil})))) - (is (= #{:d} (err-ks (coercer {:d nil})))) - (is (= #{:d} (err-ks (coercer {:d "1.0"})))))) - #+clj (testing "malformed uuid" - (let [coercer (coerce/coercer Generic coerce/json-coercion-matcher)] - (is (= #{:u} (err-ks (coercer {:i 1 :u "uuid-wannabe"}))))))) + #?(:clj (testing "jvm specific" + (let [coercer (coerce/coercer JVM coerce/json-coercion-matcher) + res {:l 1 :d 1.0 :jk :asdf :f (float 0.1)}] + (is (= res (coercer {:l 1.0 :d 1 :jk "asdf" :f 0.1}) )) + (is (= res (coercer res))) + (is (= {:jb true} (coercer {:jb "TRUE"}))) + (is (= {:jb false} (coercer {:jb "Yes"}))) + (is (= #{:l :jk :f} (err-ks (coercer {:l 1.2 :jk 1.0 :f "0"})))) + (is (= #{:f} (err-ks (coercer {:f nil})))) + (is (= #{:d} (err-ks (coercer {:d nil})))) + (is (= #{:d} (err-ks (coercer {:d "1.0"}))))))) + #?(:clj (testing "malformed uuid" + (let [coercer (coerce/coercer Generic coerce/json-coercion-matcher)] + (is (= #{:u} (err-ks (coercer {:i 1 :u "uuid-wannabe"})))))))) (deftest string-coercer-test (let [coercer (coerce/coercer Generic coerce/string-coercion-matcher)] @@ -69,18 +69,18 @@ (coercer {:b "true" :i "1" :n "3.0" :s "asdf" :k1 {"1" "hi"} :k2 "bye" :e "a" :eq "k" :u "550e8400-e29b-41d4-a716-446655440000" :set ["a" "a" "b"]}))) (is (= #{:i} (err-ks (coercer {:i "1.1"}))))) - #+clj (testing "jvm specific" - (let [coercer (coerce/coercer JVM coerce/string-coercion-matcher) - res {:jb false :l 2 :d 1.0 :jk :asdf}] - (is (= res (coercer {:jb "false" :l "2.0" :d "1" :jk "asdf"}))) - (is (= #{:l} (err-ks (coercer {:l "1.2"}))))))) + #?(:clj (testing "jvm specific" + (let [coercer (coerce/coercer JVM coerce/string-coercion-matcher) + res {:jb false :l 2 :d 1.0 :jk :asdf}] + (is (= res (coercer {:jb "false" :l "2.0" :d "1" :jk "asdf"}))) + (is (= #{:l} (err-ks (coercer {:l "1.2"})))))))) (deftest coercer!-test (let [coercer (coerce/coercer! {:k s/Keyword :i s/Int} coerce/string-coercion-matcher)] (is (= {:k :key :i 12} (coercer {:k "key" :i "12"}))) - (is (thrown-with-msg? #+clj Exception #+cljs js/Error #"keyword\? 12" (coercer {:k 12 :i 12}))))) + (is (thrown-with-msg? #?(:clj Exception :cljs js/Error) #"keyword\? 12" (coercer {:k 12 :i 12}))))) -#+clj +#?(:clj (do (def NestedVecs [(s/one s/Num "Node ID") (s/recursive #'NestedVecs)]) @@ -89,7 +89,7 @@ "Test that recursion (which rebinds subschema-walker) works with coercion." (is (= [1 [2 [3] [4]]] ((coerce/coercer NestedVecs coerce/string-coercion-matcher) - ["1" ["2" ["3"] ["4"]]]))))) + ["1" ["2" ["3"] ["4"]]])))))) (deftest constrained-test (is (= 1 ((coerce/coercer! (s/constrained s/Int odd?) coerce/string-coercion-matcher) "1"))) diff --git a/test/cljx/schema/core_test.cljx b/test/cljc/schema/core_test.cljc similarity index 93% rename from test/cljx/schema/core_test.cljx rename to test/cljc/schema/core_test.cljc index 1fb461cb..50156bb1 100644 --- a/test/cljx/schema/core_test.cljx +++ b/test/cljc/schema/core_test.cljc @@ -6,31 +6,31 @@ - (invalid! s x) asserts that (s/check s x) returns a validation failure - The optional last argument also checks the printed Clojure representation of the error. - (invalid-call! s x) asserts that calling the function throws an error." - #+clj (:use clojure.test [schema.test-macros :only [valid! invalid! invalid-call!]]) - #+cljs (:use-macros - [cljs.test :only [is deftest testing are]] - [schema.test-macros :only [valid! invalid! invalid-call!]]) - #+cljs (:require-macros [schema.macros :as macros]) + #?(:clj (:use clojure.test [schema.test-macros :only [valid! invalid! invalid-call!]])) + #?(:cljs (:use-macros + [cljs.test :only [is deftest testing are]] + [schema.test-macros :only [valid! invalid! invalid-call!]])) + #?(:cljs (:require-macros [schema.macros :as macros])) (:require [clojure.string :as str] - #+clj [clojure.pprint :as pprint] + #?(:clj [clojure.pprint :as pprint]) clojure.data [schema.utils :as utils] [schema.core :as s] [schema.other-namespace :as other-namespace] [schema.spec.core :as spec] [schema.spec.collection :as collection] - #+clj [schema.macros :as macros] - #+cljs cljs.test)) + #?(:clj [schema.macros :as macros]) + #?(:cljs cljs.test))) -#+cljs +#?(:cljs (do (def Exception js/Error) (def AssertionError js/Error) - (def Throwable js/Error)) + (def Throwable js/Error))) (deftest if-cljs-test - (is (= #+cljs true #+clj false (macros/if-cljs true false)))) + (is (= #?(:cljs true :clj false) (macros/if-cljs true false)))) (deftest try-catchall-test (let [a (atom 0)] @@ -47,16 +47,16 @@ (deftest fn-name-test (is (= "odd?" (utils/fn-name odd?))) - (is (= #+clj "schema.core-test/foo-bar" #+cljs "foo-bar" + (is (= #?(:clj "schema.core-test/foo-bar" :cljs "foo-bar") (utils/fn-name foo-bar))) - #+clj (is (= "schema.core-test$fn" (subs (utils/fn-name (fn foo [x] (+ x x))) 0 19))) - #+cljs (is (= "foo" (utils/fn-name (fn foo [x] (+ x x))))) - #+cljs (is (= "function" (utils/fn-name (fn [x] (+ x x)))))) + #?(:clj (is (= "schema.core-test$fn" (subs (utils/fn-name (fn foo [x] (+ x x))) 0 19)))) + #?(:cljs (is (= "foo" (utils/fn-name (fn foo [x] (+ x x)))))) + #?(:cljs (is (= "function" (utils/fn-name (fn [x] (+ x x))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Platform-specific leaf Schemas -#+clj +#?(:clj (do (deftest class-test (valid! String "a") @@ -86,7 +86,7 @@ (valid! (Class/forName "[D") (double-array [1.0])) (invalid! (Class/forName "[D") (into-array Double [1.0])) (valid! doubles (double-array [1.0])) - (is (= 'doubles (s/explain doubles))))) + (is (= 'doubles (s/explain doubles)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -114,10 +114,10 @@ (valid! schema-no-h ::integer) (invalid! schema-with-h ::form) (invalid! schema-no-h ::form) - #+clj - (valid! (s/isa java.lang.Number) java.lang.Long) - #+cljs - (valid! (s/isa js/Number) js/Number) + #?(:clj + (valid! (s/isa java.lang.Number) java.lang.Long) + :cljs + (valid! (s/isa js/Number) js/Number)) (is (= '(isa? ::shape) (s/explain schema-with-h))) (is (= '(isa? ::number) (s/explain schema-no-h))))) @@ -189,7 +189,7 @@ (deftest leaf-int-test (valid! s/Int 1) (invalid! s/Int 1.2 "(not (integer? 1.2))") - #+clj (invalid! s/Int 1.0 "(not (integer? 1.0))") + #?(:clj (invalid! s/Int 1.0 "(not (integer? 1.0))")) (invalid! s/Int nil "(not (integer? nil))") (is (= 'Int (s/explain s/Int)))) @@ -293,11 +293,11 @@ (let [schema (s/conditional (fn [x] (throw (ex-info "non-fatal error" {}))) s/Int)] (invalid! schema 99))) - #+clj + #?(:clj (testing "fatal exceptions are not caught" (let [schema (s/conditional (fn [x] (throw (InterruptedException.))) s/Int)] - (is (thrown? InterruptedException (s/validate schema 42)))))) + (is (thrown? InterruptedException (s/validate schema 42))))))) (deftest cond-pre-test (let [s (s/cond-pre @@ -388,9 +388,9 @@ (invalid! schema {:x {:x {:y {}}}}) (let [explanation (first (s/explain schema))] (is (= '(optional-key :x) (key explanation))) - #+clj (is (= 'recursive (first (val explanation)))) - #+clj (is (re-matches #"clojure.lang.Atom.*" (second (val explanation)))) - #+cljs (is (= '(recursive ...) (val explanation))))) + #?(:clj (is (= 'recursive (first (val explanation))))) + #?(:clj (is (re-matches #"clojure.lang.Atom.*" (second (val explanation))))) + #?(:cljs (is (= '(recursive ...) (val explanation)))))) (is (= '{:black {(optional-key :red) (recursive (var schema.core-test/TestBlackNode))}} (s/explain TestBlackNode)))) @@ -475,7 +475,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Handle Struct -#+clj +#?(:clj (do (defstruct ts1 :num :str :map :vec) (defstruct ts2 :num :str) @@ -507,7 +507,7 @@ (invalid! schema (struct ts2 1 "str")) (invalid! schema (assoc (struct ts2 1 "str") :map {:key 1} - :vec []))))) + :vec [])))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Set Schemas @@ -568,7 +568,7 @@ (valid! schema []) (valid! schema [1 2 3]) (invalid! schema {}) - #+clj (invalid! schema [1 2 1.0]) + #?(:clj (invalid! schema [1 2 1.0])) (invalid! schema [1 2 1.1]))) (deftest simple-one-seq-test @@ -613,7 +613,7 @@ (invalid! schema ["user1" 42 42]) (valid! schema ["user2" 41]) )) -#+clj +#?(:clj (deftest java-list-test (let [schema [s/Str]] (valid! schema (java.util.ArrayList. ["hi" "bye"])) @@ -622,7 +622,7 @@ (invalid! schema (java.util.LinkedList. [1 2])) (valid! schema java.util.Collections/EMPTY_LIST) (invalid! schema java.util.Collections/EMPTY_MAP) - (invalid! schema #{"hi" "bye"}))) + (invalid! schema #{"hi" "bye"})))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Record Schemas @@ -634,8 +634,8 @@ (valid! schema (Foo. :foo 1)) (invalid! schema {:x :foo :y 1}) (invalid! schema (assoc (Foo. :foo 1) :bar 2)) - #+clj (is (= '(record schema.core_test.Foo {:x Any, (optional-key :y) Int}) - (s/explain schema))))) + #?(:clj (is (= '(record schema.core_test.Foo {:x Any, (optional-key :y) Int}) + (s/explain schema)))))) (deftest record-with-extra-keys-test (let [schema (s/record Foo {:x s/Any @@ -672,13 +672,14 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Schematized defrecord +#?(:clj (defmacro test-normalized-meta [symbol ex-schema desired-meta] (let [normalized (macros/normalized-metadata &env symbol ex-schema)] `(do (is (= '~symbol '~normalized)) (is (= ~(select-keys desired-meta [:schema :tag]) - ~(select-keys (meta normalized) [:schema :tag])))))) + ~(select-keys (meta normalized) [:schema :tag]))))))) -#+clj +#?(:clj (do (def ASchema [long]) @@ -700,7 +701,7 @@ (testing "no-tag" (test-meta-extraction [x] [x])) (testing "old-tags" (test-meta-extraction [^String x] [^String x])) (testing "new-vs-old-tag" (test-meta-extraction [^String x] [x :- String])) - (testing "multi vars" (test-meta-extraction [x ^String y z] [x y :- String z])))) + (testing "multi vars" (test-meta-extraction [x ^String y z] [x y :- String z]))))) (defprotocol PProtocol (do-something [this])) @@ -782,7 +783,7 @@ (def LongOrString (s/either s/Int s/Str)) -#+clj (s/defrecord Nested [^Bar4 b ^LongOrString c p :- (s/protocol PProtocol)]) +#?(:clj (s/defrecord Nested [^Bar4 b ^LongOrString c p :- (s/protocol PProtocol)])) (s/defrecord NestedExplicit [b :- Bar4 c :- LongOrString p :- (s/protocol PProtocol)]) (defn test-fancier-defrecord-schema [klass constructor] @@ -802,7 +803,7 @@ (invalid! klass (constructor {:b nil :c "hi" :p bar2})))) (deftest fancier-defrecord-schema-test - #+clj (test-fancier-defrecord-schema Nested map->Nested) + #?(:clj (test-fancier-defrecord-schema Nested map->Nested)) (test-fancier-defrecord-schema NestedExplicit map->NestedExplicit)) @@ -815,12 +816,12 @@ (valid! OddSum (OddSum. 1 2)) (invalid! OddSum (OddSum. 1 3))) -#+clj +#?(:clj (do (s/defrecord RecordWithPrimitive [x :- long]) (deftest record-with-primitive-test (valid! RecordWithPrimitive (RecordWithPrimitive. 1)) (is (thrown? Exception (RecordWithPrimitive. "a"))) - (is (thrown? Exception (RecordWithPrimitive. nil))))) + (is (thrown? Exception (RecordWithPrimitive. nil)))))) (deftest map->record-test (let [subset {:foo 1 :bar "a"} @@ -845,16 +846,16 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Schematized functions -#+clj +#?(:clj (deftest split-rest-arg-test (is (= (macros/split-rest-arg {} ['a '& 'b]) '[[a] b])) (is (= (macros/split-rest-arg {} ['a 'b]) - '[[a b] nil]))) + '[[a b] nil])))) ;;; fn -(def OddLong (s/both (s/pred odd?) #+cljs s/Int #+clj long)) +(def OddLong (s/both (s/pred odd?) #?(:cljs s/Int :clj long))) (def +test-fn-schema+ "Schema for (s/fn ^String [^OddLong x y])" @@ -878,7 +879,7 @@ (s/with-fn-validation (is (= 4 (f 1 {:foo 3}))) ;; Primitive Interface Test - #+clj (is (thrown? Exception (.invokePrim f 1 {:foo 3}))) ;; primitive type hints don't work on fns + #?(:clj (is (thrown? Exception (.invokePrim f 1 {:foo 3})))) ;; primitive type hints don't work on fns (invalid-call! f 1 {:foo 4}) ;; foo not odd? (invalid-call! f 2 {:foo 3})) ;; return not even? @@ -958,8 +959,8 @@ (is (= 0 (f -1)))))) (defn parse-long [x] - #+clj (Long/parseLong x) - #+cljs (js/parseInt x)) + #?(:clj (Long/parseLong x) + :cljs (js/parseInt x))) (deftest destructured-validated-fn-test (let [LongPair [(s/one s/Int 'x) (s/one s/Int 'y)] @@ -1038,11 +1039,11 @@ (s/with-fn-validation (is (= 120 (f 5 1))))))) -#+clj ;; in ClojureScript, metadata on ordinary fn form does not propagate to fn either. +#?(:clj ;; in ClojureScript, metadata on ordinary fn form does not propagate to fn either. (deftest fn-metadata-test (let [->mkeys #(set (keys (meta %)))] (is (= (into (->mkeys (s/fn [])) [:blah]) - (->mkeys ^:blah (s/fn [])))))) + (->mkeys ^:blah (s/fn []))))))) ;;; defn @@ -1068,13 +1069,13 @@ (def ^String +bad-input-str+ "Input to simple-validated-defn does not match schema") ;; Test that s/defn returns var -#+clj +#?(:clj (with-test (s/defn with-test-fn [a b] (+ a b)) (is (= 3 (with-test-fn 1 2))) - (is (= 0 (with-test-fn 10 -10)))) + (is (= 0 (with-test-fn 10 -10))))) -#+cljs +#?(:cljs (deftest simple-validated-defn-test (s/with-fn-validation (is (= "3" (simple-validated-defn 3))) @@ -1091,18 +1092,18 @@ (catch js/Error e e))] (when e ;; validation can be disabled at compile time, and exception not thrown (is (>= (.indexOf (str e) +bad-input-str+) 0))))) - (is (= +simple-validated-defn-schema+ (s/fn-schema simple-validated-defn)))) + (is (= +simple-validated-defn-schema+ (s/fn-schema simple-validated-defn))))) -#+clj +#?(:clj (s/defn ^String multi-arglist-validated-defn :- OddLongString "I am a multi-arglist schema fn" {:metadata :bla} ([arg0 :- OddLong] (str arg0)) ([arg0 :- OddLong arg1 :- Long] - (str (+ arg0 arg1)))) + (str (+ arg0 arg1))))) -#+clj +#?(:clj (deftest simple-validated-defn-test (is (= "Inputs: [arg0 :- OddLong]\n Returns: OddLongString\n\n I am a simple schema fn" (:doc (meta #'simple-validated-defn)))) @@ -1121,7 +1122,7 @@ (validated-pre-post-defn 1))) (invalid-call! validated-pre-post-defn "a"))) (let [{:keys [tag schema metadata]} (meta #'simple-validated-defn)] - #+clj (is (= tag s/Str)) + (is (= tag s/Str)) (is (= +simple-validated-defn-schema+ schema)) (is (= metadata :bla))) (is (= +simple-validated-defn-schema+ (s/fn-schema simple-validated-defn))) @@ -1135,7 +1136,7 @@ (let [e ^Exception (try (s/with-fn-validation (simple-validated-defn 2)) nil (catch Exception e e))] (is (.contains (.getMessage e) +bad-input-str+)) (is (.contains (.getClassName ^StackTraceElement (first (.getStackTrace e))) "simple_validated_defn")) - (is (.startsWith (.getFileName ^StackTraceElement (first (.getStackTrace e))) "core_test.clj")))) + (is (.startsWith (.getFileName ^StackTraceElement (first (.getStackTrace e))) "core_test.clj"))))) (s/defn ^:always-validate always-validated-defn :- (s/pred even?) [x :- (s/pred pos?)] @@ -1202,7 +1203,7 @@ (invalid-call! y (x))))) ;; Primitive validation testing for JVM -#+clj +#?(:clj (do (def +primitive-validated-defn-schema+ @@ -1230,12 +1231,12 @@ (deftest another-primitive-fn-test (is ((ancestors (class another-primitive-fn)) clojure.lang.IFn$LD)) - (is (= 1.0 (another-primitive-fn 10))))) + (is (= 1.0 (another-primitive-fn 10)))))) (deftest with-fn-validation-error-test - (is (thrown? #+clj RuntimeException #+cljs js/Error - (s/with-fn-validation (throw #+clj (RuntimeException.) #+cljs (js/Error. "error"))))) + (is (thrown? #?(:clj RuntimeException :cljs js/Error) + (s/with-fn-validation (throw #?(:clj (RuntimeException.) :cljs (js/Error. "error")))))) (is (false? (s/fn-validation?)))) @@ -1246,15 +1247,15 @@ (is (= 1 v)) (s/def v "doc" 2) (is (= 2 v)) - #+clj (is (= "doc" (:doc (meta #'v)))) + #?(:clj (is (= "doc" (:doc (meta #'v))))) (s/def v :- s/Int "doc" 3) (is (= 3 v)) - #+clj (is (= "doc" (:doc (meta #'v)))) + #?(:clj (is (= "doc" (:doc (meta #'v))))) (s/def v :- s/Int 3) - #+clj (is (= String (:tag (meta (s/def v :- String "a"))))) - #+clj (is (thrown? Exception (s/def v :- s/Int "doc" 1.0))) - #+clj (is (thrown? Exception (s/def v :- s/Int 1.0))) - #+clj (is (thrown? Exception (s/def ^s/Int v 1.0)))) + #?(:clj (is (= String (:tag (meta (s/def v :- String "a")))))) + #?(:clj (is (thrown? Exception (s/def v :- s/Int "doc" 1.0)))) + #?(:clj (is (thrown? Exception (s/def v :- s/Int 1.0)))) + #?(:clj (is (thrown? Exception (s/def ^s/Int v 1.0))))) ;; defmethod @@ -1290,7 +1291,7 @@ (deftest defmethod-metadata-test (s/defmethod ^:always-validate m :v :- s/Num [m :- {:k s/Keyword} x :- s/Num y :- s/Num] "wrong") - (is (thrown? #+clj RuntimeException #+cljs js/Error + (is (thrown? #?(:clj RuntimeException :cljs js/Error) (m {:k :v} 1 2)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1320,7 +1321,7 @@ [^s/Int foo ^s/Keyword bar] {(s/optional-key :baz) s/Keyword}) -#+clj ;; clojurescript.test hangs on this test in phantom.js, so marking clj-only +#?(:clj ;; clojurescript.test hangs on this test in phantom.js, so marking clj-only (deftest fancy-explain-test (is (= (s/explain {(s/required-key 'x) s/Int s/Keyword [(s/one s/Int "foo") (s/maybe Explainer)]}) @@ -1328,18 +1329,19 @@ ~'Keyword [(~'one ~'Int "foo") (~'maybe (~'record - #+clj Explainer #+cljs schema.core-test/Explainer + #?(:clj Explainer + :cljs schema.core-test/Explainer) {:foo ~'Int :bar ~'Keyword - (~'optional-key :baz) ~'Keyword}))]}))) + (~'optional-key :baz) ~'Keyword}))]})))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Regression tests -#+clj +#?(:clj (deftest pprint-test - (is (= "(maybe Int)" (str/trim (with-out-str (pprint/pprint (s/maybe s/Int))))))) + (is (= "(maybe Int)" (str/trim (with-out-str (pprint/pprint (s/maybe s/Int)))))))) (defrecord ItemTest [first second]) @@ -1440,11 +1442,11 @@ (is false "unreachable") (catch Exception e (is (re-find #"ffbe878f" - (#+cljs .-message #+clj .getMessage e)))))) + (#?(:cljs .-message :clj .getMessage) e)))))) (testing "multimethods in a different namespace" (try (other-namespace/ef408750 42) (is false "unreachable") (catch Exception e (is (re-find #"ef408750" - (#+cljs .-message #+clj .getMessage e))))))) + (#?(:cljs .-message :clj .getMessage) e))))))) diff --git a/test/cljx/schema/experimental/abstract_map_test.cljx b/test/cljc/schema/experimental/abstract_map_test.cljc similarity index 79% rename from test/cljx/schema/experimental/abstract_map_test.cljx rename to test/cljc/schema/experimental/abstract_map_test.cljc index b71d30e3..25a644dd 100644 --- a/test/cljx/schema/experimental/abstract_map_test.cljx +++ b/test/cljc/schema/experimental/abstract_map_test.cljc @@ -1,13 +1,14 @@ (ns schema.experimental.abstract-map-test - #+clj (:use clojure.test [schema.test-macros :only [valid! invalid! invalid-call!]]) - #+cljs (:use-macros - [cljs.test :only [is deftest testing]] - [schema.test-macros :only [valid! invalid! invalid-call!]]) + #?(:clj (:use clojure.test [schema.test-macros :only [valid! invalid! invalid-call!]]) + :cljs (:use-macros + [cljs.test :only [is deftest testing]] + [schema.test-macros :only [valid! invalid! invalid-call!]])) (:require [schema.core :as s] [schema.coerce :as coerce] - [schema.experimental.abstract-map :as abstract-map :include-macros true] - #+cljs cljs.test)) + #?(:clj [schema.experimental.abstract-map :as abstract-map] + :cljs [schema.experimental.abstract-map :as abstract-map :include-macros true]) + #?(:cljs cljs.test))) (s/defschema Animal (abstract-map/abstract-map-schema diff --git a/test/cljx/schema/other_namespace.cljx b/test/cljc/schema/other_namespace.cljc similarity index 100% rename from test/cljx/schema/other_namespace.cljx rename to test/cljc/schema/other_namespace.cljc diff --git a/test/cljx/schema/test_test.cljx b/test/cljc/schema/test_test.cljc similarity index 72% rename from test/cljx/schema/test_test.cljx rename to test/cljc/schema/test_test.cljc index 84ea9e57..17db6f13 100644 --- a/test/cljx/schema/test_test.cljx +++ b/test/cljc/schema/test_test.cljc @@ -1,10 +1,10 @@ (ns schema.test-test - #+clj (:use clojure.test) + #?(:clj (:use clojure.test)) (:require [schema.core :as s] [schema.test :as st])) -#+clj +#?(:clj (do (s/defn test-fn :- s/Str [] 5) @@ -12,4 +12,4 @@ (is (= 5 (test-fn)))) (st/deftest validation-on-test - (is (thrown? Exception (test-fn))))) + (is (thrown? Exception (test-fn)))))) diff --git a/test/cljc/schema/utils_test.cljc b/test/cljc/schema/utils_test.cljc new file mode 100644 index 00000000..0d954d70 --- /dev/null +++ b/test/cljc/schema/utils_test.cljc @@ -0,0 +1,29 @@ +(ns schema.utils-test + #?(:clj (:use clojure.test) + :cljs (:use-macros + [cljs.test :only [are deftest]])) + (:require + [schema.utils :as utils])) + +(defn ^:private a-defn-function-with-a-normal-name [a b c d]) + +(deftest fn-name-test + (are [in pattern] (re-matches pattern (utils/fn-name in)) + + (fn a-fn-function-with-a-normal-name [x]) + #?(:clj #".*/a-fn-function-with-a-normal-name.*" + :cljs #"a-fn-function-with-a-normal-name") + + a-defn-function-with-a-normal-name + #?(:clj #".*/a-defn-function-with-a-normal-name" + :cljs #"a-defn-function-with-a-normal-name") + + ;; regression for issue #416 + (fn foo$$ [x]) + #?(:clj #"schema.utils.*foo.*" + :cljs #"foo") + + + #(+ 1 2) + #?(:clj #"schema\.utils-test.*" + :cljs #"function"))) diff --git a/test/cljx/schema/utils_test.cljx b/test/cljx/schema/utils_test.cljx deleted file mode 100644 index b9db3325..00000000 --- a/test/cljx/schema/utils_test.cljx +++ /dev/null @@ -1,29 +0,0 @@ -(ns schema.utils-test - #+clj (:use clojure.test) - #+cljs (:use-macros - [cljs.test :only [are deftest]]) - (:require - [schema.utils :as utils])) - -(defn ^:private a-defn-function-with-a-normal-name [a b c d]) - -(deftest fn-name-test - (are [in pattern] (re-matches pattern (utils/fn-name in)) - - (fn a-fn-function-with-a-normal-name [x]) - #+clj #".*/a-fn-function-with-a-normal-name.*" - #+cljs #"a-fn-function-with-a-normal-name" - - a-defn-function-with-a-normal-name - #+clj #".*/a-defn-function-with-a-normal-name" - #+cljs #"a-defn-function-with-a-normal-name" - - ;; regression for issue #416 - (fn foo$$ [x]) - #+clj #"schema.utils.*foo.*" - #+cljs #"foo" - - - #(+ 1 2) - #+clj #"schema\.utils-test.*" - #+cljs #"function"))