configurable 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,10 @@
1
1
  autoload(:YAML, 'yaml')
2
2
 
3
3
  module Configurable
4
+ # A hash of (block, default attributes) for config blocks. The
5
+ # attributes for nil will be merged with those for the block.
6
+ DEFAULT_ATTRIBUTES = Hash.new({})
7
+ DEFAULT_ATTRIBUTES[nil] = {:reader => true, :writer => true}
4
8
 
5
9
  # Validation generates blocks for common validations and transformations of
6
10
  # configurations set through Configurable. In general these blocks load
@@ -24,7 +28,7 @@ module Configurable
24
28
  # do it all in one step.
25
29
  module Validation
26
30
 
27
- # Raised when Validation blocks fail.
31
+ # Raised when a Validation block fails.
28
32
  class ValidationError < ArgumentError
29
33
  def initialize(input, validations)
30
34
  super case
@@ -36,21 +40,16 @@ module Configurable
36
40
  end
37
41
  end
38
42
 
39
- # Raised when yamlization fails.
40
- class YamlizationError < ArgumentError
41
- def initialize(input, error)
42
- super "#{error} ('#{input}')"
43
- end
44
- end
45
-
46
43
  module_function
47
44
 
48
- # Yaml conversion and checker. Valid if any of the validations
49
- # match in a case statement. Otherwise raises an error.
50
-
51
- # Returns input if any of the validations match any of the
52
- # inputs, as in a case statement. Raises a ValidationError
53
- # otherwise. For example:
45
+ # Registers the default attributes with the specified block
46
+ # in Configurable::DEFAULT_ATTRIBUTES.
47
+ def register(block, attributes)
48
+ DEFAULT_ATTRIBUTES[block] = attributes
49
+ end
50
+
51
+ # Returns input if it matches any of the validations as in would in a case
52
+ # statement. Raises a ValidationError otherwise. For example:
54
53
  #
55
54
  # validate(10, [Integer, nil])
56
55
  #
@@ -61,44 +60,38 @@ module Configurable
61
60
  # else raise ValidationError.new(...)
62
61
  # end
63
62
  #
64
- # Note the validations input must be an Array or nil;
65
- # validate will raise an ArgumentError otherwise.
66
- # All inputs are considered VALID if validations == nil.
63
+ # A block may be provided to handle invalid inputs; if provided it will be
64
+ # called and a ValidationError will not be raised. Note the validations
65
+ # input must be an Array or nil; validate will raise an ArgumentError
66
+ # otherwise. All inputs are considered VALID if validations == nil.
67
67
  def validate(input, validations)
68
68
  case validations
69
69
  when Array
70
70
 
71
71
  case input
72
72
  when *validations then input
73
- else raise ValidationError.new(input, validations)
73
+ else
74
+ if block_given?
75
+ yield(input)
76
+ else
77
+ raise ValidationError.new(input, validations)
78
+ end
74
79
  end
75
80
 
76
81
  when nil then input
77
- else raise ArgumentError.new("validations must be nil, or an array of valid inputs")
78
- end
79
- end
80
-
81
- # Attempts to load the input as YAML. Raises a YamlizationError
82
- # for errors.
83
- def yamlize(input)
84
- begin
85
- YAML.load(input)
86
- rescue
87
- raise YamlizationError.new(input, $!.message)
82
+ else raise ArgumentError, "validations must be nil, or an array of valid inputs"
88
83
  end
89
84
  end
90
85
 
91
86
  # Returns a block that calls validate using the block input
92
- # and the input validations. Raises an error if no validations
93
- # are specified.
87
+ # and validations.
94
88
  def check(*validations)
95
- raise ArgumentError.new("no validations specified") if validations.empty?
96
89
  lambda {|input| validate(input, validations) }
97
90
  end
98
91
 
99
92
  # Returns a block that loads input strings as YAML, then
100
- # calls validate with the result and the input validations.
101
- # Non-string inputs are not converted.
93
+ # calls validate with the result and validations. Non-string
94
+ # inputs are validated directly.
102
95
  #
