optout 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.rdoc +31 -8
  2. data/lib/optout.rb +238 -62
  3. data/spec/optout_spec.rb +369 -217
  4. metadata +9 -9
@@ -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 => true
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 "/sshaw" and have user write permission
99
- on :path, Optout::Dir.under("/home").permissions("w")
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
- There are plenty of other features, see {the RDoc}[http://rubydoc.info/github/sshaw/optout/frames].
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
- Released under the MIT License: http://www.opensource.org/licenses/MIT
144
+ Copyright (c) 2011-2012 Skye Shaw
145
+
146
+ Released under the MIT License: http://www.opensource.org/licenses/MIT
@@ -2,7 +2,7 @@ require "rbconfig"
2
2
  require "pathname"
3
3
 
4
4
  class Optout
5
- VERSION = "0.0.1"
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 to validate and create.
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
- # [definition (Proc)] Option definitions
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 +on+. See Optout#on@Options.
45
- # [:check_keys] If +true+ an <code>Optout::OptionUnknown</code> error will be raised when the incoming option hash contains a key that has not been associated with an option.
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@Options.
48
- # [:required] Set the default for all subsequent options defined via +on+. See Optout#on@Options.
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, :index => 2
69
+ # on :lib
67
70
  # on :prefix, "--prefix" , %w{/sshaw/lib /sshaw/usr/lib}, :arg_separator => "="
68
71
  # end
69
72
  #
70
- # optz.argv(:lib => "libssl2",
71
- # :prefix => "/sshaw/usr/lib",
72
- # :bad_key => "No error raised because of moi")
73
- # # Creates: ["--prefix='/sshaw/usr/lib'", "libssl2"]
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
- #@opt_seperator = args[:opt_seperator]
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 that will passed to +shell+ or +argv+.
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 {Validating}[rdoc-ref:#on@Validating].
104
- # [options (Hash)] Additional option configuration, see {Options}[rdoc-ref:#on@Options].
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
- # [:index] The index of the option in the resulting +String+ or +Array+.
111
- # [:multiple] If +true+ the option will accept multiple values. If +false+ an <code>Optout::OptionInvalid</code> error will be raised if the option
112
- # contains multiple values. If +true+ multiple values are joined on a comma, you can set this to a +String+
113
- # to join on that string instead. Defaults to +false+.
114
- # [:required] If +true+ the option must contian a value i.e., it must not be +false+ or +nil+ else an <code>Optout::OptionRequired</code> error will be raised.
115
- # Defaults to +false+.
116
- # [:validator] An additional validation rule, see Validating.
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
- # A Validator will only be applied if there's a value. If the option is required pass <code>:required => true</code>
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
- # [Regular Expresion] A pattern to match the option's value against.
124
- # [An Array] Restrict the option's value(s) to item(s) contained in the given array.
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
- # [ArgumentError] An +ArgumentError+ is raised if +key+ is +nil+ or +key+ has already been defined
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 _does not_ validate the option. You must call <code>validate!</code>.
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 the does not conform to the defined specification
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
- validator = setting.class.name
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
- # Check for multiple values
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
- # These are shortcuts and/or marker classes used by the public interface so Validator.for()
505
- # can load the equivalent validation class
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 _do_ want the file to exist just call the +exists+ method.
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. Any combination of <code>"r"</code>, <code>"w"</code> and <code>"x"</code> is supported.
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
- # Validation rules can be combined:
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
- class Boolean #:nodoc:
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