optout 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +31 -8
- data/lib/optout.rb +238 -62
- data/spec/optout_spec.rb +369 -217
- metadata +9 -9
data/README.rdoc
CHANGED
@@ -20,7 +20,7 @@ arguments and define validation rules that must be met before the command line a
|
|
20
20
|
:gem => "rake",
|
21
21
|
:os => "mswin",
|
22
22
|
:version => "0.9.2",
|
23
|
-
:user =>
|
23
|
+
:user => truep
|
24
24
|
}
|
25
25
|
|
26
26
|
exec "gem", *optout.argv(options)
|
@@ -68,13 +68,30 @@ in a different format. +Optout+ accepts various configuration options that can r
|
|
68
68
|
optout = Optout.options do
|
69
69
|
on :path, "--path", :arg_separator => "=", :required => true
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
optout.shell(:path => "/home/sshaw")
|
73
73
|
# Returns: --path='/home/sshaw'
|
74
74
|
|
75
75
|
optout.shell({})
|
76
76
|
# Raises: Optout::OptionRequired
|
77
77
|
|
78
|
+
Options can be grouped into required and optional:
|
79
|
+
|
80
|
+
Optout.options :arg_separator => "=" do
|
81
|
+
required do
|
82
|
+
on :in, "if"
|
83
|
+
on :out, "of"
|
84
|
+
end
|
85
|
+
|
86
|
+
optional do
|
87
|
+
on :size, "size"
|
88
|
+
on :count, "count"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
optout.shell(:in => "/dev/zero", :out => "/var/log/secure")
|
93
|
+
# Returns: in='/dev/zero' out='/var/log/secure'
|
94
|
+
|
78
95
|
== Validating Options
|
79
96
|
|
80
97
|
+Optout+ can validate your options too. Just specify the validation rule after the option's key or switch:
|
@@ -85,7 +102,7 @@ in a different format. +Optout+ accepts various configuration options that can r
|
|
85
102
|
end
|
86
103
|
|
87
104
|
optout = Optout.options do
|
88
|
-
# Must be true, false, or nil
|
105
|
+
# Must be true, false, or nil (add :required => true to allow only true or false)
|
89
106
|
on :path, "-p", Optout::Boolean
|
90
107
|
end
|
91
108
|
|
@@ -95,20 +112,24 @@ in a different format. +Optout+ accepts various configuration options that can r
|
|
95
112
|
end
|
96
113
|
|
97
114
|
optout = Optout.options do
|
98
|
-
# Must be a diretory under "/
|
99
|
-
on :path, Optout::Dir.under("/home").permissions("
|
115
|
+
# Must be a diretory under "/home" and have user read and write permissions
|
116
|
+
on :path, Optout::Dir.under("/home").permissions("rw")
|
100
117
|
end
|
101
118
|
|
102
119
|
optout.shell(:path => "/root")
|
103
120
|
# Raises: Optout::OptionInvalid
|
104
121
|
|
105
|
-
|
122
|
+
== TODOs
|
123
|
+
|
124
|
+
* Proper <code>cmd.exe</code> quoting
|
125
|
+
* Mutually exclusive options
|
126
|
+
* Split options i.e., <code>:jvm => %w[A B C]</code> would be created as <code>-XA -XB -XC</code>
|
106
127
|
|
107
128
|
== More Info
|
108
129
|
|
109
130
|
=== RDoc
|
110
131
|
|
111
|
-
http://rubydoc.info/github/sshaw/optout/frames
|
132
|
+
http://rubydoc.info/github/sshaw/optout/frames (with RDoc -> YARD incompatibilities :)
|
112
133
|
|
113
134
|
=== Bugs
|
114
135
|
|
@@ -120,4 +141,6 @@ Skye Shaw [sshaw AT lucas.cis.temple.edu]
|
|
120
141
|
|
121
142
|
== License
|
122
143
|
|
123
|
-
|
144
|
+
Copyright (c) 2011-2012 Skye Shaw
|
145
|
+
|
146
|
+
Released under the MIT License: http://www.opensource.org/licenses/MIT
|
data/lib/optout.rb
CHANGED
@@ -2,7 +2,7 @@ require "rbconfig"
|
|
2
2
|
require "pathname"
|
3
3
|
|
4
4
|
class Optout
|
5
|
-
VERSION = "0.0.
|
5
|
+
VERSION = "0.0.2"
|
6
6
|
|
7
7
|
class OptionError < StandardError
|
8
8
|
attr :key
|
@@ -32,20 +32,26 @@ class Optout
|
|
32
32
|
|
33
33
|
class << self
|
34
34
|
##
|
35
|
-
# Define a set of options
|
35
|
+
# Define a set of options.
|
36
|
+
# After the options are defined call Optout#argv or Optout#shell to create them.
|
37
|
+
#
|
38
|
+
# optz = Optout.options config do
|
39
|
+
# on :key, "-switch", ValidationRule, :multiple => false, :required => true
|
40
|
+
# # ...
|
41
|
+
# end
|
36
42
|
#
|
37
43
|
# === Parameters
|
38
44
|
#
|
39
45
|
# [config (Hash)] Configuration options
|
40
|
-
# [
|
46
|
+
# [block (Proc)] Option definitions
|
41
47
|
#
|
42
48
|
# === Configuration Options
|
43
49
|
#
|
44
|
-
# [:arg_separator] Set the default for all subsequent options defined via
|
45
|
-
# [:check_keys] If +true+ an
|
50
|
+
# [:arg_separator] Set the default argument seperator (i.e., the char used to seperate a switch from its value) for all subsequent options defined via Optout#on.
|
51
|
+
# [:check_keys] If +true+ an +OptionUnknown+ error will be raised when the incoming option hash contains a key that has not been associated with an option via Optout#on.
|
46
52
|
# Defaults to +true+.
|
47
|
-
# [:multiple] Set the default for all subsequent options defined via +on+. See Optout#on
|
48
|
-
# [:required] Set the default for all subsequent options defined via +on+. See Optout#on
|
53
|
+
# [:multiple] Set the default for all subsequent options defined via +on+. See Optout#on.
|
54
|
+
# [:required] Set the default for all subsequent options defined via +on+. See Optout#on.
|
49
55
|
#
|
50
56
|
# === Errors
|
51
57
|
#
|
@@ -59,20 +65,20 @@ class Optout
|
|
59
65
|
# on :file, Optout::File.under("/home/sshaw"), :default => "/home/sshaw/tmp"
|
60
66
|
# end
|
61
67
|
#
|
62
|
-
# optz.shell(:all => true, :size => 1024, :file => "/home/sshaw/some file")
|
63
|
-
# # Creates: "-a -b '1024' '/home/sshaw/some file'
|
64
|
-
#
|
65
68
|
# optz = Optout.options :required => true, :check_keys => false do
|
66
|
-
# on :lib
|
69
|
+
# on :lib
|
67
70
|
# on :prefix, "--prefix" , %w{/sshaw/lib /sshaw/usr/lib}, :arg_separator => "="
|
68
71
|
# end
|
69
72
|
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
73
|
+
# # Same as above
|
74
|
+
# optz = Optout.options :check_keys => false do
|
75
|
+
# required do
|
76
|
+
# on :lib
|
77
|
+
# on :prefix, "--prefix" , %w{/sshaw/lib /sshaw/usr/lib}, :arg_separator => "="
|
78
|
+
# end
|
79
|
+
# end
|
74
80
|
#
|
75
|
-
|
81
|
+
|
76
82
|
def options(config = {}, &block)
|
77
83
|
optout = new(config)
|
78
84
|
optout.instance_eval(&block) if block_given?
|
@@ -85,7 +91,8 @@ class Optout
|
|
85
91
|
def initialize(args = {})
|
86
92
|
@options = {}
|
87
93
|
@check_keys = args.include?(:check_keys) ? args[:check_keys] : true
|
88
|
-
|
94
|
+
@required_context = option_context(:required => true)
|
95
|
+
@optional_context = option_context(:required => false)
|
89
96
|
@default_opt_options = {
|
90
97
|
:required => args[:required],
|
91
98
|
:multiple => args[:multiple],
|
@@ -98,45 +105,103 @@ class Optout
|
|
98
105
|
#
|
99
106
|
# === Parameters
|
100
107
|
#
|
101
|
-
# [key (Symbol)] The key of the option in the option hash
|
108
|
+
# [key (Symbol)] The key of the option in the option hash passed to +shell+ or +argv+.
|
102
109
|
# [switch (String)] Optional. The option's command line switch. If no switch is given only the option's value is output.
|
103
|
-
# [rule (Object)] Optional. Validation rule, see
|
104
|
-
# [options (Hash)] Additional option configuration, see
|
110
|
+
# [rule (Object)] Optional. Validation rule, see Optout#on@Validating.
|
111
|
+
# [options (Hash)] Additional option configuration, see Optout#on@Options.
|
105
112
|
#
|
106
113
|
# === Options
|
107
114
|
#
|
108
|
-
# [:arg_separator] The +String+ used to separate the option's switch from its value. Defaults to <code>" "</code> (space).
|
115
|
+
# [:arg_separator] The +String+ used to separate the option's switch from its value. Defaults to <code>" "</code> (space). This can be set globally via Optout::options.
|
109
116
|
# [:default] The option's default value. This will be used if the option is +nil+ or +empty?+.
|
110
|
-
# [:
|
111
|
-
# [:
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
# [
|
117
|
+
# [:multiple] If +true+ the option will accept multiple values. If +false+ an <code>Optout::OptionInvalid</code> error will be raised if the option contains multiple values. By default multiple values are joined on a comma, you can set this to a +String+ to join on that string instead. Defaults to +false+. This can be set globally via Optout::options.
|
118
|
+
# [:required] If +true+ the option must contian a value i.e., it must not be +false+ or +nil+ otherwise an <code>Optout::OptionRequired</code> exception will be raised.
|
119
|
+
# Defaults to +false+. This can be set globally via Optout::options or for a set of options via Optout#required or Optout#optional.
|
120
|
+
#
|
121
|
+
# === Errors
|
122
|
+
#
|
123
|
+
# [ArgumentError] An +ArgumentError+ is raised if +key+ is +nil+ or has already been defined
|
117
124
|
#
|
118
125
|
# === Validating
|
119
126
|
#
|
120
|
-
#
|
121
|
-
# to +on+ when defining the option. Validation rules can be in one of the following forms:
|
127
|
+
# An option's value can be restricted by a validation rule. If validation fails an Optout::OptionInvalid exception is raised.
|
122
128
|
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
# [Class] Restrict the option's value to instances of the given class.
|
126
|
-
# [Optout::Boolean] Restrict the option's value to something boolean, i.e., +true+, +false+, or +nil+.
|
127
|
-
# [Optout::File] The option's value must be a file. Note that the file does not have to exist. <code>Optout::File</code> has several methods that can be used to tune validation, see Optout::File.
|
128
|
-
# [Optout::Dir] The option's value must be a directory. <code>Optout::Dir</code> has several methods that can be used to tune validation, see Optout::Dir.
|
129
|
-
#
|
130
|
-
# === Errors
|
129
|
+
# Validation rules will only be applied if the option hash contains a non-nil value for the given option's key.
|
130
|
+
# If the option is required you must either define it in a Optout#required block or set the +:required+ option to +true+ when calling Optout#on.
|
131
131
|
#
|
132
|
-
#
|
133
|
-
|
132
|
+
# Validation rules can be in one of the following forms:
|
133
|
+
#
|
134
|
+
# ==== Regex
|
135
|
+
#
|
136
|
+
# A pattern to match the option's value against.
|
137
|
+
#
|
138
|
+
# on :key, /\d+/
|
139
|
+
# on :key, "-switch", /\d+/
|
140
|
+
#
|
141
|
+
# ==== Array
|
142
|
+
#
|
143
|
+
# Only accept value(s) contained in the given array.
|
144
|
+
#
|
145
|
+
# on :key, %w(item_a item_b item_c)
|
146
|
+
# on :key, "-switch", %w(item_a item_b item_c)
|
147
|
+
#
|
148
|
+
# ==== Class
|
149
|
+
#
|
150
|
+
# Must be an instance of the given class.
|
151
|
+
#
|
152
|
+
# on :key, Fixnum
|
153
|
+
# on :key, "-switch", Fixnum
|
154
|
+
#
|
155
|
+
# ==== Optout::Boolean
|
156
|
+
#
|
157
|
+
# Must be +true+ or +false+.
|
158
|
+
#
|
159
|
+
# on :key, Optout::Boolean
|
160
|
+
# on :key, "-switch", Optout::Boolean
|
161
|
+
#
|
162
|
+
# ==== Optout::File
|
163
|
+
#
|
164
|
+
# Must be a file. Note that the file does not have to exist.
|
165
|
+
#
|
166
|
+
# on :key, Optout::File
|
167
|
+
# on :key, "-switch", Optout::File
|
168
|
+
#
|
169
|
+
# <code>Optout::File</code> has several methods that can be used to tune validation:
|
170
|
+
#
|
171
|
+
# on :key, "-switch", Optout::File.named(/-\d{2}$/).under("/home/sshaw")
|
172
|
+
#
|
173
|
+
# In this case the file's basename must match the given regexp and exist under the given directory. See Optout::File for more info.
|
174
|
+
#
|
175
|
+
# ==== Optout::Dir
|
176
|
+
#
|
177
|
+
# Like <code>Optout::File</code> except for directories. <code>Optout::Dir</code> has several methods that can be used to tune validation, see Optout::Dir.
|
178
|
+
#
|
179
|
+
# on :key, Optout::Dir
|
180
|
+
# on :key, "-switch", Optout::Dir
|
181
|
+
#
|
182
|
+
# ==== Custom Validator
|
183
|
+
#
|
184
|
+
# A class that responds to +validate!+ and accepts a single argument containing the option (as an instance of Optout::Option).
|
185
|
+
#
|
186
|
+
# class MyValidator
|
187
|
+
# def validate!(option)
|
188
|
+
# if option.empty? || option.value.size % 2 != 1
|
189
|
+
# raise Optout::OptionInvalid.new(option.key, "bad option!")
|
190
|
+
# end
|
191
|
+
# end
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# on :key, MyValidator.new
|
195
|
+
# on :key, "-switch", MyValidator.new
|
196
|
+
|
134
197
|
def on(*args)
|
135
198
|
key = args.shift
|
136
199
|
|
137
200
|
# switch is optional, this could be a validation rule
|
138
201
|
switch = args.shift if String === args[0]
|
139
202
|
raise ArgumentError, "option key required" if key.nil?
|
203
|
+
|
204
|
+
key = key.to_sym
|
140
205
|
raise ArgumentError, "option already defined: '#{key}'" if @options[key]
|
141
206
|
|
142
207
|
opt_options = Hash === args.last ? @default_opt_options.merge(args.pop) : @default_opt_options.dup
|
@@ -146,41 +211,120 @@ class Optout
|
|
146
211
|
@options[key] = Option.create(key, switch, opt_options)
|
147
212
|
end
|
148
213
|
|
214
|
+
##
|
215
|
+
# Create a set of options that are optional. This can also be set on a per option basis, see Optout#on.
|
216
|
+
#
|
217
|
+
# === Examples
|
218
|
+
#
|
219
|
+
# optz = Optout.options do
|
220
|
+
# optional do
|
221
|
+
# on :ignore, "-i"
|
222
|
+
# on :recurse, "-r"
|
223
|
+
# end
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# optz.optional { on :path, Optout::File }
|
227
|
+
|
228
|
+
def optional(&block)
|
229
|
+
@optional_context.instance_eval(&block)
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# Create a set of options that are required.
|
234
|
+
#
|
235
|
+
# If any +required+ option is missing from the option hash passed to Optout#argv or Optout#shell an
|
236
|
+
# <code>Optout::OptionRequired</code> exception is raised.
|
237
|
+
#
|
238
|
+
# This can also be set on a per option basis, see Optout#on.
|
239
|
+
#
|
240
|
+
# === Examples
|
241
|
+
#
|
242
|
+
# optz = Optout.options do
|
243
|
+
# required do
|
244
|
+
# on :ignore, "-i"
|
245
|
+
# on :recurse, "-r"
|
246
|
+
# end
|
247
|
+
# end
|
248
|
+
#
|
249
|
+
# optz.required { on :path, Optout::File }
|
250
|
+
#
|
251
|
+
|
252
|
+
def required(&block)
|
253
|
+
@required_context.instance_eval(&block)
|
254
|
+
end
|
255
|
+
|
149
256
|
##
|
150
257
|
# Create an argument string that can be to passed to a +system+ like function.
|
258
|
+
# Options must first be defined via Optout#on.
|
151
259
|
#
|
152
260
|
# === Parameters
|
261
|
+
#
|
153
262
|
# [options (Hash)] The option hash used to construct the argument string.
|
154
263
|
#
|
155
264
|
# === Returns
|
265
|
+
#
|
156
266
|
# [String] The argument string.
|
157
267
|
#
|
158
268
|
# === Errors
|
269
|
+
#
|
159
270
|
# See Optout#argv@Errors
|
271
|
+
#
|
272
|
+
# === Examples
|
273
|
+
#
|
274
|
+
# Create <code>"-a -b '1024' '/home/sshaw/some file'"</code>
|
275
|
+
#
|
276
|
+
# optz = Optout.options do
|
277
|
+
# on :all, "-a"
|
278
|
+
# on :size, "-b", /\A\d+\z/, :required => true
|
279
|
+
# on :file, Optout::File.under("/home/sshaw"), :default => "/home/sshaw/tmp"
|
280
|
+
# end
|
281
|
+
#
|
282
|
+
# optz.shell(:all => true, :size => 1024, :file => "/home/sshaw/some file")
|
283
|
+
|
160
284
|
def shell(options = {})
|
161
285
|
create_options(options).map { |opt| opt.to_s }.join " "
|
162
286
|
end
|
163
287
|
|
164
288
|
##
|
165
289
|
# Create an +argv+ array that can be to passed to an +exec+ like function.
|
290
|
+
# Options must first be defined via Optout#on.
|
166
291
|
#
|
167
292
|
# === Parameters
|
293
|
+
#
|
168
294
|
# [options (Hash)] The options hash used to construct the +argv+ array.
|
169
295
|
#
|
170
296
|
# === Returns
|
297
|
+
#
|
171
298
|
# [Array] The +argv+ array, each element is a +String+
|
172
299
|
#
|
173
300
|
# === Errors
|
301
|
+
#
|
302
|
+
# [ArgumentError] If options are not a +Hash+
|
174
303
|
# [Optout::OptionRequired] The option hash is missing a required value.
|
175
304
|
# [Optout::OptionUnknown] The option hash contains an unknown key.
|
176
305
|
# [Optout::OptionInvalid] The option hash contains a value the does not conform to the defined specification.
|
177
|
-
|
306
|
+
#
|
307
|
+
# === Examples
|
308
|
+
#
|
309
|
+
# Create <code>["--prefix='/sshaw/usr/lib'", "libssl2"]</code>
|
310
|
+
#
|
311
|
+
# optz = Optout.options do
|
312
|
+
# on :all, "-a"
|
313
|
+
# on :size, "-b", /\A\d+\z/, :required => true
|
314
|
+
# on :file, Optout::File.under("/home/sshaw"), :default => "/home/sshaw/tmp"
|
315
|
+
# end
|
316
|
+
#
|
317
|
+
# optz.argv(:lib => "libssl2",
|
318
|
+
# :prefix => "/sshaw/usr/lib")
|
319
|
+
|
178
320
|
def argv(options = {})
|
179
321
|
create_options(options).map { |opt| opt.to_a }.flatten
|
180
322
|
end
|
181
323
|
|
182
324
|
private
|
183
|
-
def create_options(options = {})
|
325
|
+
def create_options(options = {})
|
326
|
+
raise ArgumentError, "options must be a Hash" unless Hash === options
|
327
|
+
|
184
328
|
argv = []
|
185
329
|
options = options.dup
|
186
330
|
|
@@ -199,12 +343,24 @@ class Optout
|
|
199
343
|
sort_by { |opt| opt.index }
|
200
344
|
end
|
201
345
|
|
346
|
+
def option_context(forced_options)
|
347
|
+
klass = self
|
348
|
+
Class.new do
|
349
|
+
define_method(:on) do |*args|
|
350
|
+
options = Hash === args.last ? args.pop.dup : {}
|
351
|
+
options.merge!(forced_options)
|
352
|
+
args << options
|
353
|
+
klass.on *args
|
354
|
+
end
|
355
|
+
end.new
|
356
|
+
end
|
357
|
+
|
202
358
|
class Option
|
203
359
|
attr :key
|
204
360
|
attr :value
|
205
361
|
attr :index
|
206
362
|
|
207
|
-
##
|
363
|
+
##
|
208
364
|
# Creates a subclass of +Option+
|
209
365
|
#
|
210
366
|
# === Parameters
|
@@ -246,7 +402,7 @@ class Optout
|
|
246
402
|
|
247
403
|
##
|
248
404
|
# Turn the option into a string that can be to passed to a +system+ like function.
|
249
|
-
# This
|
405
|
+
# This _does_ _not_ validate the option. You must call <code>validate!</code>.
|
250
406
|
#
|
251
407
|
# === Examples
|
252
408
|
#
|
@@ -300,7 +456,7 @@ class Optout
|
|
300
456
|
#
|
301
457
|
# [OptionRequired] The option is missing a required value
|
302
458
|
# [OptionUnknown] The option contains an unknown key
|
303
|
-
# [OptionInvalid] The option contains a value
|
459
|
+
# [OptionInvalid] The option contains a value that does not conform to the defined specification
|
304
460
|
#
|
305
461
|
def validate!
|
306
462
|
@validators.each { |v| v.validate!(self) }
|
@@ -324,28 +480,29 @@ class Optout
|
|
324
480
|
end
|
325
481
|
|
326
482
|
def unix?
|
327
|
-
RbConfig::CONFIG["host_os"] !~ /mswin|mingw/i
|
483
|
+
RbConfig::CONFIG["host_os"] !~ /mswin|mingw|msys/i
|
328
484
|
end
|
329
|
-
|
485
|
+
|
330
486
|
def normalize(value)
|
331
487
|
value.respond_to?(:entries) ? value.entries.join(@joinon) : value.to_s.strip
|
332
488
|
end
|
333
489
|
end
|
334
|
-
|
490
|
+
|
335
491
|
module Validator #:nodoc: all
|
336
492
|
def self.for(setting)
|
337
493
|
if setting.respond_to?(:validate!)
|
338
494
|
setting
|
339
495
|
else
|
340
496
|
# Load validator based on the setting's name or the name of its class
|
341
|
-
|
497
|
+
# Note that on 1.9 calling class.name on anonymous classes (i.e., Class.new.new) returns nil
|
498
|
+
validator = setting.class.name.to_s
|
342
499
|
if validator == "Class"
|
343
|
-
name = setting.name.split("::", 2)
|
500
|
+
name = setting.name.to_s.split("::", 2)
|
344
501
|
validator = name[1] if name[1] && name[0] == "Optout"
|
345
502
|
end
|
346
503
|
|
347
|
-
# Support 1.8 and 1.9, avoid String/Symbol and const_defined? differences
|
348
|
-
if !constants.include?(validator) && !constants.include?(validator.to_sym)
|
504
|
+
# Support 1.8 and 1.9, avoid String/Symbol and const_defined? differences
|
505
|
+
if validator.empty? || !constants.include?(validator) && !constants.include?(validator.to_sym)
|
349
506
|
raise ArgumentError, "don't know how to validate with #{setting}"
|
350
507
|
end
|
351
508
|
|
@@ -355,7 +512,7 @@ class Optout
|
|
355
512
|
|
356
513
|
Base = Struct.new :setting
|
357
514
|
|
358
|
-
#
|
515
|
+
# Checks for multiple values
|
359
516
|
class Multiple < Base
|
360
517
|
def validate!(opt)
|
361
518
|
if !opt.empty? && opt.value.respond_to?(:entries) && opt.value.entries.size > 1 && !multiple_values_allowed?
|
@@ -384,6 +541,8 @@ class Optout
|
|
384
541
|
|
385
542
|
class Array < Base
|
386
543
|
def validate!(opt)
|
544
|
+
return if opt.empty?
|
545
|
+
|
387
546
|
values = [opt.value].flatten
|
388
547
|
values.each do |e|
|
389
548
|
if !setting.include?(e)
|
@@ -403,7 +562,7 @@ class Optout
|
|
403
562
|
|
404
563
|
class Class < Base
|
405
564
|
def validate!(opt)
|
406
|
-
if !(setting === opt.value)
|
565
|
+
if !opt.empty? && !(setting === opt.value)
|
407
566
|
raise OptionInvalid.new(opt.key, "value '#{opt.value}' must be type #{setting}")
|
408
567
|
end
|
409
568
|
end
|
@@ -412,6 +571,7 @@ class Optout
|
|
412
571
|
class Boolean < Base
|
413
572
|
def validate!(opt)
|
414
573
|
if !(opt.value == true || opt.value == false || opt.value.nil?)
|
574
|
+
# TODO: Better message
|
415
575
|
raise OptionInvalid.new(opt.key, "does not accept an argument")
|
416
576
|
end
|
417
577
|
end
|
@@ -485,6 +645,7 @@ class Optout
|
|
485
645
|
@file.parent.expand_path.to_s == ::File.expand_path(@under))
|
486
646
|
end
|
487
647
|
|
648
|
+
# TODO: Should probably make correct_type? a separate check
|
488
649
|
def creatable?
|
489
650
|
@file.exist? && correct_type? ||
|
490
651
|
!@file.exist? && @file.parent.exist? && @file.parent.writable?
|
@@ -501,22 +662,24 @@ class Optout
|
|
501
662
|
|
502
663
|
|
503
664
|
#
|
504
|
-
#
|
505
|
-
#
|
665
|
+
# The following are shortcuts and/or marker classes used by Optout's public. They enable Validator.for()
|
666
|
+
# to load the appropriate validation class.
|
506
667
|
#
|
507
668
|
|
508
669
|
##
|
509
670
|
# <code>Optout::File</code> is a validaton rule that can be used to check that an option's value is a path to a file.
|
510
671
|
# By default <code>Optout::File</code> *does* *not* *check* that the file exists. Instead, it checks that the file's parent directory
|
511
672
|
# exists. This is done so that you can validate a path that _will_ be created by the program the options are for.
|
512
|
-
# If you
|
673
|
+
# If you do want the file to exist just call the +exists+ method.
|
513
674
|
#
|
514
675
|
# Validation rules can be combined:
|
515
676
|
#
|
516
677
|
# Optout.options do
|
517
678
|
# on :path, "--path", Optout::File.exists.under("/home").named(/\.txt$/)
|
518
679
|
# end
|
519
|
-
#
|
680
|
+
#
|
681
|
+
# To validate directories use Optout::Dir.
|
682
|
+
#
|
520
683
|
class File
|
521
684
|
class << self
|
522
685
|
Validator::File::RULES.each do |r|
|
@@ -554,11 +717,15 @@ class Optout
|
|
554
717
|
# :call-seq:
|
555
718
|
# permissions(symbolic_mode)
|
556
719
|
#
|
557
|
-
# The option's user permissions must match the given permission(s).
|
720
|
+
# The option's *user* *permissions* must match the given permission(s).
|
721
|
+
#
|
558
722
|
#
|
559
723
|
# === Parameters
|
560
724
|
#
|
561
|
-
# A +String+ denoting the desired permission.
|
725
|
+
# A <code>chmod(1)</code> symbolic mode +String+ denoting the desired permission(s).
|
726
|
+
# Any combination of <code>"r"</code>, <code>"w"</code> and <code>"x"</code> is supported.
|
727
|
+
#
|
728
|
+
# Note that permissions are system dependent, certain modes might not be supported by your OS.
|
562
729
|
|
563
730
|
##
|
564
731
|
#
|
@@ -576,7 +743,9 @@ class Optout
|
|
576
743
|
|
577
744
|
##
|
578
745
|
# <code>Optout::Dir</code> is a validaton rule that can be used to check that an option's value is a path to a directory.
|
579
|
-
#
|
746
|
+
# This class proivdes the same functionality for directories that Optout::File provides for files. See Optout::File for more info.
|
747
|
+
#
|
748
|
+
# Validation rules can be combined:
|
580
749
|
#
|
581
750
|
# Optout.options do
|
582
751
|
# on :path, "--path", Optout::Dir.exists.under("/tmp").named(/\d$/)
|
@@ -590,7 +759,14 @@ class Optout
|
|
590
759
|
end
|
591
760
|
end
|
592
761
|
|
593
|
-
|
762
|
+
##
|
763
|
+
# <code>Optout::Boolean</code> is a validaton rule that can be used to check that an option's value is +true+ or +false+.
|
764
|
+
#
|
765
|
+
# Optout.options do
|
766
|
+
# on :force, "-f", Optout::Boolean
|
767
|
+
# end
|
768
|
+
|
769
|
+
class Boolean
|
594
770
|
end
|
595
771
|
end
|
596
772
|
|