Skip to content

Instantly share code, notes, and snippets.

@madstap
Last active November 22, 2017 16:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save madstap/ae2ced5f049d73c27e138bbf6bf07b64 to your computer and use it in GitHub Desktop.
Save madstap/ae2ced5f049d73c27e138bbf6bf07b64 to your computer and use it in GitHub Desktop.
(ns bank.account
(:require
[clojure.spec.alpha :as s]))
(s/def ::fname string?)
(s/def ::lname string?)
(s/def ::cents integer?)
;; It's currently valid to have a negative balance.
;; Could alternatively do something like (s/and ::cents (complement neg?))
(s/def ::balance ::cents)
;; maybe use an inst here?
(s/def ::date-of-birth string?)
;; The first name is optional, the others are required.
(s/def ::account
(s/keys :req [::lname ::balance ::date-of-birth]
:opt [::fname]))
(s/fdef deposit
:args (s/cat :account ::account, :quantity ::cents)
:ret ::account)
;; This is the implementation I would use regardless of whether I used spec or not.
(defn deposit [account quantity]
(update account ::balance + quantity))
(s/fdef withdraw-valid?
:args (s/cat :account ::account, :quantity ::cents)
:ret boolean?)
(defn withdraw-valid? [{::keys [balance] :as account} quantity]
(>= balance quantity))
(s/fdef withdraw
:args (s/cat :account ::account, :quantity ::cents)
:ret ::account)
(defn withdraw [account quantity]
(update account ::balance - quantity))
(comment
;; Usage
(def me #::{:lname "madstap"
:balance 100
:date-of-birth "01-01-17"})
(withdraw me 100) ;=> #:bank.account{,,, :balance 0 ,,,}
(deposit me 1000) ;=> ;=> #:bank.account{,,, :balance 1100 ,,,}
(withdraw-valid? me 1000) ;=> false
;; Bonus: Generate random, valid bank accounts.
;; NB: Needs test.check as a dependency [org.clojure/test.check "0.10.0-alpha2"]
(clojure.pprint/pprint (s/exercise ::account))
([#:bank.account{:lname "", :balance -1, :date-of-birth "", :fname ""}
#:bank.account{:lname "", :balance -1, :date-of-birth "", :fname ""}]
[#:bank.account{:lname "", :balance 0, :date-of-birth "6", :fname ""}
#:bank.account{:lname "", :balance 0, :date-of-birth "6", :fname ""}]
,,,)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment