optimist_xl 3.2.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/History.md +7 -0
- data/README.md +134 -4
- data/examples/didyoumean.rb +11 -0
- data/examples/optional_string_arg_type.rb +10 -0
- data/examples/partialmatch.rb +11 -0
- data/lib/optimist_xl.rb +127 -40
- data/optimist_xl.gemspec +2 -1
- data/test/optimist_xl/stringflag_test.rb +158 -0
- metadata +13 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fe9d9828ccf8519f081c520339195ab106b579a0d09564aab1a0ea47134b00a
|
4
|
+
data.tar.gz: 1f60a13d38245b2d7214093843403ffeefb917d3a4466ef50b11904cdc733037
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce7e01b876214a131e653a5c9a3f700aaa7388bf68b211927b8bcda2f80d65d963b0991bc323a23d356f4be3bf2a41c943dcc44219bc421e18be824d0d897bb8
|
7
|
+
data.tar.gz: 4f6a89f6a84d5609e84f6323e104ee535893e7f74f2ca964665d4e745292b32a640cfead9efde73d9681c2d637edc38af2fe6f68ebaa3b428e28d72d58ace39f
|
data/.travis.yml
CHANGED
data/History.md
CHANGED
@@ -1,8 +1,15 @@
|
|
1
|
+
# [3.3.0] / 2020-11-12
|
2
|
+
|
3
|
+
* Adding new `:stringflag` option.
|
4
|
+
* Improving documentation.
|
5
|
+
* Removing support for Ruby 2.2
|
6
|
+
|
1
7
|
# [3.2.0] / 2020-03-02
|
2
8
|
|
3
9
|
* Added alternate-named long options using `:alt`
|
4
10
|
* Added alternate-named short-options by allowing `:short` to take an Array.
|
5
11
|
* Refactored some short/long handling code into ShortNames and LongNames classes.
|
12
|
+
|
6
13
|
# [3.1.1] / 2020-01-20
|
7
14
|
|
8
15
|
* The gem has been forked from optimist to optimist_xl
|
data/README.md
CHANGED
@@ -29,13 +29,15 @@ See the **Extended Features** section below for the differences/enhancements
|
|
29
29
|
conversion.
|
30
30
|
- Automatic help message generation, wrapped to current screen width.
|
31
31
|
|
32
|
-
## Extended
|
32
|
+
## Extended features unavailable in the original Optimist gem
|
33
33
|
|
34
34
|
### Parser Settings
|
35
35
|
- Automatic suggestions whens incorrect options are given
|
36
36
|
- disable with `suggestions: false`
|
37
|
+
- see example below
|
37
38
|
- Inexact matching of long arguments
|
38
39
|
- disable with `exact_match: true`
|
40
|
+
- see example below
|
39
41
|
- Available prevention of short-arguments by default
|
40
42
|
- enable with `explicit_short_opts: true`
|
41
43
|
|
@@ -61,16 +63,144 @@ Long options can be given alternate names using `alt:`
|
|
61
63
|
|
62
64
|
See [example](examples/alt_names.rb)
|
63
65
|
|
66
|
+
### Stringflag option-type
|
67
|
+
|
68
|
+
It is useful to allow an option that can be set as a string, used with a default string or unset, especialy in the case of specifying a log-file. AFAICT this was not possible with the original Optimist.
|
69
|
+
|
70
|
+
Example:
|
71
|
+
|
72
|
+
For this option definition:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
opt :log, "Specify optional logfile", :type => :stringflag, :default => "progname.log"
|
76
|
+
```
|
77
|
+
|
78
|
+
The programmer should use the value of `log_given` in conjunction with the value of `log`
|
79
|
+
to determine whether to enable logging what what the filename should be.
|
80
|
+
|
81
|
+
```sh
|
82
|
+
$ ./examples/optional_string_arg_type.rb -h
|
83
|
+
Options:
|
84
|
+
-l, --log=<s?>, --no-log specify optional log-file path (Default: progname.log)
|
85
|
+
-h, --help Show this message
|
86
|
+
|
87
|
+
# Note that when no options are given, :log_given is not set, but the default passes through.
|
88
|
+
$ ./examples/optional_string_arg_type.rb
|
89
|
+
{:log=>"progname.log", :help=>false}
|
90
|
+
|
91
|
+
$ ./examples/optional_string_arg_type.rb -l
|
92
|
+
{:log=>"progname.log", :help=>false, :log_given=>true}
|
93
|
+
|
94
|
+
# In this case no-log can be used to force a false value into :log
|
95
|
+
$ ./examples/optional_string_arg_type.rb --no-log
|
96
|
+
{:log=>false, :help=>false, :log_given=>true}
|
97
|
+
|
98
|
+
# Overriding the default case
|
99
|
+
$ ./examples/optional_string_arg_type.rb --log othername.log
|
100
|
+
{:log=>"othername.log", :help=>false, :log_given=>true}
|
101
|
+
```
|
102
|
+
|
64
103
|
### Subcommands
|
65
104
|
"Native" subcommand support - similar to sub-commands in Git.
|
66
105
|
- See [example](examples/subcommands.rb)
|
67
106
|
- Ideas borrowed from https://github.com/jwliechty/trollop-subcommands
|
68
107
|
|
108
|
+
### Automatic suggestions
|
109
|
+
|
110
|
+
Suggestions are formed using the DidYouMean gem, which is part of Ruby 2.3+. It uses the JaroWinkler and Levenshtein distance to determine when unknown options are within a certain 'distance' of a known option keyword.
|
111
|
+
|
112
|
+
```sh
|
113
|
+
$ ./examples/didyoumean.rb -h
|
114
|
+
Options:
|
115
|
+
-c, --cone Ice cream cone
|
116
|
+
-z, --zippy It zips
|
117
|
+
-a, --zapzy It zapz
|
118
|
+
-b, --big-bug Madagascar cockroach
|
119
|
+
-h, --help Show this message
|
120
|
+
|
121
|
+
# Suggestions for a simple misspelling
|
122
|
+
|
123
|
+
$ ./examples/didyoumean.rb --bone
|
124
|
+
Error: unknown argument '--bone'. Did you mean: [--cone] ?.
|
125
|
+
Try --help for help.
|
126
|
+
|
127
|
+
# Letter transposition
|
128
|
+
$ ./examples/didyoumean.rb --ocne
|
129
|
+
Error: unknown argument '--ocne'. Did you mean: [--cone] ?.
|
130
|
+
Try --help for help.
|
131
|
+
|
132
|
+
# Accidental plural
|
133
|
+
|
134
|
+
$ ./examples/didyoumean.rb --cones
|
135
|
+
Error: unknown argument '--cones'. Did you mean: [--cone] ?.
|
136
|
+
Try --help for help.
|
137
|
+
|
138
|
+
# Two close matches, provide two suggestions.
|
139
|
+
|
140
|
+
$ ./examples/didyoumean.rb --zipzy
|
141
|
+
Error: unknown argument '--zipzy'. Did you mean: [--zippy, --zapzy] ?.
|
142
|
+
Try --help for help.
|
143
|
+
|
144
|
+
# Posix-style options with '-' instead of '_' are a common mistake
|
145
|
+
|
146
|
+
$ ./examples/didyoumean.rb --big_bug
|
147
|
+
Error: unknown argument '--big_bug'. Did you mean: [--big-bug] ?.
|
148
|
+
Try --help for help.
|
149
|
+
|
150
|
+
# Eventually the input option is too far away from
|
151
|
+
# anything we know about so just say we dont understand
|
152
|
+
|
153
|
+
$ ./examples/didyoumean.rb --bugblatter-beast
|
154
|
+
Error: unknown argument '--bugblatter-beast'.
|
155
|
+
Try --help for help.
|
156
|
+
```
|
157
|
+
|
158
|
+
### Inexact Matching
|
159
|
+
|
160
|
+
Similar to Perl's Getopt::Long, partially specified long-options can be used as long as they would unambiguously match a single option.
|
161
|
+
|
162
|
+
```sh
|
163
|
+
$ ./examples/partialmatch.rb -h
|
164
|
+
Options:
|
165
|
+
-a, --apple An apple
|
166
|
+
-p, --apple-sauce Cooked apple puree
|
167
|
+
-t, --atom Smallest unit of ordinary matter
|
168
|
+
-n, --anvil Heavy metal
|
169
|
+
-e, --anteater Eats ants
|
170
|
+
-h, --help Show this message
|
171
|
+
|
172
|
+
# Exact match for 'apple'
|
173
|
+
$ ./examples/partialmatch.rb --apple
|
174
|
+
{:apple=>true, :apple_sauce=>false, :atom=>false, :anvil=>false, :anteater=>false, :help=>false, :apple_given=>true}
|
175
|
+
|
176
|
+
# Cannot inexact match with 'app', as it partially matches more than one known option
|
177
|
+
$ ./examples/partialmatch.rb --app
|
178
|
+
Error: ambiguous option '--app' matched keys (apple,apple-sauce).
|
179
|
+
Try --help for help.
|
180
|
+
|
181
|
+
# Inexact match for 'apple-sauce'
|
182
|
+
$ ./examples/partialmatch.rb --apple-s
|
183
|
+
{:apple=>false, :apple_sauce=>true, :atom=>false, :anvil=>false, :anteater=>false, :help=>false, :apple_sauce_given=>true}
|
184
|
+
|
185
|
+
# Shortest match for 'anvil'
|
186
|
+
$ ./examples/partialmatch.rb --anv
|
187
|
+
{:apple=>false, :apple_sauce=>false, :atom=>false, :anvil=>true, :anteater=>false, :help=>false, :anvil_given=>true}
|
188
|
+
|
189
|
+
# Cannot inexact match with 'an', as it partially matches more than one known option
|
190
|
+
$ ./examples/partialmatch.rb --an
|
191
|
+
Error: ambiguous option '--an' matched keys (anvil,anteater).
|
192
|
+
Try --help for help.
|
193
|
+
|
194
|
+
# Shortest match for 'atom'
|
195
|
+
$ ./examples/partialmatch.rb --at
|
196
|
+
{:apple=>false, :apple_sauce=>false, :atom=>true, :anvil=>false, :anteater=>false, :help=>false, :atom_given=>true}
|
197
|
+
```
|
198
|
+
|
69
199
|
## Requirements
|
70
200
|
|
71
|
-
* Ruby 2.2+
|
72
201
|
* A burning desire to write less code.
|
73
|
-
|
202
|
+
* Ruby 2.3+
|
203
|
+
|
74
204
|
## Install
|
75
205
|
|
76
206
|
* `gem install optimist_xl`
|
@@ -94,6 +224,6 @@ Copyright © 2008-2014 [William Morgan](http://masanjin.net/).
|
|
94
224
|
|
95
225
|
Copyright © 2014 Red Hat, Inc.
|
96
226
|
|
97
|
-
Copyright © 2019 Ben Bowers
|
227
|
+
Copyright © 2019-2020 Ben Bowers
|
98
228
|
|
99
229
|
OptimistXL is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative '../lib/optimist_xl'
|
3
|
+
|
4
|
+
opts = OptimistXL::options do
|
5
|
+
opt :apple, "An apple"
|
6
|
+
opt :apple_sauce, "Cooked apple puree"
|
7
|
+
opt :atom, "Smallest unit of ordinary matter"
|
8
|
+
opt :anvil, "Heavy metal"
|
9
|
+
opt :anteater, "Eats ants"
|
10
|
+
end
|
11
|
+
p opts
|
data/lib/optimist_xl.rb
CHANGED
@@ -9,7 +9,7 @@ require 'date'
|
|
9
9
|
module OptimistXL
|
10
10
|
# note: this is duplicated in gemspec
|
11
11
|
# please change over there too
|
12
|
-
VERSION = "3.
|
12
|
+
VERSION = "3.3.0"
|
13
13
|
|
14
14
|
## Thrown by Parser in the event of a commandline error. Not needed if
|
15
15
|
## you're using the OptimistXL::options entry.
|
@@ -402,15 +402,34 @@ class Parser
|
|
402
402
|
# The block returns the number of parameters taken.
|
403
403
|
num_params_taken = 0
|
404
404
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
405
|
+
#DEBUG# puts "\nparams:#{params} npt:#{num_params_taken},ps:#{params.size}"
|
406
|
+
|
407
|
+
#if params.size > 0
|
408
|
+
# if @specs[sym].min_args == 1 && @specs[sym].max_args == 1
|
409
|
+
# given_args[sym][:params] << params[0, 1] # take the first parameter
|
410
|
+
# num_params_taken = 1
|
411
|
+
# elsif @specs[sym].max_args > 1
|
412
|
+
# given_args[sym][:params] << params # take all the parameters
|
413
|
+
# num_params_taken = params.size
|
414
|
+
# end
|
415
|
+
#end
|
416
|
+
|
417
|
+
if params.size == 0
|
418
|
+
if @specs[sym].min_args == 0
|
419
|
+
given_args[sym][:params] << [ @specs[sym].default || true]
|
420
|
+
end
|
421
|
+
elsif params.size > 0
|
422
|
+
if params.size >= @specs[sym].max_args
|
423
|
+
# take smaller of the two sizes to determine how many parameters to take
|
424
|
+
num_params_taken = [params.size, @specs[sym].max_args].min
|
425
|
+
given_args[sym][:params] << params[0, num_params_taken]
|
426
|
+
else
|
427
|
+
# take all the parameters
|
428
|
+
given_args[sym][:params] << params
|
411
429
|
num_params_taken = params.size
|
412
430
|
end
|
413
431
|
end
|
432
|
+
|
414
433
|
|
415
434
|
num_params_taken
|
416
435
|
end
|
@@ -443,7 +462,8 @@ class Parser
|
|
443
462
|
arg, params, negative_given = given_data.values_at :arg, :params, :negative_given
|
444
463
|
|
445
464
|
opts = @specs[sym]
|
446
|
-
|
465
|
+
|
466
|
+
if params.size < opts.min_args
|
447
467
|
raise CommandlineError, "option '#{arg}' needs a parameter" unless opts.default
|
448
468
|
params << (opts.array_default? ? opts.default.clone : [opts.default])
|
449
469
|
end
|
@@ -458,13 +478,19 @@ class Parser
|
|
458
478
|
|
459
479
|
vals[sym] = opts.parse(params, negative_given)
|
460
480
|
|
461
|
-
if opts.
|
481
|
+
if opts.min_args==0 && opts.max_args==1
|
482
|
+
if opts.multi?
|
483
|
+
vals[sym] = vals[sym].map { |p| p[0] }
|
484
|
+
else
|
485
|
+
vals[sym] = vals[sym][0][0]
|
486
|
+
end
|
487
|
+
elsif opts.min_args==1 && opts.max_args==1
|
462
488
|
if opts.multi? # multiple options, each with a single parameter
|
463
489
|
vals[sym] = vals[sym].map { |p| p[0] }
|
464
490
|
else # single parameter
|
465
491
|
vals[sym] = vals[sym][0][0]
|
466
492
|
end
|
467
|
-
elsif opts.
|
493
|
+
elsif opts.max_args>1 && !opts.multi?
|
468
494
|
vals[sym] = vals[sym][0] # single option, with multiple parameters
|
469
495
|
end
|
470
496
|
# else: multiple options, with multiple parameters
|
@@ -847,6 +873,17 @@ class Option
|
|
847
873
|
@permitted = nil
|
848
874
|
@permitted_response = "option '%{arg}' only accepts %{valid_string}"
|
849
875
|
@optshash = Hash.new()
|
876
|
+
@min_args = 1
|
877
|
+
@max_args = 1
|
878
|
+
# maximum max_args is likely ~~ 128*1024, as linux MAX_ARG_STRLEN is 128kiB
|
879
|
+
end
|
880
|
+
|
881
|
+
|
882
|
+
# Check that an option is compatible with another option.
|
883
|
+
# By default, checking that they are the same class, but we
|
884
|
+
# can override this in the subclass as needed.
|
885
|
+
def compatible_with?(other_option)
|
886
|
+
self.is_a? other_option.class
|
850
887
|
end
|
851
888
|
|
852
889
|
def opts(key)
|
@@ -857,24 +894,24 @@ class Option
|
|
857
894
|
@optshash = o
|
858
895
|
end
|
859
896
|
|
860
|
-
## Indicates a flag option, which is an option without an argument
|
861
|
-
def flag? ; false ; end
|
862
|
-
def single_arg?
|
863
|
-
!self.multi_arg? && !self.flag?
|
864
|
-
end
|
865
897
|
|
866
898
|
def multi ; @multi_given ; end
|
867
899
|
alias multi? multi
|
868
900
|
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
901
|
+
attr_reader :min_args, :max_args
|
902
|
+
# |@min_args | @max_args |
|
903
|
+
# +----------+-----------+
|
904
|
+
# | 0 | 0 | formerly flag?==true (option without any arguments)
|
905
|
+
# | 1 | 1 | formerly single_arg?==true (single-parameter/normal option)
|
906
|
+
# | 1 | >1 | formerly multi_arg?==true
|
907
|
+
# | ? | ? | presumably illegal condition. untested.
|
908
|
+
|
873
909
|
def array_default? ; self.default.kind_of?(Array) ; end
|
874
910
|
|
875
911
|
def doesnt_need_autogen_short ; !short.auto || !short.chars.empty? ; end
|
876
912
|
|
877
913
|
def callback ; opts(:callback) ; end
|
914
|
+
|
878
915
|
def desc ; opts(:desc) ; end
|
879
916
|
|
880
917
|
def required? ; opts(:required) ; end
|
@@ -890,7 +927,7 @@ class Option
|
|
890
927
|
optionlist = []
|
891
928
|
optionlist.concat(short.chars.map { |o| "-#{o}" })
|
892
929
|
optionlist.concat(long.names.map { |o| "--#{o}" })
|
893
|
-
optionlist.compact.join(', ') + type_format + (
|
930
|
+
optionlist.compact.join(', ') + type_format + (min_args==0 && default ? ", --no-#{long}" : "")
|
894
931
|
end
|
895
932
|
|
896
933
|
## Format the educate-line description including the default and permitted value(s)
|
@@ -998,9 +1035,11 @@ class Option
|
|
998
1035
|
|
999
1036
|
opttype = OptimistXL::Parser.registry_getopttype(opts[:type])
|
1000
1037
|
opttype_from_default = get_klass_from_default(opts, opttype)
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1038
|
+
#DEBUG# puts "\nopt:#{opttype||'nil'} ofd:#{opttype_from_default}" if opttype_from_default
|
1039
|
+
if opttype && opttype_from_default && !opttype.compatible_with?(opttype_from_default) # opttype.is_a? opttype_from_default.class
|
1040
|
+
raise ArgumentError, ":type specification (#{opttype.class}) and default type don't match (default type is #{opttype_from_default.class})"
|
1041
|
+
end
|
1042
|
+
|
1004
1043
|
opt_inst = (opttype || opttype_from_default || OptimistXL::BooleanOption.new)
|
1005
1044
|
|
1006
1045
|
## fill in :long
|
@@ -1034,7 +1073,7 @@ class Option
|
|
1034
1073
|
if disambiguated_default.is_a? Array
|
1035
1074
|
return(optdef.first.class.name.downcase + "s") if !optdef.empty?
|
1036
1075
|
if opttype
|
1037
|
-
raise ArgumentError, "multiple argument type must be plural" unless opttype.
|
1076
|
+
raise ArgumentError, "multiple argument type must be plural" unless opttype.max_args > 1
|
1038
1077
|
return nil
|
1039
1078
|
else
|
1040
1079
|
raise ArgumentError, "multiple argument type cannot be deduced from an empty array"
|
@@ -1063,16 +1102,42 @@ class Option
|
|
1063
1102
|
private_class_method :get_type_from_disdef
|
1064
1103
|
private_class_method :get_klass_from_default
|
1065
1104
|
|
1105
|
+
def self.handle_long_opt(lopt, name)
|
1106
|
+
lopt = lopt ? lopt.to_s : name.to_s.gsub("_", "-")
|
1107
|
+
lopt = case lopt
|
1108
|
+
when /^--([^-].*)$/ then $1
|
1109
|
+
when /^[^-]/ then lopt
|
1110
|
+
else raise ArgumentError, "invalid long option name #{lopt.inspect}"
|
1111
|
+
end
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
def self.handle_short_opt(sopt)
|
1115
|
+
sopt = sopt.to_s if sopt && sopt != :none
|
1116
|
+
sopt = case sopt
|
1117
|
+
when /^-(.)$/ then $1
|
1118
|
+
when nil, :none, /^.$/ then sopt
|
1119
|
+
else raise ArgumentError, "invalid short option name '#{sopt.inspect}'"
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
if sopt
|
1123
|
+
raise ArgumentError, "a short option name can't be a number or a dash" if sopt =~ ::OptimistXL::Parser::INVALID_SHORT_ARG_REGEX
|
1124
|
+
end
|
1125
|
+
return sopt
|
1126
|
+
end
|
1127
|
+
|
1066
1128
|
end
|
1067
1129
|
|
1068
1130
|
# Flag option. Has no arguments. Can be negated with "no-".
|
1069
1131
|
class BooleanOption < Option
|
1070
1132
|
register_alias :flag, :bool, :boolean, :trueclass, :falseclass
|
1133
|
+
|
1071
1134
|
def initialize
|
1072
1135
|
super()
|
1073
1136
|
@default = false
|
1137
|
+
@min_args = 0
|
1138
|
+
@max_args = 0
|
1074
1139
|
end
|
1075
|
-
|
1140
|
+
|
1076
1141
|
def parse(_paramlist, neg_given)
|
1077
1142
|
return(self.name.to_s =~ /^no_/ ? neg_given : !neg_given)
|
1078
1143
|
end
|
@@ -1139,6 +1204,38 @@ class StringOption < Option
|
|
1139
1204
|
end
|
1140
1205
|
end
|
1141
1206
|
|
1207
|
+
#
|
1208
|
+
class StringFlagOption < StringOption
|
1209
|
+
register_alias :stringflag
|
1210
|
+
def type_format ; "=<s?>" ; end
|
1211
|
+
def parse(paramlist, neg_given)
|
1212
|
+
paramlist.map do |plist|
|
1213
|
+
plist.map do |pg|
|
1214
|
+
neg_given ? false : pg
|
1215
|
+
#case pg
|
1216
|
+
#when FalseClass then () ? neg_given : !neg_given
|
1217
|
+
#when TrueClass then (self.name.to_s =~ /^no_/) ? neg_given : !neg_given
|
1218
|
+
#else pg
|
1219
|
+
#end
|
1220
|
+
end
|
1221
|
+
end
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
def initialize
|
1225
|
+
super
|
1226
|
+
@default = false
|
1227
|
+
@min_args = 0
|
1228
|
+
@max_args = 1
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
def compatible_with?(other_option)
|
1232
|
+
self.is_a?(other_option.class) ||
|
1233
|
+
other_option.is_a?(BooleanOption) ||
|
1234
|
+
other_option.is_a?(StringArrayOption)
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
end
|
1238
|
+
|
1142
1239
|
# Option for dates. No longer uses Chronic if available.
|
1143
1240
|
# If chronic style dates are needed, then you may
|
1144
1241
|
# require 'optimist_xl/chronic'
|
@@ -1169,35 +1266,35 @@ end
|
|
1169
1266
|
class IntegerArrayOption < IntegerOption
|
1170
1267
|
register_alias :fixnums, :ints, :integers
|
1171
1268
|
def type_format ; "=<i+>" ; end
|
1172
|
-
def
|
1269
|
+
def initialize ; super ; @max_args = 999 ; end
|
1173
1270
|
end
|
1174
1271
|
|
1175
1272
|
# Option class for handling multiple Floats
|
1176
1273
|
class FloatArrayOption < FloatOption
|
1177
1274
|
register_alias :doubles, :floats
|
1178
1275
|
def type_format ; "=<f+>" ; end
|
1179
|
-
def
|
1276
|
+
def initialize ; super ; @max_args = 999 ; end
|
1180
1277
|
end
|
1181
1278
|
|
1182
1279
|
# Option class for handling multiple Strings
|
1183
1280
|
class StringArrayOption < StringOption
|
1184
1281
|
register_alias :strings
|
1185
1282
|
def type_format ; "=<s+>" ; end
|
1186
|
-
def
|
1283
|
+
def initialize ; super ; @max_args = 999 ; end
|
1187
1284
|
end
|
1188
1285
|
|
1189
1286
|
# Option class for handling multiple dates
|
1190
1287
|
class DateArrayOption < DateOption
|
1191
1288
|
register_alias :dates
|
1192
1289
|
def type_format ; "=<date+>" ; end
|
1193
|
-
def
|
1290
|
+
def initialize ; super ; @max_args = 999 ; end
|
1194
1291
|
end
|
1195
1292
|
|
1196
1293
|
# Option class for handling Files/URLs via 'open'
|
1197
1294
|
class IOArrayOption < IOOption
|
1198
1295
|
register_alias :ios
|
1199
1296
|
def type_format ; "=<filename/uri+>" ; end
|
1200
|
-
def
|
1297
|
+
def initialize ; super ; @max_args = 999 ; end
|
1201
1298
|
end
|
1202
1299
|
|
1203
1300
|
## The easy, syntactic-sugary entry method into OptimistXL. Creates a Parser,
|
@@ -1342,13 +1439,3 @@ end
|
|
1342
1439
|
|
1343
1440
|
module_function :options, :die, :educate, :with_standard_exception_handling
|
1344
1441
|
end # module
|
1345
|
-
|
1346
|
-
|
1347
|
-
# @global_parser.stop_on(subcommands)
|
1348
|
-
# @global_parser.stop_on_unknown
|
1349
|
-
# Trollop::with_standard_exception_handling(@global_parser) do
|
1350
|
-
# global_options = @global_parser.parse(args)
|
1351
|
-
# cmd = parse_subcommand(args)
|
1352
|
-
# cmd_options = parse_subcommand_options(args, cmd)
|
1353
|
-
# Result.new(global_options, cmd, cmd_options)
|
1354
|
-
# end
|
data/optimist_xl.gemspec
CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.email = "nanobowers@gmail.com"
|
12
12
|
spec.summary = "OptimistXL is feature fork of the Optimist commandline option parser."
|
13
13
|
spec.description = "OptimistXL is feature filled but lightweight commandline option parser.
|
14
|
+
It contains all of the features of the Optimist gem, plus lots of additional features you didnt know you needed.
|
14
15
|
One line of code per option is all you typically need to write.
|
15
16
|
For that, you get a nice automatically-generated help page, robust option
|
16
17
|
parsing, command subcompletion, and sensible defaults for everything you don't
|
@@ -32,6 +33,6 @@ specify. This gem is an enhanced-feature fork of the Optimist gem."
|
|
32
33
|
spec.required_ruby_version = '>= 2.2'
|
33
34
|
|
34
35
|
spec.add_development_dependency "minitest", "~> 5.4.3"
|
35
|
-
spec.add_development_dependency "rake", "
|
36
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
36
37
|
spec.add_development_dependency "chronic"
|
37
38
|
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module OptimistXL
|
5
|
+
class StringFlagParserTest < ::MiniTest::Test
|
6
|
+
def setup
|
7
|
+
@p = Parser.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# in this case, the stringflag should return false
|
11
|
+
def test_stringflag_unset
|
12
|
+
@p.opt :xyz, "desc", :type => :stringflag
|
13
|
+
@p.opt :abc, "desc", :type => :flag
|
14
|
+
opts = @p.parse %w()
|
15
|
+
assert_equal false, opts[:xyz]
|
16
|
+
assert_equal false, opts[:abc]
|
17
|
+
opts = @p.parse %w(--abc)
|
18
|
+
assert_equal false, opts[:xyz]
|
19
|
+
assert_equal true, opts[:abc]
|
20
|
+
end
|
21
|
+
|
22
|
+
# in this case, the stringflag should return true
|
23
|
+
def test_stringflag_as_flag
|
24
|
+
@p.opt :xyz, "desc", :type => :stringflag
|
25
|
+
@p.opt :abc, "desc", :type => :flag
|
26
|
+
opts = @p.parse %w(--xyz )
|
27
|
+
assert_equal true, opts[:xyz_given]
|
28
|
+
assert_equal true, opts[:xyz]
|
29
|
+
assert_equal false, opts[:abc]
|
30
|
+
opts = @p.parse %w(--xyz --abc)
|
31
|
+
assert_equal true, opts[:xyz_given]
|
32
|
+
assert_equal true, opts[:xyz]
|
33
|
+
assert_equal true, opts[:abc]
|
34
|
+
end
|
35
|
+
|
36
|
+
# in this case, the stringflag should return a string
|
37
|
+
def test_stringflag_as_string
|
38
|
+
@p.opt :xyz, "desc", :type => :stringflag
|
39
|
+
@p.opt :abc, "desc", :type => :flag
|
40
|
+
opts = @p.parse %w(--xyz abcd)
|
41
|
+
assert_equal true, opts[:xyz_given]
|
42
|
+
assert_equal "abcd", opts[:xyz]
|
43
|
+
assert_equal false, opts[:abc]
|
44
|
+
opts = @p.parse %w(--xyz abcd --abc)
|
45
|
+
assert_equal true, opts[:xyz_given]
|
46
|
+
assert_equal "abcd", opts[:xyz]
|
47
|
+
assert_equal true, opts[:abc]
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_stringflag_with_string_default
|
51
|
+
@p.opt :log, "desc", :type => :stringflag, default: "output.log"
|
52
|
+
opts = @p.parse []
|
53
|
+
assert_nil opts[:log_given]
|
54
|
+
assert_equal "output.log", opts[:log]
|
55
|
+
|
56
|
+
opts = @p.parse %w(--no-log)
|
57
|
+
assert_equal true, opts[:log_given]
|
58
|
+
assert_equal false, opts[:log]
|
59
|
+
|
60
|
+
opts = @p.parse %w(--log)
|
61
|
+
assert_equal true, opts[:log_given]
|
62
|
+
assert_equal "output.log", opts[:log]
|
63
|
+
|
64
|
+
opts = @p.parse %w(--log other.log)
|
65
|
+
assert_equal true, opts[:log_given]
|
66
|
+
assert_equal "other.log", opts[:log]
|
67
|
+
end
|
68
|
+
|
69
|
+
# should be same as with no default, but making sure.
|
70
|
+
def test_stringflag_with_false_default
|
71
|
+
@p.opt :log, "desc", :type => :stringflag, default: false
|
72
|
+
opts = @p.parse []
|
73
|
+
assert_nil opts[:log_given]
|
74
|
+
assert_equal false, opts[:log]
|
75
|
+
|
76
|
+
opts = @p.parse %w(--no-log)
|
77
|
+
assert_equal true, opts[:log_given]
|
78
|
+
assert_equal false, opts[:log]
|
79
|
+
|
80
|
+
opts = @p.parse %w(--log)
|
81
|
+
assert_equal true, opts[:log_given]
|
82
|
+
assert_equal true, opts[:log]
|
83
|
+
|
84
|
+
opts = @p.parse %w(--log other.log)
|
85
|
+
assert_equal true, opts[:log_given]
|
86
|
+
assert_equal "other.log", opts[:log]
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_stringflag_with_no_defaults
|
90
|
+
@p.opt :log, "desc", :type => :stringflag
|
91
|
+
|
92
|
+
opts = @p.parse []
|
93
|
+
assert_nil opts[:log_given]
|
94
|
+
assert_equal false, opts[:log]
|
95
|
+
|
96
|
+
opts = @p.parse %w(--no-log)
|
97
|
+
assert_equal true, opts[:log_given]
|
98
|
+
assert_equal false, opts[:log]
|
99
|
+
|
100
|
+
opts = @p.parse %w(--log)
|
101
|
+
assert_equal true, opts[:log_given]
|
102
|
+
assert_equal true, opts[:log]
|
103
|
+
|
104
|
+
opts = @p.parse %w(--log other.log)
|
105
|
+
assert_equal true, opts[:log_given]
|
106
|
+
assert_equal "other.log", opts[:log]
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class MultiStringFlagParserTest < ::MiniTest::Test
|
112
|
+
def setup
|
113
|
+
@p = Parser.new
|
114
|
+
@p.opt :xyz, "desc", :type => :stringflag, :multi => true
|
115
|
+
@p.opt :ghi, "desc", :type => :stringflag, :multi => true, default: ["gg","hh"]
|
116
|
+
@p.opt :abc, "desc", :type => :string, :multi => true
|
117
|
+
end
|
118
|
+
|
119
|
+
# in this case, the stringflag should return multiple strings
|
120
|
+
def test_multi_stringflag_as_strings
|
121
|
+
opts = @p.parse %w(--xyz dog --xyz cat)
|
122
|
+
assert_equal true, opts[:xyz_given]
|
123
|
+
assert_equal ["dog","cat"], opts[:xyz]
|
124
|
+
assert_equal [], opts[:abc] # note, multi-args default to empty array
|
125
|
+
assert_nil opts[:ghi_given]
|
126
|
+
assert_equal ["gg","hh"], opts[:ghi]
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_multi_stringflag_as_flags
|
130
|
+
opts = @p.parse %w(--xyz --xyz --xyz)
|
131
|
+
assert_equal true, opts[:xyz_given]
|
132
|
+
assert_equal [true, true, true], opts[:xyz]
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_multi_stringflag_as_mix1
|
136
|
+
opts = @p.parse %w(--xyz --xyz dog --xyz cat)
|
137
|
+
assert_equal true, opts[:xyz_given]
|
138
|
+
assert_equal [true, "dog", "cat"], opts[:xyz]
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_multi_stringflag_as_mix2
|
142
|
+
opts = @p.parse %w(--xyz dog --xyz cat --xyz --abc letters)
|
143
|
+
assert_equal true, opts[:xyz_given]
|
144
|
+
assert_equal ["dog", "cat", true], opts[:xyz]
|
145
|
+
assert_equal ["letters"], opts[:abc]
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_multi_stringflag_override_array_default
|
149
|
+
opts = @p.parse %w(--xyz --ghi yy --ghi zz)
|
150
|
+
assert_equal true, opts[:xyz_given]
|
151
|
+
assert_equal true, opts[:ghi_given]
|
152
|
+
assert_equal ["yy","zz"], opts[:ghi]
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: optimist_xl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Morgan
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2020-
|
14
|
+
date: 2020-11-12 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: minitest
|
@@ -31,16 +31,16 @@ dependencies:
|
|
31
31
|
name: rake
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- - "
|
34
|
+
- - ">="
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
36
|
+
version: 12.3.3
|
37
37
|
type: :development
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- - "
|
41
|
+
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
43
|
+
version: 12.3.3
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
45
|
name: chronic
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
@@ -57,6 +57,7 @@ dependencies:
|
|
57
57
|
version: '0'
|
58
58
|
description: |-
|
59
59
|
OptimistXL is feature filled but lightweight commandline option parser.
|
60
|
+
It contains all of the features of the Optimist gem, plus lots of additional features you didnt know you needed.
|
60
61
|
One line of code per option is all you typically need to write.
|
61
62
|
For that, you get a nice automatically-generated help page, robust option
|
62
63
|
parsing, command subcompletion, and sensible defaults for everything you don't
|
@@ -79,7 +80,10 @@ files:
|
|
79
80
|
- examples/banners1.rb
|
80
81
|
- examples/banners2.rb
|
81
82
|
- examples/banners3.rb
|
83
|
+
- examples/didyoumean.rb
|
82
84
|
- examples/medium_example.rb
|
85
|
+
- examples/optional_string_arg_type.rb
|
86
|
+
- examples/partialmatch.rb
|
83
87
|
- examples/permitted.rb
|
84
88
|
- examples/subcommands.rb
|
85
89
|
- examples/types.rb
|
@@ -95,6 +99,7 @@ files:
|
|
95
99
|
- test/optimist_xl/parser_parse_test.rb
|
96
100
|
- test/optimist_xl/parser_test.rb
|
97
101
|
- test/optimist_xl/permitted_test.rb
|
102
|
+
- test/optimist_xl/stringflag_test.rb
|
98
103
|
- test/optimist_xl/subcommands_test.rb
|
99
104
|
- test/optimist_xl/version_needed_test.rb
|
100
105
|
- test/optimist_xl_test.rb
|
@@ -122,8 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
127
|
- !ruby/object:Gem::Version
|
123
128
|
version: '0'
|
124
129
|
requirements: []
|
125
|
-
|
126
|
-
rubygems_version: 2.7.4
|
130
|
+
rubygems_version: 3.1.2
|
127
131
|
signing_key:
|
128
132
|
specification_version: 4
|
129
133
|
summary: OptimistXL is feature fork of the Optimist commandline option parser.
|
@@ -136,6 +140,7 @@ test_files:
|
|
136
140
|
- test/optimist_xl/parser_parse_test.rb
|
137
141
|
- test/optimist_xl/parser_test.rb
|
138
142
|
- test/optimist_xl/permitted_test.rb
|
143
|
+
- test/optimist_xl/stringflag_test.rb
|
139
144
|
- test/optimist_xl/subcommands_test.rb
|
140
145
|
- test/optimist_xl/version_needed_test.rb
|
141
146
|
- test/optimist_xl_test.rb
|