{"id":17244839,"url":"https://github.com/hlship/multi","last_synced_at":"2026-02-09T01:34:17.888Z","repository":{"id":66810325,"uuid":"225439487","full_name":"hlship/multi","owner":"hlship","description":"Joker library to support tools with multiple embedded commands","archived":false,"fork":false,"pushed_at":"2020-02-25T00:31:53.000Z","size":36,"stargazers_count":6,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-27T23:44:22.463Z","etag":null,"topics":["cli","joker"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hlship.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-02T18:14:45.000Z","updated_at":"2021-03-17T09:10:54.000Z","dependencies_parsed_at":"2023-02-24T23:46:18.123Z","dependency_job_id":null,"html_url":"https://github.com/hlship/multi","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/hlship/multi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlship%2Fmulti","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlship%2Fmulti/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlship%2Fmulti/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlship%2Fmulti/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hlship","download_url":"https://codeload.github.com/hlship/multi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hlship%2Fmulti/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29252979,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T22:49:53.206Z","status":"ssl_error","status_checked_at":"2026-02-08T22:49:51.384Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","joker"],"created_at":"2024-10-15T06:27:42.509Z","updated_at":"2026-02-09T01:34:17.874Z","avatar_url":"https://github.com/hlship.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# multi\n\n`net.lewisship.multi` is a complement to joker.tools.cli that allows a single tool, a Joker script, to \ncontain multiple commands, each with its own command line options and arguments.\n\nAt the core is the `net.lewisship.multi/dispatch` macro; this identifies the name of the tool, and \noptionally, the namespaces to collect commands from.\n\nEach command within the tool is provided via the `net.lewisship.multi/defcommand` macro.\n\nA command option, `-h / --help`, is added to all commands automatically.\n\nA `help` command is also added; it displays the list of commands available.\nThe help command displays the first line of each command's docstring, as a summary\nof the command.\n\nThe `help` command displays a short summary of what the overall tool does; this is the docstring\nof the first namespace provided to `dispatch` (again, if omitted, the current namespace\nis used).\n\nWhereas command option parsing is driven by the option names, command argument\nparsing is positional. Each command option spec will consume one command line argument\n(exception: the last spec may be repeatable).\n\ncommand argument specs are similar to command option specs; each spec is a vector that starts\nwith one or two strings; the first string is always the label (by convention,\nin upper case). The optional second string is the documentation of the argument.\n\nFollowing that are key/value pairs:\n\n* `:id` (keyword) - identifies which key is used in the arguments map; by default,\nthis is the label converted to a lower case keyword\n\n* `:doc` (string) - documentation for the argument\n\n* `:optional` (boolean) -- if true, the argument may be omitted if there isn't a\n    command line argument to match\n\n* `:repeatable` (boolean) -- if true, then any remaining command line arguments are processed\nby the argument\n\n* `:parse-fn` - passed the command line argument, returns a value, or throws an exception\n\n* `:validate` - a vector of function/message pairs\n\n* `:update-fn` - optional function used to update the (initially nil) entry for the argument in the :arguments map\n \n* `:assoc-fn` - optional function used to update the arguments map; passed the map, the id, and the parsed value\n\n* `:update-fn` and `:assoc-fn` are mutually exclusive.\n\nFor repeatable arguments, the default update function will construct a vector of values.\nFor non-repeatable arguments, the default update function simply sets the value.\n\n# Using multi\n\n```\n#!/usr/bin/env joker\n\n(ns-sources\n  {\"net.lewisship.multi\" {:url \"https://raw.githubusercontent.com/hlship/multi/v1.4.0/src/net/lewisship/multi.joke\"}})\n\n(ns example\n  \"System management tool\"\n  (:require [net.lewisship.multi :as multi]))\n\n(multi/defcommand configure\n  \"Configures the system with keys and values\"\n  [verbose [\"-v\" \"--verbose\" \"Enable verbose logging\"]\n   :args\n   host [\"HOST\" \"System configuration URL\"\n         :validate [#(re-matches #\"https?://.+\" %) \"must be a URL\"]]\n   key-values [\"DATA\" \"Data to configure as KEY=VALUE\"\n               :parse-fn (fn [s]\n                           (when-let [[_ k v] (re-matches #\"(.+)=(.+)\" s)]\n                             [(keyword k) v]))\n               :update-fn (fn [m [k v]]\n                            (assoc m k v))\n               :repeatable true]]\n  (prn :verbose verbose :host host :key-values key-values)\n\n;; Execution:\n\n(multi/dispatch {:tool-name \"example\"]})\n```\nIf this file is saved as `bin/example`, it can be executed directly:\n\n```\n\u003e bin/example configure --help\nUsage: example configure [OPTIONS] HOST DATA+\n\nConfigures the system with keys and values\n\nOptions:\n  -v, --verbose  Enable verbose logging\n  -h, --help     This command summary\n\n\nArguments:\n  HOST: System configuration URL\n  DATA: Data to configure as KEY=VALUE\n\n\u003e bin/example configure http://localhost:9983 retries=3 alerts=on -v\n:verbose true :host \"http://localhost:9983\" :key-values {:retries \"3\", :alerts \"on\"}\n```\n\nNotes:\n* With `defcommand` a docstring is required\n* After the docstring comes the _interface_, which defines options and arguments\n* The interface initially expects to consume a symbol then an option spec\n* The `:args` keyword switches over to consuming symbol and argument spec\n\nThe `dispatch` macro normally searches for `defcommand`s in the same namespace, but this can be\noverridden by providing a list of namespace symbols as the `:namespaces` option.\n\nTool documentation comes from the docstring of the first namespace.\n\n## defcommand extras\n\n## :as \\\u003csymbol\\\u003e\n\nInside the interface, you can request the _command map_ using `:as`.\nThis command map is used when invoking `net.lewisship.multi/show-summary`, \nwhich a command may wish to do to present errors to the user.\n\n### :command-name \\\u003cstring\\\u003e\n\nYou may also override the command name away from its default (the name of the function).\n\nFor example, if you had an existing `configure` function you didn't want to rename, \nthen you could name the command function `configure-command`:\n\n```\n(multi/defcommand configure-command\n  \"Configures the system with keys and values\"\n  [verbose [\"-v\" \"--verbose\" \"Enable verbose logging\"]\n   :args\n   host [\"HOST\" \"System configuration URL\"\n         :validate [#(re-matches #\"https?://.+\" %) \"must be a URL\"]]\n   key-values [\"DATA\" \"Data to configure as KEY=VALUE\"\n               :parse-fn (fn [s]\n                           (when-let [[_ k v] (re-matches #\"(.+)=(.+)\" s)]\n                             [(keyword k) v]))\n               :update-fn (fn [m [k v]]\n                            (assoc m k v))\n               :repeatable true]\n   :command-name \"configure\"]\n  ...)\n```\n\n### Meta Data\n\nFinally, you can specify additional meta data for the command by applying\nit to the command's symbol.  For example:\n\n```\n(multi/defcommand ^{:command-name \"conf\"} configure\n  ...\n```\n\n  ... though there's rarely a need to ever do this.\n\n# Function Metadata\n\nThe `defcommand` macro works by adding the following meta-data to the Var it creates:\n\n* `:command` (boolean) -- indicates the function is a command \n\n* `:command-name` (string, optional) -- overrides the name of the command, normally the symbol\n\n* `:doc` (string) -- the command's docstring is the command description, used when printing help\n\n* `:command-opts` - a list of option specs, passed to joker.tools.cli/parse-opts\n\n* `:command-args` - a list of positional argument specs \n\nThe command function is ultimately passed the command map containing two sub-maps:\nThe :options map contains the command options, and the :arguments\nmap contains a map of processed command line arguments;\n`defcommand` adds a `let` to pull values out of the command map and into the \noption and argument symbols you define in the interface.\n\nOther keys within the command map are private, used by multi.\n\nAgain, `defcommand` is the preferred way to define commands.\n\n## License\n\n`multi` is (c) 2019-present Howard M. Lewis Ship.\n\nIt is released under the terms of the Apache Software License, 2.0.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhlship%2Fmulti","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhlship%2Fmulti","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhlship%2Fmulti/lists"}