configurable 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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