optbind 0.3.2 → 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 +182 -2
- data/TODO.md +10 -7
- data/lib/optbind/version.rb +1 -1
- data/lib/optbind.rb +59 -37
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a75ae614f40e93666809a3bcefac9e58ed61e699
|
|
4
|
+
data.tar.gz: d3a138e3f55237c587aa1d1901f529c3415afa7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c487f3899ff91d0a18a25647ffe10ae32dcf2cc0bf3b88aa524bb993bea749b271623b3be965970e56169bf5bd87afcc384bbf67c7f3b2b31be59bf64d45eff0
|
|
7
|
+
data.tar.gz: 2f52caa014b1fb9b66a228e1c557ba3daef0b3d220a392671880a46207fbcc71675e8184d34e2a25a7f88384e0faf88e5109baf6d4f0f584c2e7655ea026f31f
|
data/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
Binds command-line options to variables.
|
|
7
7
|
|
|
8
|
-
Extends command-line option analysis by wrapping an instance of standard [`OptionParser`](http://ruby-doc.org/stdlib-2.
|
|
8
|
+
Extends command-line option analysis by wrapping an instance of standard [`OptionParser`](http://ruby-doc.org/stdlib-2.3.1/libdoc/optparse/rdoc/OptionParser.html).
|
|
9
9
|
Enables binding of options and arguments to instance or local variables. Provides `Hash` and `String` only interfaces
|
|
10
10
|
to define command line options, unlike a mixed interface by standard library. Supports access to default values and
|
|
11
11
|
partial argument analysis. Builds Git-like options and help by default.
|
|
@@ -21,7 +21,7 @@ Bind local variables to `ARGV` and parse command line arguments:
|
|
|
21
21
|
```ruby
|
|
22
22
|
require 'optbind'
|
|
23
23
|
|
|
24
|
-
ARGV #=> ['--no-verbose', '-o', 'file.out', 'file.in']
|
|
24
|
+
ARGV #=> ['--no-verbose', '-o', 'file.out', 'file.in']
|
|
25
25
|
|
|
26
26
|
i, o, v = STDIN, STDOUT, true
|
|
27
27
|
|
|
@@ -33,11 +33,191 @@ ARGV.bind_and_parse! to: :locals do
|
|
|
33
33
|
arg 'i [<file>]'
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
ARGV #=> []
|
|
37
|
+
|
|
36
38
|
[i, o, v] #=> ['file.in', 'file.out', false]
|
|
37
39
|
```
|
|
38
40
|
|
|
41
|
+
Use `bind` or one of its aliases on `ARGV` instead of `bind_and_parse!` to be able to `parse!` command line arguments later:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
ARGV.bind to: :locals do
|
|
45
|
+
# ...
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
ARGV.parse!
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Create an `OptionBinder` and use it directly:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
binder = OptionBinder.new do
|
|
55
|
+
# ...
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
binder.parse! ARGV
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Note that plain `OptionBinder.new` binds to local variables of top level binding object by default.
|
|
62
|
+
|
|
39
63
|
See specs for more examples and details on usage.
|
|
40
64
|
|
|
65
|
+
### Bindings
|
|
66
|
+
|
|
67
|
+
Various binding possibilities include:
|
|
68
|
+
|
|
69
|
+
#### Bind to `Hash` object
|
|
70
|
+
|
|
71
|
+
Create target:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
options = { input: STDIN, output: STDOUT }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Use `OptionBinder` directly:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
OptionBinder.new(target: options) do
|
|
81
|
+
# ...
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Use `ARGV` shortcut:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
ARGV.define_and_bind(to: options) do
|
|
89
|
+
# ...
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Bind to public accessors
|
|
94
|
+
|
|
95
|
+
Create target:
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
class Options
|
|
99
|
+
attr_accessor :input, :output
|
|
100
|
+
|
|
101
|
+
def initialize
|
|
102
|
+
@input, @output = STDIN, STDOUT
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Use `OptionBinder` directly:
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
OptionBinder.new(target: options) do
|
|
111
|
+
# ...
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Use `ARGV` shortcut:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
ARGV.define_and_bind(to: options) do
|
|
119
|
+
# ...
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Bind to class variables
|
|
124
|
+
|
|
125
|
+
Create target:
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
class Options
|
|
129
|
+
@@input, @@output = STDIN, STDOUT
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
options = Options.new
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Use `OptionBinder` directly:
|
|
136
|
+
|
|
137
|
+
```ruby
|
|
138
|
+
OptionBinder.new(target: options, bind: :to_class_variables) do
|
|
139
|
+
# ...
|
|
140
|
+
end
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Use `ARGV` shortcut:
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
ARGV.define_and_bind(to: options, via: :class_variables) do
|
|
147
|
+
# ...
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Bind to instance variables
|
|
152
|
+
|
|
153
|
+
Create target:
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
class Options
|
|
157
|
+
def initialize
|
|
158
|
+
@input, @output = STDIN, STDOUT
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
options = Options.new
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Use `OptionBinder` directly:
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
OptionBinder.new(target: options, bind: :to_instance_variables) do
|
|
169
|
+
# ...
|
|
170
|
+
end
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Use `ARGV` shortcut:
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
ARGV.define_and_bind(to: options, via: :instance_variables) do
|
|
177
|
+
# ...
|
|
178
|
+
end
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### Bind to local variables
|
|
182
|
+
|
|
183
|
+
Create target:
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
input, output = STDIN, STDOUT
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Use `OptionBinder` directly:
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
OptionBinder.new(target: TOPLEVEL_BINDING, bind: :to_local_variables) do
|
|
193
|
+
# ...
|
|
194
|
+
end
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Use `OptionBinder` directly with top level binding object as target by default:
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
OptionBinder.new do
|
|
201
|
+
# ...
|
|
202
|
+
end
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Use `ARGV` shortcut:
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
ARGV.define_and_bind(to: TOPLEVEL_BINDING, via: :local_variables) do
|
|
209
|
+
# ...
|
|
210
|
+
end
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Use `ARGV` shortcut with top level binding object as target by default:
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
ARGV.define_and_bind(to: :locals) do
|
|
217
|
+
# ...
|
|
218
|
+
end
|
|
219
|
+
```
|
|
220
|
+
|
|
41
221
|
## Testing
|
|
42
222
|
|
|
43
223
|
bundle exec rspec
|
data/TODO.md
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
# TODOS
|
|
2
2
|
|
|
3
|
+
- move order and permute to separate package, required on demand
|
|
4
|
+
|
|
3
5
|
- `Switch#parser_opts_from_string` - support regexps with options, like `=<name:/[a-z]/i>`
|
|
4
6
|
- `Switch#parser_opts_from_string` - support ranges, like `=<indent:0..8>`
|
|
5
|
-
|
|
6
|
-
- add
|
|
7
|
-
- add
|
|
7
|
+
|
|
8
|
+
- add custom type definitions to separate package, required on demand
|
|
9
|
+
- add support for ranges on `OptionParser` level
|
|
10
|
+
|
|
11
|
+
- add optbind/handlers from extise as separate package, required on demand
|
|
12
|
+
- add optbind/defaults from extise as separate package, required on demand
|
|
13
|
+
|
|
8
14
|
- make optional extensions for `OptionParser` monkey-patching `make_switch` to support hash-or-string-exclusive arguments
|
|
9
15
|
|
|
10
16
|
# IDEAS
|
|
@@ -17,10 +23,7 @@ gems:
|
|
|
17
23
|
opt ??? enhances syntax see syntax def below
|
|
18
24
|
optargs supoort for args
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
- support arguments? consider ARGF
|
|
22
|
-
|
|
23
|
-
- bind API:
|
|
26
|
+
bind API:
|
|
24
27
|
must be uninvasive, i.e. must not affect #on in any way, must act as #parse, see example
|
|
25
28
|
ARGV, OptionParser (options)
|
|
26
29
|
example: ARGV.options { |o| o.on(...); o.bind ...; o.parse! }
|
data/lib/optbind/version.rb
CHANGED
data/lib/optbind.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'forwardable'
|
|
2
4
|
require 'optparse'
|
|
3
5
|
|
|
@@ -18,6 +20,8 @@ class OptionBinder
|
|
|
18
20
|
return -> (v) { target.local_variable_get v }, -> (v, x) { target.local_variable_set v, x }
|
|
19
21
|
when :to_instance_variables
|
|
20
22
|
return -> (v) { target.instance_variable_get "@#{v}" }, -> (v, x) { target.instance_variable_set "@#{v}", x }
|
|
23
|
+
when :to_class_variables
|
|
24
|
+
return -> (v) { target.class_variable_get "@@#{v}" }, -> (v, x) { target.class_variable_set "@@#{v}", x }
|
|
21
25
|
else
|
|
22
26
|
return -> (v) { target[v] }, -> (v, x) { target[v] = x } if target.respond_to? :[]
|
|
23
27
|
return -> (v) { target.public_send v }, -> (v, x) { target.public_send "#{v}=", x }
|
|
@@ -25,11 +29,14 @@ class OptionBinder
|
|
|
25
29
|
end
|
|
26
30
|
|
|
27
31
|
def resolve_parser(parser = nil)
|
|
28
|
-
parser
|
|
32
|
+
parser ||= OptionParser.new do |p|
|
|
29
33
|
p.define_singleton_method(:banner) { (b = super()) !~ /\AU/ ? b : "usage: #{program_name} [<options>]\n\n" }
|
|
30
|
-
p.define_singleton_method(:version) { super() || (defined?(::VERSION) && ::VERSION) }
|
|
31
34
|
p.define_singleton_method(:help) { super().gsub(/(-\S+)=\[/, '\1[=') << " -h, --help\n --version\n\n" }
|
|
32
35
|
end
|
|
36
|
+
parser.tap do |p|
|
|
37
|
+
p.program_name = ::PROGRAM if defined? ::PROGRAM
|
|
38
|
+
p.version = ::VERSION if defined? ::VERSION
|
|
39
|
+
end
|
|
33
40
|
end
|
|
34
41
|
|
|
35
42
|
private :resolve_binding, :resolve_parser
|
|
@@ -40,8 +47,12 @@ class OptionBinder
|
|
|
40
47
|
def_delegators :@parser, :abort, :warn
|
|
41
48
|
def_delegators :@parser, :load
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
def parse(argv)
|
|
51
|
+
parse!(argv.dup) and argv
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def parse!(argv)
|
|
55
|
+
parse_args! @parser.parse! argv
|
|
45
56
|
end
|
|
46
57
|
|
|
47
58
|
def_delegators :@parser, :to_a, :to_s
|
|
@@ -54,10 +65,10 @@ class OptionBinder
|
|
|
54
65
|
line = (args * ' ') << "\n"
|
|
55
66
|
|
|
56
67
|
if @parser.banner =~ /\Ausage:.+\n\n/i
|
|
57
|
-
@parser.banner = "usage: #{program} "
|
|
68
|
+
@parser.banner = "usage: #{program} #{line}"
|
|
58
69
|
@parser.separator "\n"
|
|
59
70
|
else
|
|
60
|
-
@parser.banner
|
|
71
|
+
@parser.banner += " or: #{program} #{line}"
|
|
61
72
|
end
|
|
62
73
|
|
|
63
74
|
self
|
|
@@ -69,14 +80,11 @@ class OptionBinder
|
|
|
69
80
|
opts, handler, bound, variable, default = *several_variants(*opts, &handler)
|
|
70
81
|
|
|
71
82
|
@parser.on(*opts) do |r|
|
|
72
|
-
if opts.include? :
|
|
73
|
-
a = opts.select { |o| o =~ /\A-/ }.sort_by { |o| o.length }[-1]
|
|
74
|
-
@parser.abort "missing argument: #{a}=" if !r || (r.respond_to?(:empty?) && r.empty?)
|
|
75
|
-
end
|
|
76
|
-
|
|
83
|
+
raise OptionParser::InvalidArgument if opts.include?(:REQUIRED) && (r.nil? || r.respond_to?(:empty?) && r.empty?)
|
|
77
84
|
handle! handler, r, bound, variable, default
|
|
78
85
|
end
|
|
79
86
|
|
|
87
|
+
(@option_definitions ||= []) << { opts: opts, handler: handler, bound: bound, variable: variable }
|
|
80
88
|
(@bound_variables_with_defaults ||= {})[variable] = default if bound
|
|
81
89
|
self
|
|
82
90
|
end
|
|
@@ -86,8 +94,9 @@ class OptionBinder
|
|
|
86
94
|
def argument(*opts, &handler)
|
|
87
95
|
opts, handler, bound, variable, default = *several_variants(*opts, &handler)
|
|
88
96
|
|
|
89
|
-
opts.
|
|
90
|
-
|
|
97
|
+
(@argument_parser ||= OptionParser.new).on(*(opts << "--#{(@argument_definitions || []).size}")) do |r|
|
|
98
|
+
raise OptionParser::InvalidArgument if opts.include?(:REQUIRED) && (r.nil? || r.respond_to?(:empty?) && r.empty?)
|
|
99
|
+
handle! handler, r, bound, variable, default
|
|
91
100
|
end
|
|
92
101
|
|
|
93
102
|
(@argument_definitions ||= []) << { opts: opts, handler: handler, bound: bound, variable: variable }
|
|
@@ -118,12 +127,12 @@ class OptionBinder
|
|
|
118
127
|
end
|
|
119
128
|
|
|
120
129
|
def bound?(v)
|
|
121
|
-
(@bound_variables_with_defaults || {}).
|
|
130
|
+
(@bound_variables_with_defaults || {}).key? v.to_sym
|
|
122
131
|
end
|
|
123
132
|
|
|
124
133
|
def assigned?(v)
|
|
125
134
|
return nil unless bound? v
|
|
126
|
-
(@assigned_variables_with_values || {}).
|
|
135
|
+
(@assigned_variables_with_values || {}).key? v.to_sym
|
|
127
136
|
end
|
|
128
137
|
|
|
129
138
|
module Switch
|
|
@@ -151,9 +160,9 @@ class OptionBinder
|
|
|
151
160
|
end
|
|
152
161
|
|
|
153
162
|
def self.parser_opts_from_string(string = '', &handler)
|
|
154
|
-
shorts, longs = [], []
|
|
163
|
+
string, shorts, longs = string.dup, [], []
|
|
155
164
|
|
|
156
|
-
while string.sub!(/\A(?:(?<short>-\w)\s+)/, '')
|
|
165
|
+
while string.sub!(/\A(?:(?<short>-\w)\s+)/, '') do
|
|
157
166
|
shorts << $~[:short]
|
|
158
167
|
end
|
|
159
168
|
|
|
@@ -164,6 +173,7 @@ class OptionBinder
|
|
|
164
173
|
next unless $~[:argument]
|
|
165
174
|
argument = $~[:argument]
|
|
166
175
|
style = argument =~ /\A=?[<(]/ ? :REQUIRED : :OPTIONAL
|
|
176
|
+
pattern = Array if argument =~ /\.{3}\]?\z/
|
|
167
177
|
values = $~[:values].split('|') if argument =~ /(?:\[?=?|=\[)\((?<values>\S*)\)\]?/
|
|
168
178
|
|
|
169
179
|
if values.nil? && argument =~ /(?:\[?=?|=\[)<(?<name>\S+):(?<pattern>\S+)>\]?/
|
|
@@ -203,25 +213,36 @@ class OptionBinder
|
|
|
203
213
|
|
|
204
214
|
private :several_variants
|
|
205
215
|
|
|
206
|
-
|
|
207
|
-
|
|
216
|
+
class MissingArguments < OptionParser::ParseError
|
|
217
|
+
const_set :Reason, 'missing arguments'
|
|
218
|
+
alias_method :message, :reason
|
|
219
|
+
alias_method :to_s, :reason
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
class TooManyArguments < OptionParser::ParseError
|
|
223
|
+
const_set :Reason, 'too many arguments'
|
|
224
|
+
alias_method :message, :reason
|
|
225
|
+
alias_method :to_s, :reason
|
|
208
226
|
end
|
|
209
227
|
|
|
210
228
|
def parse_args!(argv)
|
|
211
|
-
return argv unless @
|
|
212
|
-
@argument_definitions.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
229
|
+
return argv unless @argument_parser
|
|
230
|
+
k = @argument_definitions.find_index { |a| a[:opts].include? Array }
|
|
231
|
+
p = k ? argv[0...k].map { |r| [r] } << argv[k..-1] : argv.map { |r| [r] }
|
|
232
|
+
p = (p.empty? ? p << [] : p).each_with_index.map do |r, i|
|
|
233
|
+
a = @argument_definitions[i]
|
|
234
|
+
raise TooManyArguments unless a
|
|
235
|
+
raise MissingArguments if a[:opts].include?(:REQUIRED) && r.empty?
|
|
236
|
+
"--#{i}=#{r * ','}" if a[:opts].include?(:REQUIRED) || !(r.empty? || r.find(&:empty?))
|
|
219
237
|
end
|
|
220
|
-
@
|
|
238
|
+
@argument_parser.order! p
|
|
239
|
+
argv.shift argv.size - p.size
|
|
221
240
|
argv
|
|
241
|
+
rescue OptionParser::InvalidArgument
|
|
242
|
+
raise $!.tap { |e| e.args[0] = e.args[0].sub(/\A--\d+=/, '') }
|
|
222
243
|
end
|
|
223
244
|
|
|
224
|
-
private :parse_args
|
|
245
|
+
private :parse_args!
|
|
225
246
|
|
|
226
247
|
def handle!(handler, raw, bound, variable, default)
|
|
227
248
|
(handler || -> (r) { r }).call(raw == nil ? default : raw).tap do |x|
|
|
@@ -264,9 +285,14 @@ class OptionBinder
|
|
|
264
285
|
alias_method :define_and_bind, :binder
|
|
265
286
|
alias_method :bind, :binder
|
|
266
287
|
|
|
288
|
+
def define_and_parse(opts = {}, &blk)
|
|
289
|
+
define(opts, &blk) and parse
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
alias_method :bind_and_parse, :define_and_parse
|
|
293
|
+
|
|
267
294
|
def define_and_parse!(opts = {}, &blk)
|
|
268
|
-
define
|
|
269
|
-
parse!
|
|
295
|
+
define(opts, &blk) and parse!
|
|
270
296
|
end
|
|
271
297
|
|
|
272
298
|
alias_method :bind_and_parse!, :define_and_parse!
|
|
@@ -275,12 +301,8 @@ class OptionBinder
|
|
|
275
301
|
self.options
|
|
276
302
|
end
|
|
277
303
|
|
|
278
|
-
def
|
|
279
|
-
binder.
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
def permute!
|
|
283
|
-
binder.permute! self
|
|
304
|
+
def parse
|
|
305
|
+
binder.parse self
|
|
284
306
|
end
|
|
285
307
|
|
|
286
308
|
def parse!
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: optbind
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pavol Zbell
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-
|
|
11
|
+
date: 2016-05-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -72,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
72
72
|
version: '0'
|
|
73
73
|
requirements: []
|
|
74
74
|
rubyforge_project:
|
|
75
|
-
rubygems_version: 2.
|
|
75
|
+
rubygems_version: 2.5.1
|
|
76
76
|
signing_key:
|
|
77
77
|
specification_version: 4
|
|
78
78
|
summary: Binds command-line options to variables.
|