103
96
  # b = yaml(Integer, nil)
104
97
  # b.class # => Proc
@@ -110,19 +103,9 @@ module Configurable
110
103
  # If no validations are specified, the result will be
111
104
  # returned without validation.
112
105
  def yaml(*validations)
106
+ validations = nil if validations.empty?
113
107
  lambda do |input|
114
- res = input.kind_of?(String) ? yamlize(input) : input
115
- validations.empty? ? res : validate(res, validations)
116
- end
117
- end
118
-
119
- # Returns a block loads a String input as YAML then
120
- # validates the result is valid using the input
121
- # validations. If the input is not a String, the
122
- # input is validated directly.
123
- def yamlize_and_check(*validations)
124
- lambda do |input|
125
- input = yamlize(input) if input.kind_of?(String)
108
+ input = YAML.load(input) if input.kind_of?(String)
126
109
  validate(input, validations)
127
110
  end
128
111
  end
@@ -174,14 +157,14 @@ module Configurable
174
157
  # symbol.call('str') # => ValidationError
175
158
  #
176
159
  def symbol(); SYMBOL; end
177
- SYMBOL = yamlize_and_check(Symbol)
160
+ SYMBOL = yaml(Symbol)
178
161
 
179
162
  # Same as symbol but allows nil:
180
163
  #
181
164
  # symbol_or_nil.call('~') # => nil
182
165
  # symbol_or_nil.call(nil) # => nil
183
166
  def symbol_or_nil(); SYMBOL_OR_NIL; end
184
- SYMBOL_OR_NIL = yamlize_and_check(Symbol, nil)
167
+ SYMBOL_OR_NIL = yaml(Symbol, nil)
185
168
 
186
169
  # Returns a block that checks the input is true, false or nil.
187
170
  # String inputs are loaded as yaml first.
@@ -199,15 +182,21 @@ module Configurable
199
182
  # boolean.call("str") # => ValidationError
200
183
  #
201
184
  def boolean(); BOOLEAN; end
202
- BOOLEAN = yamlize_and_check(true, false, nil)
185
+ BOOLEAN = yaml(true, false, nil)
203
186
 
204
187
  # Same as boolean.
205
188
  def switch(); SWITCH; end
206
- SWITCH = yamlize_and_check(true, false, nil)
207
-
189
+
190
+ # default attributes {:type => :switch}
191
+ SWITCH = yaml(true, false, nil)
192
+ register SWITCH, :type => :switch
193
+
208
194
  # Same as boolean.
209
195
  def flag(); FLAG; end
210
- FLAG = yamlize_and_check(true, false, nil)
196
+
197
+ # default attributes {:type => :flag}
198
+ FLAG = yaml(true, false, nil)
199
+ register FLAG, :type => :flag
211
200
 
212
201
  # Returns a block that checks the input is an array.
213
202
  # String inputs are loaded as yaml first.
@@ -219,14 +208,20 @@ module Configurable
219
208
  # array.call('str') # => ValidationError
220
209
  #
221
210
  def array(); ARRAY; end
222
- ARRAY = yamlize_and_check(Array)
211
+
212
+ # default attributes {:arg_name => "'[a, b, c]'"}
213
+ ARRAY = yaml(Array)
214
+ register ARRAY, :arg_name => "'[a, b, c]'"
223
215
 
224
216
  # Same as array but allows nil:
225
217
  #
226
218
  # array_or_nil.call('~') # => nil
227
219
  # array_or_nil.call(nil) # => nil
228
220
  def array_or_nil(); ARRAY_OR_NIL; end
229
- ARRAY_OR_NIL = yamlize_and_check(Array, nil)
221
+
222
+ # default attributes {:arg_name => "'[a, b, c]'"}
223
+ ARRAY_OR_NIL = yaml(Array, nil)
224
+ register ARRAY_OR_NIL, :arg_name => "'[a, b, c]'"
230
225
 
231
226
  # Returns a block that checks the input is an array,
232
227
  # then yamlizes each string value of the array.
@@ -240,11 +235,14 @@ module Configurable
240
235
  def list(); LIST; end
241
236
  list_block = lambda do |input|
242
237
  validate(input, [Array]).collect do |arg|
243
- arg.kind_of?(String) ? yamlize(arg) : arg
238
+ arg.kind_of?(String) ? YAML.load(arg) : arg
244
239
  end
245
240
  end
241
+
242
+ # default attributes {:type => :list, :split => ','}
246
243
  LIST = list_block
247
-
244
+ register LIST, :type => :list, :split => ','
245
+
248
246
  # Returns a block that checks the input is a hash.
249
247
  # String inputs are loaded as yaml first.
250
248
  #
@@ -255,14 +253,20 @@ module Configurable
255
253
  # hash.call('str') # => ValidationError
256
254
  #
257
255
  def hash(); HASH; end
258
- HASH = yamlize_and_check(Hash)
256
+
257
+ # default attributes {:arg_name => "'{one: 1, two: 2}'"}
258
+ HASH = yaml(Hash)
259
+ register HASH, :arg_name => "'{one: 1, two: 2}'"
259
260
 
260
261
  # Same as hash but allows nil:
261
262
  #
262
263
  # hash_or_nil.call('~') # => nil
263
264
  # hash_or_nil.call(nil) # => nil
264
265
  def hash_or_nil(); HASH_OR_NIL; end
265
- HASH_OR_NIL = yamlize_and_check(Hash, nil)
266
+
267
+ # default attributes {:arg_name => "'{one: 1, two: 2}'"}
268
+ HASH_OR_NIL = yaml(Hash, nil)
269
+ register HASH_OR_NIL, :arg_name => "'{one: 1, two: 2}'"
266
270
 
267
271
  # Returns a block that checks the input is an integer.
268
272
  # String inputs are loaded as yaml first.
@@ -275,14 +279,14 @@ module Configurable
275
279
  # integer.call('str') # => ValidationError
276
280
  #
277
281
  def integer(); INTEGER; end
278
- INTEGER = yamlize_and_check(Integer)
282
+ INTEGER = yaml(Integer)
279
283
 
280
284
  # Same as integer but allows nil:
281
285
  #
282
286
  # integer_or_nil.call('~') # => nil
283
287
  # integer_or_nil.call(nil) # => nil
284
288
  def integer_or_nil(); INTEGER_OR_NIL; end
285
- INTEGER_OR_NIL = yamlize_and_check(Integer, nil)
289
+ INTEGER_OR_NIL = yaml(Integer, nil)
286
290
 
287
291
  # Returns a block that checks the input is a float.
288
292
  # String inputs are loaded as yaml first.
@@ -296,14 +300,14 @@ module Configurable
296
300
  # float.call('str') # => ValidationError
297
301
  #
298
302
  def float(); FLOAT; end
299
- FLOAT = yamlize_and_check(Float)
303
+ FLOAT = yaml(Float)
300
304
 
301
305
  # Same as float but allows nil:
302
306
  #
303
307
  # float_or_nil.call('~') # => nil
304
308
  # float_or_nil.call(nil) # => nil
305
309
  def float_or_nil(); FLOAT_OR_NIL; end
306
- FLOAT_OR_NIL = yamlize_and_check(Float, nil)
310
+ FLOAT_OR_NIL = yaml(Float, nil)
307
311
 
308
312
  # Returns a block that checks the input is a number.
309
313
  # String inputs are loaded as yaml first.
@@ -318,58 +322,66 @@ module Configurable
318
322
  # num.call('str') # => ValidationError
319
323
  #
320
324
  def num(); NUMERIC; end
321
- NUMERIC = yamlize_and_check(Numeric)
325
+ NUMERIC = yaml(Numeric)
322
326
 
323
327
  # Same as num but allows nil:
324
328
  #
325
329
  # num_or_nil.call('~') # => nil
326
330
  # num_or_nil.call(nil) # => nil
327
331
  def num_or_nil(); NUMERIC_OR_NIL; end
328
- NUMERIC_OR_NIL = yamlize_and_check(Numeric, nil)
332
+ NUMERIC_OR_NIL = yaml(Numeric, nil)
329
333
 
