Skip to content

Instantly share code, notes, and snippets.

@mwmitchell
Created March 24, 2012 21:07
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 mwmitchell/2187881 to your computer and use it in GitHub Desktop.
Save mwmitchell/2187881 to your computer and use it in GitHub Desktop.
defrecord+
;; Provides the ability to use :pre and :or options to defrecord via a constructor function.
;; The constructor function is named new-X, where X is the name passed into (defrecord+ X ...)
(defmacro defrecord+
[name fields & etc]
(let [[[{:as opts}] etc]
(if (map? (first etc))
(split-at 1 etc)
[nil etc])
defaults
(into {}
(for [[k v] (:or opts)]
[(keyword k) v]))
kws (map (comp keyword) fields)
b-name (symbol (str "base-" name))
new-name (symbol (str "new-" name))]
`(do
(defrecord ~name ~fields ~@etc)
(def ~b-name (~(symbol (str name \.))
~@((apply juxt kws) defaults)))
(defn ~new-name
[& {:keys [~@fields]
:as ~(symbol "d")
:or ~(:or opts)}]
{:pre ~(:pre opts)}
(merge ~b-name ~(symbol 'd))))))
(defprotocol BRead
(read [this]))
(do
(defrecord+ Book [author title]
{:pre [(string? title)]
:or {author "n/a" title "n/a"}}
BRead
(read [this]
(str "Reading " (:title this) ", by " (:author this))))
(read (new-Book :author "F. Scott Fitzgerald" :title "THE GREAT GATSBY")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment