{"id":13393097,"url":"https://github.com/jeaye/orchestra","last_synced_at":"2025-05-15T12:05:28.591Z","repository":{"id":55412401,"uuid":"86546742","full_name":"jeaye/orchestra","owner":"jeaye","description":"Complete instrumentation for clojure.spec","archived":false,"fork":false,"pushed_at":"2021-01-01T20:39:28.000Z","size":194,"stargazers_count":622,"open_issues_count":9,"forks_count":25,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-04-30T00:02:24.506Z","etag":null,"topics":["clojure","defn-spec","instrument","spec"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jeaye.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-03-29T06:33:55.000Z","updated_at":"2025-04-28T02:07:29.000Z","dependencies_parsed_at":"2022-08-14T23:50:21.708Z","dependency_job_id":null,"html_url":"https://github.com/jeaye/orchestra","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeaye%2Forchestra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeaye%2Forchestra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeaye%2Forchestra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jeaye%2Forchestra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jeaye","download_url":"https://codeload.github.com/jeaye/orchestra/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252416506,"owners_count":21744448,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","defn-spec","instrument","spec"],"created_at":"2024-07-30T17:00:42.932Z","updated_at":"2025-05-15T12:05:23.551Z","avatar_url":"https://github.com/jeaye.png","language":"Clojure","funding_links":[],"categories":["Tests \u0026 Instrumentation","Libraries","Clojure","Data Validation"],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/jeaye/orchestra.svg?branch=master)](https://travis-ci.org/jeaye/orchestra) [![Clojars Project](https://img.shields.io/clojars/v/orchestra.svg)](https://clojars.org/orchestra)\n# Orchestra : complete instrumentation for clojure.spec\nOrchestra is a Clojure(Script) library made as a drop-in replacement for\n[clojure.spec.test.alpha](https://clojure.org/guides/spec), which provides custom\ninstrumentation that validates all aspects of function specs. By default,\nclojure.spec will only instrument `:args`. This leaves out `:ret` and `:fn`\nfrom automatic validation; Orchestra checks all of them for you.\n\n## Usage\nLeiningen dependency:\n\n```clojure\n;; Clojure requirements\n;;    org.clojure/clojure \u003e= 1.10.1\n;;\n;; ClojureScript requirements\n;;    org.clojure/clojurescript \u003e= 1.10.597\n[orchestra \"2021.01.01-1\"]\n```\n\nJust replace your `ns` and `require` forms to reference `orchestra.spec.test`\ninstead of `clojure.spec.test.alpha`. No further code changes required!\n\n```clojure\n;; Before\n(ns kitty-ninja\n  (:require [clojure.spec.test.alpha :as st]))\n\n;; Clojure: After\n(ns kitty-ninja\n  (:require [orchestra.core :refer [defn-spec]]\n            [orchestra.spec.test :as st]\n            [clojure.spec.alpha :as s]))\n\n;; ClojureScript: After\n(ns kitty-ninja\n  (:require [orchestra.core :refer-macros [defn-spec]]\n            [orchestra-cljs.spec.test :as st]\n            [clojure.spec.alpha :as s]))\n```\n\nJust as with vanilla Clojure, begin your instrumentation by calling:\n\n```clojure\n; Call after defining all of your specs\n(st/instrument)\n```\n\n## What it does\nIf you're not familiar with Clojure's instrumentation, it's worth reading the\nofficial [spec\nguide](https://clojure.org/guides/spec#_instrumentation_and_testing). In short,\nafter calling `orchestra.spec.test/instrument`, every call to a function which\nyou've spec'd will have its arguments, return value, and `:fn` spec validated,\nbased on the specs you've provided.\n\nThis magic is possible by rebinding the var, to which your spec'd functions are\nbound, with a different function which first checks all arguments, then calls\nthe original function, then checks the `:ret` and `:fn` specs, if they're\npresent.\n\n## When to use it\nI highly recommend having this **always on** during development and testing. You\nmay have systems tests, rather than unit tests, and this can help verify that\nyour data stays in the exact shape you intended.\n\n## defn-spec\nOrchestra also ships with a `defn-spec` macro for defining both functions and\ntheir specs together in a way which encourages having more specs. You can use it\nlike this:\n\n```clojure\n; Clojure\n(ns kitty-ninja\n  (:require [orchestra.core :refer [defn-spec]]))\n\n; ClojureScript\n(ns kitty-ninja\n  (:require [orchestra.core :refer-macros [defn-spec]]))\n\n; The return spec comes after the fn name.\n(defn-spec my-inc integer?\n  [a integer?] ; Each argument is followed by its spec.\n  (+ a 1))\n\n(defn-spec my-add integer?\n  [a integer?, b integer?] ; Commas can help visually group things.\n  (+ a b))\n\n; Doc strings work as expected.\n(defn-spec my-add integer?\n  \"Returns the sum of `a` and `b`.\"\n  [a integer?, b integer?]\n  (+ a b))\n\n; If a certain element doesn't have a spec, use any?\n(defn-spec get-meow any?\n  [meow-map (s/map-of keyword? any?)]\n  (:meow meow-map))\n\n; :fn specs can be specified using the fn's meta map.\n(defn-spec my-abs number?\n  {:fn #(= (:ret %) (-\u003e % :args :n))}\n  [n number?]\n  (Math/abs n))\n\n; Destructuring works nicely.\n(defn-spec add-a-b number?\n  [{:keys [a b]} (s/map-of keyword? number?)]\n  (+ a b))\n\n; Multiple arities are supported.\n(defn-spec sum number?\n  ([a number?]\n   a)\n  ; Varargs are also supported.\n  ([a number?, b number?, \u0026 args (s/* number?)]\n   (apply + a b args)))\n```\n\n### A note on defn-spec with multiple arities\nSince defn-spec allows for multiple arities, each one with arbitrary specs, some\nspecial handling needs to be done for handling how args are validated against\nthe right arity. For the most part, this is done entirely behind the scenes. The\none place it slips through is in `:fn` validation for multi-arity functions. In\nthis case, spec conforming will slightly change the input to the `:fn`\nvalidator and that needs to be handled. Here's an example.\n\n```clojure\n; A multi-arity function like this:\n(defn-spec arities number?\n  ([a number?]\n   (inc a))\n  ([a number?, b number?]\n   (+ a b))\n  ([a string?, b boolean?, c map?]\n   0))\n\n; Has an automatically-generated function spec of this:\n{:args (s/or :arity-1 (s/cat :a number?)\n             :arity-2 (s/cat :a number? :b number?)\n             :arity-3 (s/cat :a string? :b boolean? :c map?))\n :ret number?}\n\n; If we call (arities 2 2) then then :fn validator gets this:\n{:ret 4, :args [:arity-2 {:a 2, :b 2}]}\n\n; If we call (arities \"\" false {}) then the :fn validator gets this:\n{:ret 0, :args [:arity-3 {:a \"\", :b false, :c {}}]}\n```\n\nSo, the `:fn` validator needs to take note of possible arities it's handling and\nit can, for example, do a `case` on that value to validate differently for each\narity. Or just use `(-\u003e % :args second)` to ignore it and get to the args.\n\n## License\nDistributed under the Eclipse Public License version 1.0, just like Clojure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeaye%2Forchestra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjeaye%2Forchestra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjeaye%2Forchestra/lists"}