330
- # Returns a block that checks the input is a regexp.
331
- # String inputs are converted to regexps using
332
- # Regexp#new.
334
+ # Returns a block that checks the input is a regexp. String inputs are
335
+ # loaded as yaml; if the result is not a regexp, it is converted to
336
+ # a regexp using Regexp#new.
333
337
  #
334
338
  # regexp.class # => Proc
335
339
  # regexp.call(/regexp/) # => /regexp/
336
340
  # regexp.call('regexp') # => /regexp/
337
341
  #
342
+ # yaml_str = '!ruby/regexp /regexp/'
343
+ # regexp.call(yaml_str) # => /regexp/
344
+ #
338
345
  # # use of ruby-specific flags can turn on/off
339
346
  # # features like case insensitive matching
340
347
  # regexp.call('(?i)regexp') # => /(?i)regexp/
341
348
  #
342
349
  def regexp(); REGEXP; end
343
350
  regexp_block = lambda do |input|
344
- input = Regexp.new(input) if input.kind_of?(String)
351
+ if input.kind_of?(String)
352
+ begin
353
+ input = validate(YAML.load(input), [Regexp]) {|obj| input }
354
+ rescue(ArgumentError)
355
+ end
356
+ end
357
+
358
+ if input.kind_of?(String)
359
+ input = Regexp.new(input)
360
+ end
361
+
345
362
  validate(input, [Regexp])
346
363
  end
347
364
  REGEXP = regexp_block
348
365
 
349
- # Same as regexp but allows nil. Note the special
350
- # behavior of the nil string '~' -- rather than
351
- # being converted to a regexp, it is processed as
352
- # nil to be consistent with the other [class]_or_nil
353
- # methods.
366
+ # Same as regexp but allows nil. Note the special behavior of the nil
367
+ # string '~' -- rather than being converted to a regexp, it is processed
368
+ # as nil to be consistent with the other [class]_or_nil methods.
354
369
  #
355
370
  # regexp_or_nil.call('~') # => nil
356
371
  # regexp_or_nil.call(nil) # => nil
357
372
  def regexp_or_nil(); REGEXP_OR_NIL; end
358
373
  regexp_or_nil_block = lambda do |input|
359
- input = case input
374
+ case input
360
375
  when nil, '~' then nil
361
- when String then Regexp.new(input)
362
- else input
376
+ else REGEXP[input]
363
377
  end
364
-
365
- validate(input, [Regexp, nil])
366
378
  end
367
379
  REGEXP_OR_NIL = regexp_or_nil_block
368
380
 
369
- # Returns a block that checks the input is a range.
370
- # String inputs are split into a beginning and
371
- # end if possible, where each part is loaded as
372
- # yaml before being used to construct a Range.a
381
+ # Returns a block that checks the input is a range. String inputs are
382
+ # loaded as yaml; if the result is still a string, it is split into a
383
+ # beginning and end, if possible, and each part is loaded as yaml
384
+ # before being used to construct a Range.
373
385
  #
374
386
  # range.class # => Proc
375
387
  # range.call(1..10) # => 1..10
@@ -380,11 +392,22 @@ module Configurable
380
392
  # range.call('1.10') # => ValidationError
381
393
  # range.call('a....z') # => ValidationError
382
394
  #
395
+ # yaml_str = "!ruby/range \nbegin: 1\nend: 10\nexcl: false\n"
396
+ # range.call(yaml_str) # => 1..10
397
+ #
383
398
  def range(); RANGE; end
384
399
  range_block = lambda do |input|
400
+ if input.kind_of?(String)
401
+ begin
402
+ input = validate(YAML.load(input), [Range]) {|obj| input }
403
+ rescue(ArgumentError)
404
+ end
405
+ end
406
+
385
407
  if input.kind_of?(String) && input =~ /^([^.]+)(\.{2,3})([^.]+)$/
386
- input = Range.new(yamlize($1), yamlize($3), $2.length == 3)
408
+ input = Range.new(YAML.load($1), YAML.load($3), $2.length == 3)
387
409
  end
