Liking cljdoc? Tell your friends :D

CLI-matic

Compact [sub]command line parsing library, for Clojure. Perfect for scripting (who said Clojure is not good for scripting?).

Using

The library is available on Clojars:

Clojars Project

Or the library can be easily referenced through Github:

{:deps
 {cli-matic
  {:git/url "https://github.com/l3nz/cli-matic.git"
   :sha "5252413d1cacd9d3db90019fdd059893167c73db"}}}

Rationale

Say we want to create a short script, in Clojure, where we want to run a very simple calculator that either sums A to B or subtracts B from A:

$ clj -m calc add -a 40 -b 2
42
$ clj -m calc sub -a 10 -b 2
8
$ clj -m calc --base 16 add -a 30 -b 2
20

We also want it to display its help:

$clj -m calc -?
NAME:
 toycalc - A command-line toy calculator

USAGE:
 toycalc [global-options] command [command options] [arguments...]

VERSION:
 0.0.1

COMMANDS:
   add, a   Adds two numbers together
   sub, s   Subtracts parameter B from A

GLOBAL OPTIONS:
       --base N  10  The number base for output
   -?, --help

And help for sub-commands:

$clj -m calc add -?
NAME:
 toycalc add - Adds two numbers together

USAGE:
 toycalc [add|a] [command options] [arguments...]

OPTIONS:
   -a, --a1 N  0  Addendum 1
   -b, --a2 N  0  Addendum 2
   -?, --help

But while we are coding this, we do not realy want to waste time writing any parsing logic. What we care about implementing are the functions "add-numbers" and "sub-numbers"; the rest should just be declared externally and/or "just happen".

From the point of view of us programmers, we'd like to have a couple of functions like:

(defn add-number
	"Sums A and B together, and prints it in base `base`"
	[{:keys [a b base]}]
	(Integer/toString (+ a b) base))

And nothing more; the fact that both parameters exist, are of the right type, have the right defaults, print the correct help screen, etc., should ideally not be a concern.

(def CONFIGURATION
  {:app         {:command     "toycalc"
                 :description "A command-line toy calculator"
                 :version     "0.0.1"}

   :global-opts [{:option  "base"
                  :as      "The number base for output"
                  :type    :int
                  :default 10}]

   :commands    [{:command     "add"
                  :description "Adds two numbers together"
                  :opts        [{:option "a" :as "Addendum 1" :type :int}
                                {:option "b" :as "Addendum 2" :type :int :default 0}]
                  :runs        add_numbers}

                 {:command     "sub"
                  :description "Subtracts parameter B from A"
                  :opts        [{:option "a" :as "Parameter A" :type :int :default 0}
                                {:option "b" :as "Parameter B" :type :int :default 0}]
                  :runs        subtract_numbers}
                 ]})

Current pre-sets

The following pre-sets (:type) are available:

  • :int - an integer number
  • :int-0 - an integer number, with defaults to zero
  • :float - a float number
  • :float-0 - a float number, with defaults to zero
  • :string - a string
  • :json - a JSON literal value, that will be decoded an returned as a Clojure structure.
  • :yyyy-mm-dd - a Date object, expressed as "yyyy-mm-dd" in the local time zone
  • :slurp - Receives a file name - reads is as text and returns it as a single string. Handles URIs correctly.
  • :slurplines - Receives a file name - reads is as text and returns it as a seq of strings. Handles URIs correctly.
  • :jsonfile - a file (or URL) containing JSON, that will be decoded and returned as a Clojure structure.

For all options, you can then add:

  • :default the default value, as expected after conversion. If no default, the value will be passed only if present. If you set :default :present this means that Cli-matic will abort if that option is not present (and it appears with a trailing asterisk in the help)
  • :multiple if true, the values for all options with the same name are stored in an array
  • short: a short version of the command, or a positional argument (see below)

[to be done]

  • boolean types
  • having a library of ready-made types that cover most cases
  • using spec for checking values
  • :env if set, the default is taken from the current value of an envirnoment variable

Return values

The function called can return an integer; if it does, it is used as an exit code for the shell process.

Errors and exceptions return an exit code of -1; while normal executions (including invocations of help) return 0.

Positional arguments

CLI-matic will usually just return an array of unparsed entries, as strings. If you use the syntax:

{:option "a1" :short 0 :as "First addendum" :type :int :default 23}

You 'bind' the option 'a1' to the first unparsed element; this means that you can apply all presets/defaults/validation rules as if it was a named option.

The named option stays, so you can use either version. Bound entries are not removed from the unparsed command line entries.

Transitive dependencies

cli-matic currently depends on:

  • org.clojure/clojure
  • org.clojure/spec.alpha
  • org.clojure/tools.cli
  • orchestra

To use Json decoding, you need Cheshire to be on the classpath; otherwise it will break.

License

The use and distribution terms for this software are covered by the Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can be found in the file epl.html at the root of this distribution. By using this software in any fashion, you are agreeing to be bound by the terms of this license.

You must not remove this notice, or any other, from this software.

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close