Last active
April 3, 2017 10:24
-
-
Save markomanninen/80011c906e17c1bfdb660c8d3d5c9186 to your computer and use it in GitHub Desktop.
extract-keywords-and-expressions from Hy macro
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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