7 Commits
0.0.1 ... 0.0.4

Author SHA1 Message Date
10ba753ee3 cli: better to-map 2020-01-31 10:43:42 +01:00
0b185aa3b9 cli: add morphers 2020-01-30 16:43:58 +01:00
b5eb3a917b cli: fix memerror in usage 2020-01-30 16:01:11 +01:00
cb5c9f0bfe docs: fix typos 2020-01-29 21:13:13 +01:00
7bd0817c27 update docs 2020-01-29 21:09:48 +01:00
493d0016d5 vbump 2020-01-29 21:08:47 +01:00
aaf413ac04 cli: fix printing of types and do not override previous errors 2020-01-29 21:07:31 +01:00
3 changed files with 98 additions and 37 deletions

View File

@@ -3,7 +3,7 @@
A simple CLI library for Carp.
```clojure
(load "https://veitheller.de/git/carpentry/cli@master")
(load "https://veitheller.de/git/carpentry/cli@0.0.2")
(defn main []
(let [p (=> (CLI.new @"My super cool tool!")
@@ -18,7 +18,7 @@ A simple CLI library for Carp.
## Installation
```clojure
(load "https://veitheller.de/git/carpentry/cli@master")
(load "https://veitheller.de/git/carpentry/cli@0.0.2")
```
## Usage

View File

@@ -6,7 +6,7 @@
(doc CLI "is a simple CLI library for Carp.
```clojure
(load \"https://veitheller.de/git/carpentry/cli@0.0.1\")
(load \"https://veitheller.de/git/carpentry/cli@0.0.2\")
(defn main []
(let [p (=> (CLI.new @\"My super cool tool!\")
@@ -21,7 +21,7 @@
## Installation
```clojure
(load \"https://veitheller.de/git/carpentry/cli@0.0.1\")
(load \"https://veitheller.de/git/carpentry/cli@0.0.2\")
```
## Usage
@@ -46,8 +46,8 @@ manually.
Once youre done building your flag structure, you can run `CLI.parse`. It
will not abort the program on error, instead it will tell you what went wrong
in a `Result.Error`. If it succeeds, the `Result.Success` contains a `Map` from
the long flag name to the value (the values are `Maybe`s, since they might be
optional arguments.")
the long flag name to the value. The values are not in the map if they are
unset.")
(defmodule CLI
(hidden Type)
(private Type)
@@ -55,11 +55,16 @@ optional arguments.")
(Integer [Long])
(Floating [Double])
(Str [String])
(None [])
)
(defmodule Type
(defn = [a b]
(match @a
(None)
(match @b
(None) true
_ false)
(Integer i)
(match @b
(Integer j) (= i j)
@@ -78,6 +83,39 @@ optional arguments.")
(Integer i) (Long.format s i)
(Floating f) (Double.format s f)
(Str s2) (String.format s &s2)))
(defn str [t]
(match @t
(Integer i) (str i)
(Floating f) (str f)
(Str s) (str s)))
(defn to-int [x]
(match x
(Integer l) (Long.to-int l)
_ 0))
(defn to-long [x]
(match x
(Integer l) l
_ 0l))
(defn to-str [x]
(match x
(Str s) s
_ @""))
(defn to-float [x]
(match x
(Floating d) (Double.to-float d)
_ 0.0f))
(defn to-double [x]
(match x
(Floating d) d
_ 0.0))
(defn zero [] (None))
)
(hidden Tag)
@@ -97,7 +135,7 @@ optional arguments.")
)
(doc Option "is the option type. To construct an `Option`, please use
[`int`](#int), [`float`](#float), or [`str](#str).")
[`int`](#int), [`float`](#float), or [`str`](#str).")
(deftype Option [
type- Tag
long String
@@ -109,7 +147,7 @@ optional arguments.")
])
(doc Parser "is the parser type. To construct a `Parser`, please use
[`new](#new).")
[`new`](#new).")
(deftype Parser [
description String
options (Array Option)
@@ -197,7 +235,10 @@ optional arguments.")
(defn to-map [m]
(Array.reduce
&(fn [a v] (Map.put a (Pair.a (Pair.a v)) (Pair.b (Pair.b v))))
&(fn [a v]
(match @(Pair.b (Pair.b v))
(Maybe.Just e) (Map.put a (Pair.a (Pair.a v)) &e)
(Maybe.Nothing) a))
{}
(values m)))
)
@@ -265,7 +306,7 @@ optional arguments.")
(Option.long arg) (Option.short arg) (Option.description arg)))
(when @(Option.required? arg) (IO.print " REQUIRED"))
(when (Maybe.just? (Option.default arg))
(IO.print &(fmt " (default: %s)" &(Maybe.unsafe-from @(Option.default arg)))))
(IO.print &(fmt " (default: %s)" &(str &(Maybe.unsafe-from @(Option.default arg))))))
(match @(Option.options arg)
(Maybe.Just o)
(IO.print &(fmt " (options: %s)" &(join ", " &(Array.copy-map &str &o))))
@@ -309,26 +350,27 @@ mesage is empty, `--help` was requested. If you dont want to provide a
(do
(set! res (Result.Error (fmt "Unexpected argument: %s" x)))
(break)))))
(foreach [o options]
(cond
(and @(Option.required? o)
(not (CmdMap.set? &values (Option.long o))))
(do
(set! res (Result.Error (fmt "Required option missing: --%s" (Option.long o))))
(break))
(Maybe.just? (Option.options o))
(let-do [opts (Maybe.unsafe-from @(Option.options o))]
(when (not (CmdMap.in? &values (Option.long o) &opts))
(do
(set! res
(Result.Error
(fmt
"Option %s received an invalid option %s (Options are %s)"
(Option.long o)
&(CmdMap.get &values (Option.long o))
&(join ", " &(Array.copy-map &str &opts)))))
(break))))
()))
(when (Result.success? &res)
(foreach [o options]
(cond
(and @(Option.required? o)
(not (CmdMap.set? &values (Option.long o))))
(do
(set! res (Result.Error (fmt "Required option missing: --%s" (Option.long o))))
(break))
(Maybe.just? (Option.options o))
(let-do [opts (Maybe.unsafe-from @(Option.options o))]
(when (not (CmdMap.in? &values (Option.long o) &opts))
(do
(set! res
(Result.Error
(fmt
"Option %s received an invalid option %s (Options are %s)"
(Option.long o)
&(CmdMap.get &values (Option.long o))
&(join ", " &(Array.copy-map &str &opts)))))
(break))))
())))
(match res
(Result.Success _) (Result.Success (CmdMap.to-map &values))
(Result.Error x) (Result.Error x))))

View File

@@ -30,7 +30,7 @@
</h1>
<div class="module-description">
<p>is a simple CLI library for Carp.</p>
<pre><code class="language-clojure">(load &quot;https://veitheller.de/git/carpentry/cli@0.0.1&quot;)
<pre><code class="language-clojure">(load &quot;https://veitheller.de/git/carpentry/cli@0.0.2&quot;)
(defn main []
(let [p (=&gt; (CLI.new @&quot;My super cool tool!&quot;)
@@ -42,7 +42,7 @@
(Result.Error msg) (do (IO.errorln &amp;msg) (CLI.usage &amp;p)))))
</code></pre>
<h2>Installation</h2>
<pre><code class="language-clojure">(load &quot;https://veitheller.de/git/carpentry/cli@0.0.1&quot;)
<pre><code class="language-clojure">(load &quot;https://veitheller.de/git/carpentry/cli@0.0.2&quot;)
</code></pre>
<h2>Usage</h2>
<p><code>CLI</code> should be built using combinators, as in the example above. It has, as of
@@ -61,10 +61,29 @@ manually.</p>
<p>Once youre done building your flag structure, you can run <code>CLI.parse</code>. It
will not abort the program on error, instead it will tell you what went wrong
in a <code>Result.Error</code>. If it succeeds, the <code>Result.Success</code> contains a <code>Map</code> from
the long flag name to the value (the values are <code>Maybe</code>s, since they might be
optional arguments.</p>
the long flag name to the value. The values are not in the map if they are
unset.</p>
</div>
<div class="binder">
<a class="anchor" href="#(defdynamic CLI.*gensym-counter* 1001)">
<h3 id="(defdynamic CLI.*gensym-counter* 1001)">
(defdynamic CLI.*gensym-counter* 1001)
</h3>
</a>
<div class="description">
dynamic
</div>
<p class="sig">
Dynamic
</p>
<span>
</span>
<p class="doc">
</p>
</div>
<div class="binder">
<a class="anchor" href="#Option">
<h3 id="Option">
@@ -82,7 +101,7 @@ optional arguments.</p>
</span>
<p class="doc">
<p>is the option type. To construct an <code>Option</code>, please use
<a href="#int"><code>int</code></a>, <a href="#float"><code>float</code></a>, or <a href="#str">`str</a>.</p>
<a href="#int"><code>int</code></a>, <a href="#float"><code>float</code></a>, or <a href="#str"><code>str</code></a>.</p>
</p>
</div>
@@ -103,7 +122,7 @@ optional arguments.</p>
</span>
<p class="doc">
<p>is the parser type. To construct a <code>Parser</code>, please use
<a href="#new">`new</a>.</p>
<a href="#new"><code>new</code></a>.</p>
</p>
</div>
@@ -197,7 +216,7 @@ optional arguments.</p>
defn
</div>
<p class="sig">
(λ [(Ref Parser)] (Result (Map String (Maybe Type)) String))
(λ [(Ref Parser)] (Result (Map String Type) String))
</p>
<pre class="args">
(parse p)