Skip to content

Commit 72290c2

Browse files
committed
Update README a bit
1 parent 6d38dea commit 72290c2

1 file changed

Lines changed: 116 additions & 35 deletions

File tree

README.md

Lines changed: 116 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@ or add the following to your `project.clj` ([Leiningen](https://leiningen.org/))
2424
```
2525
<!-- /installation -->
2626

27+
## Rationale
28+
29+
This is an opinionated CLI argument handling library. It is meant for command
30+
line tools with subcommands (for example git, which has `git commit`, `git log`
31+
and so forth). It tries to sticks to common conventions (in particular the
32+
prominent GNU conventions), uses a syntax that should feel natural to Clojure
33+
programmers (it's all just functions and data), and provides your tool with
34+
built-in help facilities automagically.
35+
36+
It is Babashka compatible, and in fact pairs really nicely with `bb` for making
37+
home-grown or general purpose tools.
38+
39+
This library helps you write [Well-behaved Command Line
40+
Tools](https://lambdaisland.com/blog/2020-07-28-well-behaved-command-line-tools)
41+
2742
## Getting Started
2843

2944
Here, we will explain how to use `com.lambdaisland/cli` to create a simple script that can print out the options it receives and handle basic help.
@@ -33,23 +48,24 @@ Here, we will explain how to use `com.lambdaisland/cli` to create a simple scrip
3348
Init the `bb.edn` with
3449

3550
```
36-
{:deps {com.lambdaisland/cli {:mvn/version "0.24.97"}}}
51+
{:deps {com.lambdaisland/cli {:mvn/version "0.24.97"}}}
3752
```
3853

3954
Create a file (e.g., `cli-test.bb`):
4055

4156
```
4257
#!/usr/bin/env bb
4358
44-
(require '[lambdaisland.cli :as cli]
45-
'[clojure.pprint :as pprint])
59+
(require
60+
'[lambdaisland.cli :as cli]
61+
'[clojure.pprint :as pprint])
4662
4763
;; 1. Define your main function.
4864
(defn cli-test
4965
"Ground breaking tool breaks new ground."
50-
[flags]
51-
(pprint/pprint flags))
52-
66+
[opts]
67+
(pprint/pprint opts))
68+
5369
;; 2. Dispatch the function (using its var).
5470
(cli/dispatch #'cli-test)
5571
```
@@ -69,29 +85,39 @@ By passing a function var (`#'cli-test`), the library automatically infers the n
6985

7086
### Step 2: Pass Arguments and Flags
7187

72-
Your command function receives all parsed input as a single map argument, conventionally named flags or opts.
73-
7488
Run it with some input
7589

7690
```
77-
$ bb cli-test.bb --abc hello world --format=txt
78-
{:lambdaisland.cli/sources {},
79-
:lambdaisland.cli/argv ["hello" "world"],
80-
:abc 1,
91+
$ bb cli-test.bb --abc -xxy hello --format=txt world
92+
{:lambdaisland.cli/argv ["hello" "world"]
93+
:abc 1
94+
:x 2
95+
:y 1
8196
:format "txt"}
8297
```
8398

84-
Flags beginning with `--` become map keys; remaining values are collected in `:lambdaisland.cli/argv`.
99+
Your command function receives all parsed input as a single map argument.
100+
Arguments starting with `-` or `--` are parsed as flags with some default
101+
conventions (you can change how they are handled by explicitly defining them).
102+
103+
- `--abc` — the value in the map is the number of times the flag, can be treated as a count or simply as a boolean
104+
- `-x` — also a count, but multiple one-letter flags can be passed at once when using a single dash, so `-xxy` is the same as `-x -x -y`
105+
- `--format=txt` — key-value, if the value looks like a number it is parsed as such
106+
- remaining values are collected in `:lambdaisland.cli/argv`.
85107

86108
### Step 3: Define Custom Flags
87109

88-
To gain control over how flags are parsed and to provide richer help text, we wrap the command var in a configuration map.
110+
To gain control over how flags are parsed and to provide richer help text, we
111+
wrap the command var in a configuration map. Note that `:flags` uses vector
112+
syntax, so you can specify the order they show up in the help, but it functions
113+
more like a map.
89114

90115
Modify your `cli-test.bb` to include a `:flags` configuration:
91116

92117
```
93118
(cli/dispatch
94-
{:command #'cli-test ; The function to call
119+
{:name "cli-test"
120+
:command #'cli-test ; The function to call
95121
:flags ["-v, --verbose" "Increases verbosity"
96122
"--input FILE" "Specify the input file"]})
97123
```
@@ -115,38 +141,93 @@ Run the tool with the new flags:
115141

116142
```
117143
$ bb cli-test.bb -vvv --input=world.txt
118-
{:lambdaisland.cli/sources
119-
{:verbose "-v command line flag", :input "--input command line flag"},
120-
:lambdaisland.cli/argv [],
144+
{:lambdaisland.cli/argv [],
121145
:verbose 3,
122146
:input "world.txt"}
123147
```
124148

125-
Multiple short flags like `-vvv` are counted automatically, producing `:verbose 3`.
149+
### Step 4. Flag options and subcommands
126150

127-
### Summary
151+
To give a hint of the full power of this library, we'll add a few subcommands,
152+
and change how the flags behave.
128153

129-
- Step 1: Start with a single command using `cli/dispatch`.
130-
- Step 2: Pass arguments and flags; everything becomes a map.
131-
- Step 3: Add `:flags` for option parsing and richer help.
154+
For this we replace the single `:command` with a set of `:commands`, using a
155+
`tool noun verb` structure that is a common convention.
132156

133-
You now have a solid foundation for building more advanced multi-command tools.
157+
Instead of just a string, we use a map to describe each flag, so we can set a
158+
default, change how it is parsed, or set the key that will show up in the
159+
options map passed to the command function.
134160

135-
## Rationale
161+
```clj
162+
(defn ls-widgets
163+
[opts]
164+
(println "Listing widgets")
165+
(pprint/pprint opts))
136166

137-
This is an opinionated CLI argument handling library. It is meant for command
138-
line tools with subcommands (for example git, which has `git commit`, `git log`
139-
and so forth). It works exactly how we like it, which mostly means it sticks to
140-
common conventions (in particular the prominent GNU conventions), needs little
141-
ceremony, and provides your tool with built-in help facilities automagically.
167+
(cli/dispatch
168+
{:name "cli-test"
169+
:commands ["widget"
170+
{:doc "Manipulate widgets"
171+
:commands
172+
["ls"
173+
{:doc "List widgets"
174+
:command ls-widgets}]}]
175+
:flags ["-v, --verbose" {:doc "Increases verbosity"
176+
:key :verbosity
177+
:default 0}
178+
"--format <fmt>" {:doc "Specify the format"
179+
:default "txt"
180+
:parse keyword}]})
181+
```
182+
183+
And try it out:
184+
185+
```
186+
$ cli-test widget ls --format=xxx -vvv
187+
Listing widgets
188+
{:verbosity 3
189+
:format :xxx
190+
:lambdaisland.cli/command ["widget" "ls"]
191+
:lambdaisland.cli/argv []}
192+
```
142193

143-
It is Babashka compatible, and in fact pairs really nicely with `bb` for making
144-
home-grown or general purpose tools.
194+
But note that this example can also be written using vars and docstrings, which
195+
makes it really neat. It also lets you put command specific flags in var
196+
metadata, like this:
145197

146-
It scales from extremely low ceremony basic scripts, to fairly complex setups.
198+
```clj
199+
(defn ls-widgets
200+
"List widgets"
201+
{:flags ["--[no-]disabled" "Include disabled widgets in the list"]}
202+
[opts]
203+
(println "Listing widgets")
204+
(pprint/pprint opts))
205+
206+
(def widget-cmds
207+
"Manipulate widgets"
208+
{:commands ["ls" #'ls-widgets]})
209+
210+
(def flags
211+
["-v, --verbose" {:doc "Increases verbosity"
212+
:key :verbosity
213+
:default 0}
214+
"--format <fmt>" {:doc "Specify the format"
215+
:default "txt"
216+
:parse keyword}])
147217

148-
This library helps you write [Well-behaved Command Line
149-
Tools](https://lambdaisland.com/blog/2020-07-28-well-behaved-command-line-tools)
218+
(cli/dispatch
219+
{:name "cli-test"
220+
:commands ["widget" #'widget-cmds]
221+
:flags flags})
222+
```
223+
224+
### Summary
225+
226+
- Step 1: Start with a single command using `cli/dispatch`.
227+
- Step 2: Pass arguments and flags; everything becomes a map.
228+
- Step 3: Add `:flags` for option parsing and richer help.
229+
230+
You now have a solid foundation for building more advanced multi-command tools.
150231

151232
## How-to Guides
152233

0 commit comments

Comments
 (0)