Skip to content

Instantly share code, notes, and snippets.

@markomanninen
Last active April 3, 2017 10:24
Show Gist options
  • Save markomanninen/80011c906e17c1bfdb660c8d3d5c9186 to your computer and use it in GitHub Desktop.
Save markomanninen/80011c906e17c1bfdb660c8d3d5c9186 to your computer and use it in GitHub Desktop.
extract-keywords-and-expressions from Hy macro
(defclass MyApp [object]
(defn --init-- [self &kwargs args]
(setv self.routes {}))
(defn route [self route-str &kwargs args]
(fn [f]
(do (assoc self.routes route-str f)
f))))
(setv app (MyApp))
(eval-and-compile
; detach keywords and content from code expression
(defn extract-keywords-and-expressions [code]
(setv content [] attributes {} kwd None)
(for [item code]
(do ; should we add item to content / attributes list
(if-not (keyword? item)
(if (none? kwd)
; keyword was not set, so item must be a content
(.append content item)
; otherwise it is attribute
(assoc attributes kwd item)))
; should we regard next item as a value of the keyword?
(if (keyword? item) (setv kwd item) (setv kwd None))))
(, content attributes)))
(defmacro route-decorator [path methods defaults func]
`(with-decorator
(apply app.route [~path] {"methods" ~methods "defaults" ~defaults})
~func))
; recursive route decorator for multiple paths
(defmacro route* [paths defaults methods func]
(if (and (coll? paths) (> (len paths) 1))
`(route-decorator ~(name (first paths)) ~methods ~defaults
(route* ~(list (drop 1 paths)) ~defaults ~methods ~func))
(do (setv paths (name (if (coll? paths) (first paths) paths)))
`(route-decorator ~paths ~methods ~defaults ~func))))
(defmacro route [methods paths &rest code]
(setv (, content keywords) (extract-keywords-and-expressions code))
(if-not (in :defaults keywords) (assoc keywords :defaults {}))
(if-not (in :params keywords) (assoc keywords :params []))
`(route* ~paths ~(get keywords :defaults) ~(.split methods "/")
~(if (in :name keywords)
`(defn ~(get keywords :name) ~(get keywords :params) ~@content)
`(fn ~(get keywords :params) ~@content))))
(route GET/POST [/ /index] :name index (print 1))
(index)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment