Last active
June 29, 2020 12:55
-
-
Save JohnnyJayJay/3a367973b289dcc9ba00417812f72b71 to your computer and use it in GitHub Desktop.
A simple and generic command handler for clojure apps using core.match pattern matching.
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
| (ns commands.core | |
| (:require [clojure.string :refer [split]] | |
| [clojure.core.match :refer [match]])) | |
| (defmacro defcommand | |
| "Defines a command function that takes a context argument and any number of additional arguments. | |
| If the `name` symbol does not have explicit label metadata attached to it, the name of the symbol will be used as the label. | |
| The `context-binding` can be any valid `let` binding form. It will be bound to the context argument at execution time. | |
| The `patterns` are a variable number of [[clojure.core.match/match]] matching forms that represent the different arguments that | |
| can be passed to this command." | |
| [name context-binding & patterns] | |
| `(defn ~(if (contains? (meta name) :label) | |
| name | |
| (vary-meta name assoc :label (clojure.core/name name))) | |
| [~context-binding & args#] | |
| (match (vec args#) ~@patterns))) | |
| (defn commands | |
| "Creates a map of label -> command based on the inputted command function vars." | |
| [& commands] | |
| (zipmap (map :label (map meta commands)) commands)) | |
| (defn dispatch | |
| "Finds and dispatches the correct command based on the given command map and input. | |
| Throws an [[IllegalArgumentException]] if no matching command could be found." | |
| [commands context input] | |
| (let [[label & args] (split input #"\s+")] | |
| (if-let [command (get commands label)] | |
| (-> command var-get (apply context args)) | |
| (throw (IllegalArgumentException. (str "No matching command found for label " label)))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment