Specifications for function definitions

A function specification can contain a specification for the arguments, the return values and the relationship between the two.

The specifications for the function may be composed from previously defined data specifications.

Function definitions

The card game application has three functions to start with.

(defn regulation-card-deck
  "Generate a complete deck of playing cards"
  [{:keys [::deck ::players] :as game}]
  (apply + (count deck)
         (map #(-> % ::delt-hand count) players)))

At the start of function design, the algorithm may still be undefined. Using the specifications and generators mock data can be returned as a placeholder.

(defn deal-cards
  "Deal cards to each of the players
   Returns updated game hash-map"
  [game]
  (spec-gen/generate (spec/gen ::game)))
(defn winning-player
  "Calculate winning hand by comparing each players hand
  Return winning player"
  [players]
  (spec-gen/generate (spec/gen ::player)))

Function specification

(spec/fdef deal-cards
  :args (spec/cat :game ::game)
  :ret ::game
  :fn #(= (regulation-card-deck (-> % :args :game))
          (regulation-card-deck (-> % :ret))))
(spec/fdef winning-player
  :args (spec/cat :players ::players)
  :ret ::player)

Instrument functions

Instrumenting functions will wrap a function definition and check the arguments of any call to the instrumented function.

(spec-test/instrument `deal-cards)

Ignore the Warning message in the result, this is an issue with the REPL implementation used in this page.

Calling the deal-cards function with an incorrect argument returns an error that describes where in the specification the error occurred.

(deal-cards "fake game data")

Error in an easier to read format

ERROR: #error
 {:message "Call to #'practicalli.card-game/deal-cards did not conform to spec:\n\
 "fake game data\" - failed:
 map? in: [0] at: [:args :game] spec: :practicalli.card-game/game\n",
 :data {:cljs.spec.alpha/problems
 [{:path [:args :game],
   :pred cljs.core/map?,
   :val "fake game data",
   :via [:practicalli.card-game/game :practicalli.card-game/game],
   :in [0]}],
 :cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha17968],
 :cljs.spec.alpha/value ("fake game data"),
 :cljs.spec.alpha/args ("fake game data"),
 :cljs.spec.alpha/failure :instrument}}

results matching ""

    No results matching ""