-
Notifications
You must be signed in to change notification settings - Fork 3
/
optionsblock.clj
35 lines (32 loc) · 1.57 KB
/
optionsblock.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(ns docopt.optionsblock
(:require [clojure.string :as s]
[docopt.util :refer [err re-arg-str tokenize]]))
(defn tokenize-option
"Generates a sequence of tokens for an option specification string."
[string]
(tokenize string [[#"\s{2,}(?s).*\[(?i)default(?-i):\s*([^\]]+).*" :default]
[#"\s{2,}(?s).*"]
[#"(?:^|\s+),?\s*-([^-,])" :short]
[#"(?:^|\s+),?\s*--([^ \t=,]+)" :long]
[(re-pattern re-arg-str) :arg]
[#"\s*[=,]?\s*"]]))
(defn parse-option
"Parses option description line into associative map."
[option-line]
(let [tokens (tokenize-option option-line)]
(err (seq (filter string? tokens)) :syntax
"Badly-formed option definition: '" (s/replace option-line #"\s\s.*" "") "'.")
(let [{:keys [short long arg default]} (reduce conj {} tokens)
[value & more-values] (filter seq (s/split (or default "") #"\s+"))]
(into (if arg
{:takes-arg true :default-value (if (seq more-values) (into [value] more-values) value)}
{:takes-arg false})
(filter val {:short short :long long})))))
(defn parse
"Parses options lines."
[options-lines]
(let [options (map parse-option options-lines)]
(err (not (and (distinct? (filter identity (map :long options)))
(distinct? (filter identity (map :short options)))))
:syntax "In options descriptions, at least one option defined more than once.")
(into #{} options)))