strop 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +8 -4
- data/lib/strop/version.rb +1 -1
- data/lib/strop.rb +23 -9
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 225cf6a25d9576df114857aab9e157c4f9d2c666f74e066bd21fc012b9a8f83d
|
|
4
|
+
data.tar.gz: 2dfc769e16d1dff9db71788250fedeb23973a46fc2e86633bda69d03b3afef5c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57a71386c4e906a3b444da5dabb81a145faef6795639e420917f20386ee75d7c4e8a1442c398ea72db413ee363f5b284ebee113b0e3875b14867c331968c8a99
|
|
7
|
+
data.tar.gz: a77e623a861b637d2c01e955bf984d556fdd54d4b3c8f9896d22ac8b346fb370702eb04053a1c1a922de51a050e5627e5429ecc1c568bb21f650cf28c7e8f4e5
|
data/README.md
CHANGED
|
@@ -58,10 +58,11 @@ puts Strop.parse_help(help_text).to_s(:case)
|
|
|
58
58
|
## Result members (Array of Opt, Arg, Sep)
|
|
59
59
|
|
|
60
60
|
```ruby
|
|
61
|
-
res.opts
|
|
62
|
-
res.args
|
|
63
|
-
res.rest
|
|
64
|
-
res["flag"]
|
|
61
|
+
res.opts # all Opt objects
|
|
62
|
+
res.args # all Arg objects
|
|
63
|
+
res.rest # args after -- separator
|
|
64
|
+
res["flag"] # find opt by name
|
|
65
|
+
res[["flag"]] # find all opts matching name
|
|
65
66
|
|
|
66
67
|
opt = res.opts.first
|
|
67
68
|
arg = res.args.first
|
|
@@ -73,6 +74,7 @@ opt.no? # true if --no-foo variant used
|
|
|
73
74
|
opt.yes? # opposite of `no?`
|
|
74
75
|
arg.value # positional argument
|
|
75
76
|
arg.arg # same as .value, useful for pattern matching
|
|
77
|
+
arg.to_s # implicit string conversion (same as .value)
|
|
76
78
|
Sep # -- end of options marker; Const, not instantiated
|
|
77
79
|
```
|
|
78
80
|
|
|
@@ -118,6 +120,7 @@ cmd -fVAL, --foo=VAL # attached values
|
|
|
118
120
|
cmd -f VAL, --foo VAL # separate values
|
|
119
121
|
cmd --foo val -- --bar # --bar becomes positional after --
|
|
120
122
|
cmd --intermixed args and --options # flexible ordering
|
|
123
|
+
cmd --ver # partial matching (--ver matches --verbose if unique)
|
|
121
124
|
```
|
|
122
125
|
|
|
123
126
|
## Manual option declaration building
|
|
@@ -141,6 +144,7 @@ Optdecl["foo_bar"] # --foo_bar: but not in strings.
|
|
|
141
144
|
```ruby
|
|
142
145
|
optlist = Optlist[optdecl1, optdecl2] # combine decls into optlist
|
|
143
146
|
optlist["f"] # lookup by name
|
|
147
|
+
optlist["fl"] # partial match (finds "flag" if unique)
|
|
144
148
|
```
|
|
145
149
|
|
|
146
150
|
## Argument requirements
|
data/lib/strop/version.rb
CHANGED
data/lib/strop.rb
CHANGED
|
@@ -6,17 +6,18 @@ require_relative "strop/version"
|
|
|
6
6
|
# Command-line option parser that builds options from help text
|
|
7
7
|
module Strop
|
|
8
8
|
def self.prefix(name) = (name[1] ? "--" : "-") + name # helper for printing back option names with the right prefix
|
|
9
|
+
def self.name_from_symbol(name) = Symbol === name ? name.to_s.gsub(?_, ?-) : name
|
|
9
10
|
|
|
10
11
|
# Option declaration: names, argument requirement, and canonical label (auto-determined)
|
|
11
12
|
# Optdecl[:f, :foo, arg: :may] #=> Optdecl(names: ["f", "foo"], arg: :may, label: "foo")
|
|
12
13
|
Optdecl = Data.define(:names, :arg, :label) do
|
|
13
14
|
def self.[](*names, arg: nil) = new(names:, arg:) # Custom builder: Optdecl[names, ..., arg: ...]
|
|
14
15
|
def initialize(names:, arg: nil)
|
|
15
|
-
names = [*names].map{
|
|
16
|
-
names[0] = names[0].sub(/[!?]$/, "") unless arg
|
|
17
|
-
arg ||= { ?? => :may, ?! => :must }[$&] || :shant
|
|
18
|
-
label = names.find{ it.size > 1 } || names.first
|
|
19
|
-
%i[must may shant].member? arg or raise "invalid arg"
|
|
16
|
+
names = [*names].map{ Strop.name_from_symbol it } # :foo_bar to "foo-bar" for symbols
|
|
17
|
+
names[0] = names[0].sub(/[!?]$/, "") unless arg # opt? / opt! to opt, and... (unless arg given)
|
|
18
|
+
arg ||= { ?? => :may, ?! => :must }[$&] || :shant # use ?/! to determine arg (unless arg given)
|
|
19
|
+
label = names.find{ it.size > 1 } || names.first # the canonical name used to search for it
|
|
20
|
+
%i[must may shant].member? arg or raise "invalid arg" # validate arg
|
|
20
21
|
super names:, arg:, label:
|
|
21
22
|
end
|
|
22
23
|
|
|
@@ -30,7 +31,18 @@ module Strop
|
|
|
30
31
|
# Optlist[decl1, decl2] #=> [Optdecl(...), Optdecl(...)]
|
|
31
32
|
class Optlist < Array # a list of Optdecls
|
|
32
33
|
def self.from_help(doc) = Strop.parse_help(doc) #=> Optlist[decl, ...] # Build from help text
|
|
33
|
-
|
|
34
|
+
|
|
35
|
+
def [](k, ...)
|
|
36
|
+
case k
|
|
37
|
+
in String | Symbol
|
|
38
|
+
s = Strop.name_from_symbol k
|
|
39
|
+
found = find{ it.names.member? s } and return found
|
|
40
|
+
found, *others = select{ it.names.any?{ it.start_with? s }} if s[1]
|
|
41
|
+
found if found && others.empty?
|
|
42
|
+
else super(k, ...)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
34
46
|
def to_s(as=:plain)
|
|
35
47
|
case as
|
|
36
48
|
when :plain then join("\n")
|
|
@@ -58,6 +70,7 @@ module Strop
|
|
|
58
70
|
Arg = Data.define :value, :arg do
|
|
59
71
|
def initialize(value:) = super(value:, arg: value)
|
|
60
72
|
alias to_s value
|
|
73
|
+
alias to_str value
|
|
61
74
|
end
|
|
62
75
|
|
|
63
76
|
# Parsed option with declaration, invocation name, value, and negation state. Used internally. Seen as member of Result.
|
|
@@ -73,7 +86,7 @@ module Strop
|
|
|
73
86
|
end
|
|
74
87
|
|
|
75
88
|
# Const for parsed `--` end of option markers. Seen as member of Result.
|
|
76
|
-
Sep = :
|
|
89
|
+
Sep = :sep
|
|
77
90
|
|
|
78
91
|
# Parse result containing options, arguments, and separators; Returned by `parse`
|
|
79
92
|
# Result[opt1, arg1, Sep] #=> [Opt(...), Arg(...), Sep]
|
|
@@ -83,7 +96,8 @@ module Strop
|
|
|
83
96
|
def opts = Result.new(select { Opt === it })
|
|
84
97
|
def [](k, ...)
|
|
85
98
|
case k
|
|
86
|
-
|
|
99
|
+
in [String | Symbol => name] then opts.select{ it.decl.names.include? Strop.name_from_symbol name }
|
|
100
|
+
in String | Symbol then find{ Opt === it && it.decl.names.member?(Strop.name_from_symbol k) }
|
|
87
101
|
else super(k, ...)
|
|
88
102
|
end
|
|
89
103
|
end
|
|
@@ -123,7 +137,7 @@ module Strop
|
|
|
123
137
|
res = Result.new
|
|
124
138
|
ctx = :top
|
|
125
139
|
name, token, opt = nil
|
|
126
|
-
rx_value = /\A[^-]|\A
|
|
140
|
+
rx_value = /\A[^-]|\A-?\z/ # not an opt
|
|
127
141
|
loop do
|
|
128
142
|
case ctx
|
|
129
143
|
in :end then return res.concat tokens.map{ Arg[it] } # opt parsing ended, rest is positional args
|