config_parser 0.5.4 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +9 -0
- data/README.rdoc +17 -7
- data/lib/config_parser.rb +60 -59
- data/lib/config_parser/flag.rb +49 -37
- data/lib/config_parser/list.rb +12 -12
- data/lib/config_parser/option.rb +10 -10
- data/lib/config_parser/switch.rb +9 -9
- data/lib/config_parser/utils.rb +28 -31
- data/lib/config_parser/version.rb +1 -1
- metadata +4 -4
data/History.rdoc
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.5.5 / 2011-07-18
|
2
|
+
|
3
|
+
* [issue #3] added options to to_s to allow changes to the option/desc columns
|
4
|
+
widths
|
5
|
+
* [issue #4] made parser check for option_break such that breaks on non-option
|
6
|
+
args is possible
|
7
|
+
* [issue #5] single-character keys now default to a short rather than long
|
8
|
+
option
|
9
|
+
|
1
10
|
== 0.5.4 / 2011-07-11
|
2
11
|
|
3
12
|
Misc cleanup to the README and project structure. Also:
|
data/README.rdoc
CHANGED
@@ -20,10 +20,10 @@ Define options and their default values using +add+:
|
|
20
20
|
parser.add :switch, true # true makes a --[no-]switch
|
21
21
|
parser.add :flag, false # false as a default makes a --flag
|
22
22
|
parser.add :list, [] # an array makes a list-style option
|
23
|
-
|
23
|
+
|
24
24
|
parser.parse 'a b --flag --list x --list y,z c'
|
25
25
|
# => ['a', 'b', 'c']
|
26
|
-
|
26
|
+
|
27
27
|
parser.config
|
28
28
|
# => {
|
29
29
|
# :option => 'default',
|
@@ -64,19 +64,19 @@ to the option (although by default it does). As you may expect a block can be
|
|
64
64
|
given to process values before they are set as configs.
|
65
65
|
|
66
66
|
parser = ConfigParser.new
|
67
|
-
|
67
|
+
|
68
68
|
# use args to define the option
|
69
69
|
parser.add(:x, nil, '-o', '--one')
|
70
|
-
|
70
|
+
|
71
71
|
# use an options hash to define the option
|
72
72
|
parser.add(:y, nil, :short => 't', :long => 'two')
|
73
|
-
|
73
|
+
|
74
74
|
# use a block to process the values
|
75
75
|
parser.add(:z, nil, :long => 'three') {|value| value.upcase }
|
76
|
-
|
76
|
+
|
77
77
|
parser.parse('a b --one uno --two dos --three tres c')
|
78
78
|
# => ['a', 'b', 'c']
|
79
|
-
|
79
|
+
|
80
80
|
parser.config
|
81
81
|
# => {:x => 'uno', :y => 'dos', :z => 'TRES'}
|
82
82
|
|
@@ -86,6 +86,16 @@ ConfigParser is available as a gem[http://rubygems.org/gems/config_parser].
|
|
86
86
|
|
87
87
|
% gem install config_parser
|
88
88
|
|
89
|
+
== Development
|
90
|
+
|
91
|
+
To get started, checkout the code from GitHub[http://github.com/thinkerbot/config_parser] and run the tests:
|
92
|
+
|
93
|
+
git clone git://github.com/thinkerbot/config_parser.git
|
94
|
+
cd config_parser
|
95
|
+
rake test
|
96
|
+
|
97
|
+
Please report any issues {here}[http://github.com/thinkerbot/config_parser/issues].
|
98
|
+
|
89
99
|
== Info
|
90
100
|
|
91
101
|
Developer:: {Simon Chiang}[http://github.com/thinkerbot]
|
data/lib/config_parser.rb
CHANGED
@@ -8,27 +8,27 @@ autoload(:Shellwords, 'shellwords')
|
|
8
8
|
# additionally supports option declaration using an attributes hash.
|
9
9
|
class ConfigParser
|
10
10
|
include Utils
|
11
|
-
|
11
|
+
|
12
12
|
# Returns an array of the options registered with self, in the order in
|
13
13
|
# which they were added. Separators are also stored in the registry.
|
14
14
|
attr_reader :registry
|
15
|
-
|
15
|
+
|
16
16
|
# A hash of (flag, Option) pairs mapping command line flags like '-s' or
|
17
17
|
# '--long' to the Option that handles them.
|
18
18
|
attr_reader :options
|
19
|
-
|
19
|
+
|
20
20
|
# The hash receiving parsed configs.
|
21
21
|
attr_accessor :config
|
22
|
-
|
22
|
+
|
23
23
|
# The argument to stop processing options.
|
24
24
|
attr_accessor :option_break
|
25
|
-
|
25
|
+
|
26
26
|
# Set to true to preserve the option break.
|
27
27
|
attr_accessor :preserve_option_break
|
28
|
-
|
28
|
+
|
29
29
|
# Set to true to assign config defaults on parse.
|
30
30
|
attr_accessor :assign_defaults
|
31
|
-
|
31
|
+
|
32
32
|
# Initializes a new ConfigParser and passes it to the block, if given.
|
33
33
|
def initialize(config={}, opts={})
|
34
34
|
opts = {
|
@@ -36,27 +36,27 @@ class ConfigParser
|
|
36
36
|
:preserve_option_break => false,
|
37
37
|
:assign_defaults => true
|
38
38
|
}.merge(opts)
|
39
|
-
|
39
|
+
|
40
40
|
@registry = []
|
41
41
|
@options = {}
|
42
42
|
@config = config
|
43
43
|
@option_break = opts[:option_break]
|
44
44
|
@preserve_option_break = opts[:preserve_option_break]
|
45
45
|
@assign_defaults = opts[:assign_defaults]
|
46
|
-
|
46
|
+
|
47
47
|
yield(self) if block_given?
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
# Returns the config value for key.
|
51
51
|
def [](key)
|
52
52
|
config[key]
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
# Sets the config value for key.
|
56
56
|
def []=(key, value)
|
57
57
|
config[key] = value
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
# Adds a separator string to self, used in to_s.
|
61
61
|
def separator(str)
|
62
62
|
@registry << str
|
@@ -70,29 +70,29 @@ class ConfigParser
|
|
70
70
|
# no error is raised. Note that this may remove multiple options.
|
71
71
|
def register(option, override=false)
|
72
72
|
return nil if option.nil?
|
73
|
-
|
73
|
+
|
74
74
|
if override
|
75
75
|
existing = option.flags.collect {|flag| @options.delete(flag) }
|
76
76
|
@registry -= existing
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
unless @registry.include?(option)
|
80
80
|
@registry << option
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
option.flags.each do |flag|
|
84
84
|
current = @options[flag]
|
85
|
-
|
85
|
+
|
86
86
|
if current && current != option
|
87
87
|
raise ArgumentError, "already mapped to a different option: #{flag}"
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
@options[flag] = option
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
option
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
# Unregisters the option by removing it from the registry and options.
|
97
97
|
# Returns option.
|
98
98
|
def unregister(option)
|
@@ -100,16 +100,16 @@ class ConfigParser
|
|
100
100
|
@options.delete_if {|key, value| option == value }
|
101
101
|
option
|
102
102
|
end
|
103
|
-
|
103
|
+
|
104
104
|
# Sorts options in the registry as specified by the block. Groups of
|
105
105
|
# options as delimited by separators are sorted independently. If no block
|
106
106
|
# is given, options are sorted by their long and short keys.
|
107
107
|
def sort_opts!(&block)
|
108
108
|
block ||= lambda {|option| (option.long || option.short).to_s.sub(/^-+/, '') }
|
109
|
-
|
109
|
+
|
110
110
|
splits = []
|
111
111
|
current = []
|
112
|
-
|
112
|
+
|
113
113
|
options = self.options.values.uniq
|
114
114
|
registry.each do |option|
|
115
115
|
if options.include?(option)
|
@@ -120,14 +120,14 @@ class ConfigParser
|
|
120
120
|
current = []
|
121
121
|
end
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
splits << current
|
125
125
|
@registry = splits.collect {|split| split.kind_of?(Array) ? split.sort_by(&block) : split }
|
126
126
|
@registry.flatten!
|
127
|
-
|
127
|
+
|
128
128
|
self
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
# Constructs an Option using args and registers it with self. The args may
|
132
132
|
# contain (in any order) a short switch, a long switch, and a description
|
133
133
|
# string. A callback may be provided as a block to process values for the
|
@@ -183,12 +183,12 @@ class ConfigParser
|
|
183
183
|
def on(*args, &block)
|
184
184
|
register new_option(args, &block)
|
185
185
|
end
|
186
|
-
|
186
|
+
|
187
187
|
# Same as on, but overrides options with overlapping flags.
|
188
188
|
def on!(*args, &block)
|
189
189
|
register new_option(args, &block), true
|
190
190
|
end
|
191
|
-
|
191
|
+
|
192
192
|
# An alternate syntax for on, where the key and default attributes are set
|
193
193
|
# by the first two args. Like on, add can define option attributes using a
|
194
194
|
# series of args or with a trailing hash.
|
@@ -204,7 +204,7 @@ class ConfigParser
|
|
204
204
|
args << attrs
|
205
205
|
on(*args, &block)
|
206
206
|
end
|
207
|
-
|
207
|
+
|
208
208
|
# Removes options by key. Any options with the specified key are removed.
|
209
209
|
# Returns the removed options.
|
210
210
|
def rm(key)
|
@@ -216,7 +216,7 @@ class ConfigParser
|
|
216
216
|
end
|
217
217
|
end.compact
|
218
218
|
end
|
219
|
-
|
219
|
+
|
220
220
|
# Parses options from argv in a non-destructive manner. Parsing stops if an
|
221
221
|
# argument matching option_break is reached. If preserve_option_break is
|
222
222
|
# specified then the option break is preserved in the remaining arguments.
|
@@ -228,90 +228,91 @@ class ConfigParser
|
|
228
228
|
argv = argv.dup unless argv.kind_of?(String)
|
229
229
|
parse!(argv, &block)
|
230
230
|
end
|
231
|
-
|
231
|
+
|
232
232
|
# Same as parse, but removes parsed args from argv.
|
233
233
|
def parse!(argv=ARGV)
|
234
234
|
argv = Shellwords.shellwords(argv) if argv.kind_of?(String)
|
235
|
-
|
235
|
+
|
236
236
|
registry.each do |option|
|
237
237
|
if assign_defaults && option.respond_to?(:assign_default)
|
238
238
|
option.assign_default(config)
|
239
239
|
end
|
240
240
|
end
|
241
|
-
|
241
|
+
|
242
242
|
args = []
|
243
243
|
while !argv.empty?
|
244
244
|
arg = argv.shift
|
245
|
-
|
246
|
-
# determine if the arg is an option
|
247
|
-
unless option?(arg)
|
248
|
-
args << arg
|
249
|
-
next
|
250
|
-
end
|
251
|
-
|
245
|
+
|
252
246
|
# add the remaining args and break
|
253
247
|
# for the option break
|
254
248
|
if option_break === arg
|
255
249
|
argv.unshift(arg) if preserve_option_break
|
256
250
|
break
|
257
251
|
end
|
258
|
-
|
252
|
+
|
253
|
+
# determine if the arg is an option
|
254
|
+
unless option?(arg)
|
255
|
+
args << arg
|
256
|
+
next
|
257
|
+
end
|
258
|
+
|
259
259
|
flag, value = arg, nil
|
260
|
-
|
260
|
+
|
261
261
|
# try the flag directly
|
262
262
|
unless option = @options[flag]
|
263
|
-
|
263
|
+
|
264
264
|
# then try --opt=value syntax
|
265
265
|
flag, value = flag.split('=', 2)
|
266
|
-
|
266
|
+
|
267
267
|
# then try -ovalue syntax
|
268
268
|
if value.nil? && flag[1] != ?-
|
269
269
|
flag, value = flag[0, 2], flag[2, flag.length - 2]
|
270
270
|
end
|
271
|
-
|
271
|
+
|
272
272
|
unless option = @options[flag]
|
273
273
|
raise "unknown option: #{flag}"
|
274
274
|
end
|
275
275
|
end
|
276
|
-
|
276
|
+
|
277
277
|
option.parse(flag, value, argv, config)
|
278
278
|
end
|
279
|
-
|
279
|
+
|
280
280
|
args.concat(argv)
|
281
281
|
argv.replace(args)
|
282
|
-
|
282
|
+
|
283
283
|
block_given? ? yield(argv, config) : argv
|
284
284
|
end
|
285
|
-
|
285
|
+
|
286
286
|
# Resets each option and clears the config (if specified). Returns self.
|
287
287
|
def reset(options={})
|
288
288
|
options = {
|
289
289
|
:clear => true
|
290
290
|
}.merge(options)
|
291
|
-
|
291
|
+
|
292
292
|
registry.each do |option|
|
293
293
|
if option.respond_to?(:reset)
|
294
294
|
option.reset
|
295
295
|
end
|
296
296
|
end
|
297
|
-
|
297
|
+
|
298
298
|
config.clear if options[:clear]
|
299
299
|
self
|
300
300
|
end
|
301
|
-
|
301
|
+
|
302
302
|
# Converts the options and separators in self into a help string suitable
|
303
303
|
# for display on the command line.
|
304
|
-
def to_s
|
304
|
+
def to_s(opts={})
|
305
305
|
@registry.collect do |option|
|
306
|
-
option.to_s.
|
306
|
+
str = option.kind_of?(Flag) ? option.to_s(opts) : option.to_s
|
307
|
+
str.rstrip
|
307
308
|
end.join("\n") + "\n"
|
308
309
|
end
|
309
|
-
|
310
|
+
|
310
311
|
protected
|
311
|
-
|
312
|
+
|
312
313
|
def option_class(attrs) # :nodoc:
|
313
314
|
type = attrs[:option_type] || guess_option_type(attrs)
|
314
|
-
|
315
|
+
|
315
316
|
case type
|
316
317
|
when :option then Option
|
317
318
|
when :flag then Flag
|
@@ -321,16 +322,16 @@ class ConfigParser
|
|
321
322
|
else raise "unknown option type: #{type}"
|
322
323
|
end
|
323
324
|
end
|
324
|
-
|
325
|
+
|
325
326
|
# helper to parse an option from an argv. new_option is used
|
326
327
|
# by on and on! to generate options
|
327
328
|
def new_option(argv, &block) # :nodoc:
|
328
329
|
attrs = argv.last.kind_of?(Hash) ? argv.pop : {}
|
329
330
|
attrs = parse_attrs(argv).merge(attrs)
|
330
|
-
|
331
|
+
|
331
332
|
attrs[:hint] ||= guess_hint(attrs)
|
332
333
|
attrs[:callback] = block if block
|
333
|
-
|
334
|
+
|
334
335
|
option_class(attrs).new(attrs)
|
335
336
|
end
|
336
337
|
end
|
data/lib/config_parser/flag.rb
CHANGED
@@ -1,59 +1,59 @@
|
|
1
1
|
require 'config_parser/utils'
|
2
2
|
|
3
3
|
class ConfigParser
|
4
|
-
|
4
|
+
|
5
5
|
# Represents a boolean flag-style option. Flag handles the parsing of
|
6
6
|
# specific flags, and provides hooks for processing the various types of
|
7
7
|
# options (Switch, Option, List).
|
8
8
|
class Flag
|
9
9
|
include Utils
|
10
|
-
|
10
|
+
|
11
11
|
# The config key.
|
12
12
|
attr_reader :key
|
13
|
-
|
13
|
+
|
14
14
|
# The config nesting keys.
|
15
15
|
attr_reader :nest_keys
|
16
|
-
|
16
|
+
|
17
17
|
# The default value.
|
18
18
|
attr_reader :default
|
19
|
-
|
19
|
+
|
20
20
|
# The short flag mapping to self.
|
21
21
|
attr_reader :short
|
22
|
-
|
22
|
+
|
23
23
|
# The long flag mapping to self.
|
24
24
|
attr_reader :long
|
25
|
-
|
25
|
+
|
26
26
|
# The description printed by to_s.
|
27
27
|
attr_reader :desc
|
28
|
-
|
28
|
+
|
29
29
|
# A hint printed by to_s, after desc.
|
30
30
|
attr_reader :hint
|
31
|
-
|
31
|
+
|
32
32
|
# A callback for processing values (must respond to call, or be nil).
|
33
33
|
attr_reader :callback
|
34
|
-
|
34
|
+
|
35
35
|
# A tracking flag set to true when assign is called. Useful when assign
|
36
36
|
# works differently for the first assignment than later assignments. See
|
37
37
|
# reset.
|
38
38
|
attr_reader :assigned
|
39
|
-
|
39
|
+
|
40
40
|
def initialize(attrs={})
|
41
41
|
@key = attrs[:key]
|
42
42
|
@nest_keys = attrs[:nest_keys]
|
43
43
|
@default = attrs[:default]
|
44
|
-
@short = shortify(attrs[:short])
|
44
|
+
@short = shortify(attrs.has_key?(:short) ? attrs[:short] : default_short)
|
45
45
|
@long = longify(attrs.has_key?(:long) ? attrs[:long] : default_long)
|
46
46
|
@desc = attrs[:desc]
|
47
47
|
@hint = attrs[:hint]
|
48
48
|
@callback = attrs[:callback]
|
49
49
|
reset
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
# Returns an array of flags mapping to self (ie [long, short]).
|
53
53
|
def flags
|
54
54
|
[long, short].compact
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
# Parse handles the parsing of flags, which happens in three steps:
|
58
58
|
#
|
59
59
|
# * determine the value (occurs in parse)
|
@@ -95,17 +95,17 @@ class ConfigParser
|
|
95
95
|
raise "value specified for #{flag}: #{value.inspect}"
|
96
96
|
end
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
value = (default.nil? ? true : !default)
|
100
100
|
assign(config, process(value))
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
# Process the value by calling the callback, if specified, with the value
|
104
104
|
# and returns the result. Returns value if no callback is specified.
|
105
105
|
def process(value)
|
106
106
|
callback ? callback.call(value) : value
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
# Assigns the default value into config and resets the assigned flag to
|
110
110
|
# false, such that the next assign behaves as if self has not put a value
|
111
111
|
# into config. Returns config.
|
@@ -114,7 +114,7 @@ class ConfigParser
|
|
114
114
|
reset
|
115
115
|
config
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
# Assign the value to the config hash, if key is set, and flips assigned
|
119
119
|
# to true. Returns config.
|
120
120
|
def assign(config, value)
|
@@ -122,51 +122,58 @@ class ConfigParser
|
|
122
122
|
nest_config = nest(config)
|
123
123
|
nest_config[key] = value
|
124
124
|
end
|
125
|
-
|
125
|
+
|
126
126
|
@assigned = true
|
127
127
|
config
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
# Returns the nested config hash for config, as specified by nest_keys.
|
131
131
|
def nest(config)
|
132
132
|
nest_keys.each do |key|
|
133
133
|
config = (config[key] ||= {})
|
134
134
|
end if nest_keys
|
135
|
-
|
135
|
+
|
136
136
|
config
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
# Resets assigned to false.
|
140
140
|
def reset
|
141
141
|
@assigned = false
|
142
142
|
end
|
143
|
-
|
144
|
-
# Formats self as a help string for use on the command line
|
145
|
-
|
146
|
-
|
147
|
-
|
143
|
+
|
144
|
+
# Formats self as a help string for use on the command line (deprecated
|
145
|
+
# for that use, see format instead).
|
146
|
+
def to_s(opts={})
|
147
|
+
width = opts[:width] || 80
|
148
|
+
head_size = opts[:head_size] || (width * 0.45).to_i
|
149
|
+
desc_size = width - head_size - 1
|
150
|
+
|
151
|
+
format = "%-#{head_size}s %-#{desc_size}s"
|
152
|
+
|
153
|
+
lines = wrap(desc_str, desc_size)
|
154
|
+
|
148
155
|
header = header_str
|
149
|
-
header = header.length >
|
150
|
-
|
156
|
+
header = header.length > head_size ? header.ljust(width) : (format % [header, lines.shift])
|
157
|
+
|
151
158
|
if lines.empty?
|
152
159
|
header
|
153
160
|
else
|
154
|
-
lines.collect! {|line|
|
161
|
+
lines.collect! {|line| format % [nil, line] }
|
155
162
|
"#{header}\n#{lines.join("\n")}"
|
156
163
|
end
|
157
164
|
end
|
158
|
-
|
165
|
+
|
159
166
|
# Returns an inspect string.
|
160
167
|
def inspect
|
161
168
|
"#<#{self.class}:#{object_id} key=#{key.inspect} default=#{default.inspect} long=#{long.inspect} short=#{short.inspect}>"
|
162
169
|
end
|
163
|
-
|
170
|
+
|
164
171
|
private
|
165
|
-
|
172
|
+
|
166
173
|
def header_str # :nodoc:
|
167
174
|
" #{short_str}#{long_str}"
|
168
175
|
end
|
169
|
-
|
176
|
+
|
170
177
|
def short_str # :nodoc:
|
171
178
|
case
|
172
179
|
when short && long then "#{short}, "
|
@@ -174,11 +181,11 @@ class ConfigParser
|
|
174
181
|
else ' '
|
175
182
|
end
|
176
183
|
end
|
177
|
-
|
184
|
+
|
178
185
|
def long_str # :nodoc:
|
179
186
|
long
|
180
187
|
end
|
181
|
-
|
188
|
+
|
182
189
|
def desc_str # :nodoc:
|
183
190
|
case
|
184
191
|
when hint.nil? && desc.nil?
|
@@ -189,9 +196,14 @@ class ConfigParser
|
|
189
196
|
"#{desc} (#{hint})".strip
|
190
197
|
end
|
191
198
|
end
|
192
|
-
|
199
|
+
|
193
200
|
def default_long # :nodoc:
|
201
|
+
return nil if default_short
|
194
202
|
nest_keys ? (nest_keys + [key]).join(':') : key
|
195
203
|
end
|
204
|
+
|
205
|
+
def default_short # :nodoc:
|
206
|
+
key.to_s.length == 1 && nest_keys.nil? ? key : nil
|
207
|
+
end
|
196
208
|
end
|
197
209
|
end
|
data/lib/config_parser/list.rb
CHANGED
@@ -1,46 +1,46 @@
|
|
1
1
|
require 'config_parser/option'
|
2
2
|
|
3
3
|
class ConfigParser
|
4
|
-
|
4
|
+
|
5
5
|
# List represents a special type of Option where multiple values may be
|
6
6
|
# assigned to the same key.
|
7
7
|
class List < Option
|
8
|
-
|
8
|
+
|
9
9
|
# The delimiter on which to split single values into multiple values; use
|
10
10
|
# nil to prevent splitting.
|
11
11
|
attr_reader :delimiter
|
12
|
-
|
12
|
+
|
13
13
|
def initialize(attrs={})
|
14
14
|
super
|
15
|
-
|
15
|
+
|
16
16
|
@delimiter = attrs.has_key?(:delimiter) ? attrs[:delimiter] : DELIMITER
|
17
17
|
@default = split(@default)
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
# Splits the value into multiple values, and then process as usual.
|
21
21
|
def process(value)
|
22
22
|
split(value).collect {|val| super(val) }
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
# Assigns the values to config. Multiple calls to assign will concatenate
|
26
26
|
# (ie when assigned is true) new values onto the existing values. As
|
27
27
|
# usual, no values are assigned if key is not set. Returns config.
|
28
28
|
def assign(config, values)
|
29
29
|
if key
|
30
30
|
nest_config = nest(config)
|
31
|
-
|
31
|
+
|
32
32
|
unless assigned
|
33
33
|
nest_config[key] = []
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
array = (nest_config[key] ||= [])
|
37
37
|
array.concat(values)
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
@assigned = true
|
41
41
|
config
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
# Splits string values along the delimiter, if specified. Returns array
|
45
45
|
# values directly, and an empty array for nil. All other values are
|
46
46
|
# arrayified like [obj].
|
@@ -52,9 +52,9 @@ class ConfigParser
|
|
52
52
|
else [obj]
|
53
53
|
end
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
private
|
57
|
-
|
57
|
+
|
58
58
|
def header_str # :nodoc:
|
59
59
|
" #{short_str}#{long_str} #{arg_name}..."
|
60
60
|
end
|
data/lib/config_parser/option.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
require 'config_parser/switch'
|
2
2
|
|
3
3
|
class ConfigParser
|
4
|
-
|
4
|
+
|
5
5
|
# An Option represents a Flag that takes a value.
|
6
6
|
class Option < Flag
|
7
|
-
|
7
|
+
|
8
8
|
# The default argument name
|
9
9
|
DEFAULT_ARGNAME = 'VALUE'
|
10
|
-
|
10
|
+
|
11
11
|
# Matches optional argnames
|
12
12
|
OPTIONAL = /\A\[.*\]\z/
|
13
|
-
|
13
|
+
|
14
14
|
# The argument name printed by to_s.
|
15
15
|
attr_reader :arg_name
|
16
|
-
|
16
|
+
|
17
17
|
# Set to true to make the argument optional.
|
18
18
|
attr_reader :optional
|
19
|
-
|
19
|
+
|
20
20
|
def initialize(attrs={})
|
21
21
|
super
|
22
22
|
@arg_name = attrs[:arg_name] || (key ? key.to_s.upcase : DEFAULT_ARGNAME)
|
23
23
|
@optional = (attrs.has_key?(:optional) ? attrs[:optional] : (arg_name =~ OPTIONAL ? true : false))
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Parse the flag and value. If no value is provided and a value is
|
27
27
|
# required, then a value is shifted off of argv. The value is then
|
28
28
|
# processed and assigned into config.
|
@@ -36,12 +36,12 @@ class ConfigParser
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
assign(config, process(value))
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
private
|
44
|
-
|
44
|
+
|
45
45
|
def header_str # :nodoc:
|
46
46
|
" #{short_str}#{long_str} #{arg_name}"
|
47
47
|
end
|
data/lib/config_parser/switch.rb
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
require 'config_parser/flag'
|
2
2
|
|
3
3
|
class ConfigParser
|
4
|
-
|
4
|
+
|
5
5
|
# Switch represents a special type of Option where both positive (--flag)
|
6
6
|
# and negative (--no-flag) flags map to self.
|
7
7
|
class Switch < Flag
|
8
|
-
|
8
|
+
|
9
9
|
# The negative mapping prefix, defaults to 'no'
|
10
10
|
attr_reader :prefix
|
11
|
-
|
11
|
+
|
12
12
|
# The negative long flag, determined from long and prefix.
|
13
13
|
attr_reader :negative_long
|
14
|
-
|
14
|
+
|
15
15
|
def initialize(attrs={})
|
16
16
|
attrs[:default] = true unless attrs.has_key?(:default)
|
17
17
|
super
|
18
|
-
|
18
|
+
|
19
19
|
raise ArgumentError, "no long specified" unless long
|
20
20
|
@prefix = attrs[:prefix] || 'no'
|
21
21
|
@negative_long = prefix_long(long, "#{prefix}-")
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
# Returns an array of flags mapping to self (ie [long, negative_long, short]).
|
25
25
|
def flags
|
26
26
|
[long, negative_long, short].compact
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
# Assigns default into config for positive flags and !default for negative
|
30
30
|
# flags. The boolean value is then processed and assigned into config.
|
31
31
|
# Raises an error if a value is provided (switches take none).
|
32
32
|
def parse(flag, value=nil, argv=[], config={})
|
33
33
|
raise "value specified for #{flag}: #{value.inspect}" if value
|
34
|
-
|
34
|
+
|
35
35
|
value = (flag == negative_long ? !default : default)
|
36
36
|
assign(config, process(value))
|
37
37
|
end
|
38
38
|
|
39
39
|
private
|
40
|
-
|
40
|
+
|
41
41
|
def long_str # :nodoc:
|
42
42
|
prefix_long(long, "[#{prefix}-]")
|
43
43
|
end
|
data/lib/config_parser/utils.rb
CHANGED
@@ -1,24 +1,21 @@
|
|
1
1
|
class ConfigParser
|
2
|
-
|
2
|
+
|
3
3
|
# A medly of methods used throughout the ConfigParser classes.
|
4
4
|
module Utils
|
5
5
|
module_function
|
6
|
-
|
7
|
-
# A format string used by to_s
|
8
|
-
LINE_FORMAT = "%-36s %-43s"
|
9
|
-
|
6
|
+
|
10
7
|
# The default option break
|
11
8
|
OPTION_BREAK = "--"
|
12
|
-
|
9
|
+
|
13
10
|
# Matches an option (long or short)
|
14
11
|
OPTION = /\A-./
|
15
|
-
|
12
|
+
|
16
13
|
# Matches a long flag
|
17
14
|
LONG_FLAG = /\A--.+\z/
|
18
15
|
|
19
16
|
# Matches a short flag
|
20
17
|
SHORT_FLAG = /\A-.\z/
|
21
|
-
|
18
|
+
|
22
19
|
# Matches a switch option (ex: '--[no-]opt', '--nest:[no-]opt'). After the
|
23
20
|
# match:
|
24
21
|
#
|
@@ -27,17 +24,17 @@ class ConfigParser
|
|
27
24
|
# $3:: the long flag name ('opt')
|
28
25
|
#
|
29
26
|
SWITCH = /\A--(.*?)\[(.*?)-\](.+)\z/
|
30
|
-
|
27
|
+
|
31
28
|
# Matches a nest option (ex: '--nest:opt'). After the match:
|
32
29
|
#
|
33
30
|
# $1:: the nesting prefix ('nest')
|
34
31
|
# $2:: the long option ('long')
|
35
32
|
#
|
36
33
|
NEST = /\A--(.*):(.+)\z/
|
37
|
-
|
34
|
+
|
38
35
|
# The default split character for multiple values
|
39
36
|
DELIMITER = ','
|
40
|
-
|
37
|
+
|
41
38
|
# Turns the input into a short flag by prefixing '-' (as needed). Raises
|
42
39
|
# an error if the input doesn't result in a short flag. Nils are
|
43
40
|
# returned directly.
|
@@ -47,14 +44,14 @@ class ConfigParser
|
|
47
44
|
#
|
48
45
|
def shortify(str)
|
49
46
|
return nil if str.nil?
|
50
|
-
|
47
|
+
|
51
48
|
str = str.to_s
|
52
49
|
str = "-#{str}" unless option?(str)
|
53
|
-
|
50
|
+
|
54
51
|
unless str =~ SHORT_FLAG
|
55
52
|
raise ArgumentError, "invalid short flag: #{str}"
|
56
53
|
end
|
57
|
-
|
54
|
+
|
58
55
|
str
|
59
56
|
end
|
60
57
|
|
@@ -67,17 +64,17 @@ class ConfigParser
|
|
67
64
|
#
|
68
65
|
def longify(str)
|
69
66
|
return nil if str.nil?
|
70
|
-
|
67
|
+
|
71
68
|
str = str.to_s
|
72
69
|
str = "--#{str}" unless option?(str)
|
73
|
-
|
70
|
+
|
74
71
|
unless str =~ LONG_FLAG
|
75
72
|
raise ArgumentError, "invalid long flag: #{str}"
|
76
73
|
end
|
77
|
-
|
74
|
+
|
78
75
|
str
|
79
76
|
end
|
80
|
-
|
77
|
+
|
81
78
|
# Adds a prefix onto the last nested segment of a long option.
|
82
79
|
#
|
83
80
|
# prefix_long('--opt', 'no-') # => '--no-opt'
|
@@ -89,25 +86,25 @@ class ConfigParser
|
|
89
86
|
switch[-1] = "#{prefix}#{switch[-1]}"
|
90
87
|
"--#{switch.join(':')}"
|
91
88
|
end
|
92
|
-
|
89
|
+
|
93
90
|
# Returns true if the object is a string and matches OPTION.
|
94
91
|
def option?(obj)
|
95
92
|
obj.kind_of?(String) && obj =~ OPTION ? true : false
|
96
93
|
end
|
97
|
-
|
94
|
+
|
98
95
|
# Shifts and returns the first argument off of argv if it is an argument
|
99
96
|
# (rather than an option) or returns the default value.
|
100
97
|
def next_arg(argv)
|
101
98
|
option?(argv.at(0)) ? nil : argv.shift
|
102
99
|
end
|
103
|
-
|
100
|
+
|
104
101
|
# A wrapping algorithm slightly modified from:
|
105
102
|
# http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
|
106
103
|
def wrap(line, cols=80, tabsize=2)
|
107
104
|
line = line.gsub(/\t/, " " * tabsize) unless tabsize == nil
|
108
105
|
line.gsub(/(.{1,#{cols}})( +|$\r?\n?)|(.{1,#{cols}})/, "\\1\\3\n").split(/\s*?\n/)
|
109
106
|
end
|
110
|
-
|
107
|
+
|
111
108
|
# Parses the argv into an attributes hash for initializing an option.
|
112
109
|
# Heuristics are used to infer what an argument implies.
|
113
110
|
#
|
@@ -129,7 +126,7 @@ class ConfigParser
|
|
129
126
|
# arg_name with a switch) can be detected... others not so much.
|
130
127
|
def parse_attrs(argv)
|
131
128
|
attrs={}
|
132
|
-
|
129
|
+
|
133
130
|
argv.each do |arg|
|
134
131
|
unless option?(arg)
|
135
132
|
attrs[:desc] = arg
|
@@ -137,7 +134,7 @@ class ConfigParser
|
|
137
134
|
end
|
138
135
|
|
139
136
|
flag, arg_name = arg.split(/\s+/, 2)
|
140
|
-
|
137
|
+
|
141
138
|
if flag =~ NEST
|
142
139
|
attrs[:nest_keys] = $1.split(':')
|
143
140
|
end
|
@@ -150,7 +147,7 @@ class ConfigParser
|
|
150
147
|
when SWITCH
|
151
148
|
attrs[:long] = "--#{$1}#{$3}"
|
152
149
|
attrs[:prefix] = $2
|
153
|
-
|
150
|
+
|
154
151
|
if arg_name
|
155
152
|
raise ArgumentError, "arg_name specified for switch: #{arg_name}"
|
156
153
|
end
|
@@ -165,10 +162,10 @@ class ConfigParser
|
|
165
162
|
raise ArgumentError.new("invalid flag: #{arg.inspect}")
|
166
163
|
end
|
167
164
|
end
|
168
|
-
|
165
|
+
|
169
166
|
attrs
|
170
167
|
end
|
171
|
-
|
168
|
+
|
172
169
|
# Guesses an option type based on the attrs.
|
173
170
|
#
|
174
171
|
# if... then...
|
@@ -190,12 +187,12 @@ class ConfigParser
|
|
190
187
|
:flag
|
191
188
|
end
|
192
189
|
end
|
193
|
-
|
190
|
+
|
194
191
|
# Guesses :list if the arg_name has a comma, or nil.
|
195
192
|
def guess_option_type_by_arg_name(arg_name)
|
196
193
|
arg_name.to_s.include?(',') ? :list : nil
|
197
194
|
end
|
198
|
-
|
195
|
+
|
199
196
|
# Guesses an option type based on a value.
|
200
197
|
#
|
201
198
|
# if... then...
|
@@ -213,10 +210,10 @@ class ConfigParser
|
|
213
210
|
else :option
|
214
211
|
end
|
215
212
|
end
|
216
|
-
|
213
|
+
|
217
214
|
def guess_hint(attrs)
|
218
215
|
default = attrs[:default]
|
219
|
-
|
216
|
+
|
220
217
|
case default
|
221
218
|
when true, false, nil
|
222
219
|
nil
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: config_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 1
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
9
|
+
- 5
|
10
|
+
version: 0.5.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Simon Chiang
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-18 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|