410
+
388
411
  validate(input, [Range])
389
412
  end
390
413
  RANGE = range_block
@@ -395,18 +418,10 @@ module Configurable
395
418
  # range_or_nil.call(nil) # => nil
396
419
  def range_or_nil(); RANGE_OR_NIL; end
397
420
  range_or_nil_block = lambda do |input|
398
- input = case input
421
+ case input
399
422
  when nil, '~' then nil
400
- when String
401
- if input =~ /^([^.]+)(\.{2,3})([^.]+)$/
402
- Range.new(yamlize($1), yamlize($3), $2.length == 3)
403
- else
404
- input
405
- end
406
- else input
423
+ else RANGE[input]
407
424
  end
408
-
409
- validate(input, [Range, nil])
410
425
  end
411
426
  RANGE_OR_NIL = range_or_nil_block
412
427
 
@@ -451,30 +466,15 @@ module Configurable
451
466
  #
452
467
  # time_or_nil.call('~') # => nil
453
468
  # time_or_nil.call(nil) # => nil
454
- def time_or_nil()
455
- # adding this check is a compromise to autoload the parse
456
- # method (autoload doesn't work since Time already exists)
457
- require 'time' unless Time.respond_to?(:parse)
458
- TIME_OR_NIL
459
- end
469
+ def time_or_nil(); TIME_OR_NIL; end
460
470
 
461
471
  time_or_nil_block = lambda do |input|
462
- input = case input
472
+ case input
463
473
  when nil, '~' then nil
464
- when String then Time.parse(input)
465
- else input
474
+ else TIME[input]
466
475
  end
467
-
468
- validate(input, [Time, nil])
469
476
  end
470
477
  TIME_OR_NIL = time_or_nil_block
471
-
472
- # A hash of default attributes for the validation blocks.
473
- ATTRIBUTES = Hash.new({})
474
- ATTRIBUTES[SWITCH] = {:type => :switch}
475
- ATTRIBUTES[FLAG] = {:type => :flag}
476
- ATTRIBUTES[LIST] = {:type => :list, :split => ','}
477
- ATTRIBUTES[ARRAY] = {:arg_name => "'[a, b, c]'"}
478
- ATTRIBUTES[HASH] = {:arg_name => "'{one: 1, two: 2}'"}
478
+
479
479
  end
480
480
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: configurable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Chiang
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-07 00:00:00 -07:00
12
+ date: 2009-02-17 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,17 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.2.0
24
- version:
25
- - !ruby/object:Gem::Dependency
26
- name: tap
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 0.11.1
23
+ version: 0.3.1
34
24
  version:
35
25
  description:
36
26
  email: simon.a.chiang@gmail.com
@@ -41,7 +31,11 @@ extensions: []
41
31
  extra_rdoc_files:
42
32
  - MIT-LICENSE
43
33
  - README
34
+ - History
44
35
  files:
36
+ - lib/cdoc.rb
37
+ - lib/cdoc/cdoc_html_generator.rb
38
+ - lib/cdoc/cdoc_html_template.rb
45
39
  - lib/config_parser.rb
46
40
  - lib/config_parser/option.rb
47
41
  - lib/config_parser/switch.rb
@@ -52,13 +46,20 @@ files:
52
46
  - lib/configurable/delegate_hash.rb
53
47
  - lib/configurable/indifferent_access.rb
54
48
  - lib/configurable/validation.rb
49
+ - lib/configurable/utils.rb
55
50
  - MIT-LICENSE
56
51
  - README
52
+ - History
57
53
  has_rdoc: true
58
54
  homepage: http://tap.rubyforge.org/configurable
59
55
  post_install_message:
60
- rdoc_options: []
61
-
56
+ rdoc_options:
57
+ - --title
58
+ - Configurable
59
+ - --main
60
+ - README
61
+ - --line-numbers
62
+ - --inline-source
62
63
  require_paths:
63
64
  - lib
64
65
  required_ruby_version: !ruby/object:Gem::Requirement