configtoolkit 1.0.4 → 1.0.5
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.
- data/History.txt +3 -0
- data/Rakefile +1 -1
- data/lib/configtoolkit/baseconfig.rb +315 -8
- data/lib/configtoolkit/toolkit.rb +8 -2
- data/lib/configtoolkit/types.rb +40 -14
- metadata +2 -2
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -4,21 +4,69 @@ require 'pathname'
|
|
4
4
|
require 'set'
|
5
5
|
require 'uri'
|
6
6
|
|
7
|
-
#
|
8
|
-
# Tomorrow:
|
9
|
-
# 7.) Ruby gems
|
10
|
-
# 11.) Write lots of readers + writers
|
11
|
-
# 13.) Clean up cast?
|
12
|
-
# 14.) Production comments
|
13
|
-
#
|
14
7
|
module ConfigToolkit
|
15
8
|
|
9
|
+
#
|
10
|
+
# This class represents a configuration. It provides configuration
|
11
|
+
# specification, loading, and dumping functionality. A BaseConfig
|
12
|
+
# configuration can contain "scalars" (anything except an array or
|
13
|
+
# nested configuration class), ConstrainedArrays (arrays), and other
|
14
|
+
# BaseConfig child classes (which can be thought of as hashes).
|
15
|
+
# Note that ConstrainedArrays and other BaseConfig
|
16
|
+
# classes recursively can contain anything the parent BaseConfig can contain,
|
17
|
+
# so nesting to any depth is supported.
|
18
|
+
#
|
19
|
+
# BaseConfig neither parses nor writes to files directly, but instead does so
|
20
|
+
# through reader and writer classes (respectively) specified by the
|
21
|
+
# programmer. This allows BaseConfig to support virtually any underlying
|
22
|
+
# configuration file format (including YAML, UNIX key/value pairs, etc).
|
23
|
+
# BaseConfig expects reader classes to contain a read method that sources
|
24
|
+
# configuration information and returns a hash that maps strings
|
25
|
+
# (parameter names) to values, which can themselves
|
26
|
+
# be hashes or arrays. It expects writer classes to in turn support a write
|
27
|
+
# method that accepts such a hash and writes it to some underlying stream.
|
28
|
+
# The reader and writer implementations used have no effect on BaseConfig's
|
29
|
+
# validation functionality; data from whatever source (even specified
|
30
|
+
# programatically via setters) always fully is validated.
|
31
|
+
#
|
32
|
+
# Programmers wishing to create their own configuration classes
|
33
|
+
# should extend BaseConfig and, in the body of their class' definition,
|
34
|
+
# call add_required_param and add_optional_param for each parameter
|
35
|
+
# they wish to specify. If they wish to enforce a relationship between
|
36
|
+
# parameters, then they also can define validate_all_values.
|
37
|
+
#
|
16
38
|
class BaseConfig
|
39
|
+
|
40
|
+
#
|
41
|
+
# This class represents the specification for a parameter. Right now,
|
42
|
+
# a parameter specification consists of:
|
43
|
+
# 1.) The parameter name (Symbol)
|
44
|
+
# 2.) The parameter value class (Class)
|
45
|
+
# 3.) Whether or not the parameter is required
|
46
|
+
# 4.) If the parameter is not required, a default value
|
47
|
+
#
|
17
48
|
class ParamSpec
|
18
49
|
attr_reader :name
|
19
50
|
attr_reader :value_class
|
20
51
|
attr_reader :default_value # Only meaningful if is_required?
|
21
52
|
|
53
|
+
#
|
54
|
+
# ====Description:
|
55
|
+
#
|
56
|
+
#
|
57
|
+
# ====Parameters:
|
58
|
+
# [name]
|
59
|
+
# ?
|
60
|
+
# [value_class]
|
61
|
+
# ?
|
62
|
+
# [is_required]
|
63
|
+
# ?
|
64
|
+
# [default_value]
|
65
|
+
# ?
|
66
|
+
#
|
67
|
+
# ====Returns:
|
68
|
+
#
|
69
|
+
#
|
22
70
|
def initialize(name, value_class, is_required, default_value)
|
23
71
|
@name = name
|
24
72
|
@value_class = value_class
|
@@ -29,6 +77,13 @@ class BaseConfig
|
|
29
77
|
end
|
30
78
|
end
|
31
79
|
|
80
|
+
#
|
81
|
+
# ====Description:
|
82
|
+
#
|
83
|
+
#
|
84
|
+
# ====Returns:
|
85
|
+
#
|
86
|
+
#
|
32
87
|
def is_required?
|
33
88
|
return @is_required
|
34
89
|
end
|
@@ -59,6 +114,17 @@ class BaseConfig
|
|
59
114
|
attr_reader :required_params
|
60
115
|
end
|
61
116
|
|
117
|
+
#
|
118
|
+
# ====Description:
|
119
|
+
#
|
120
|
+
#
|
121
|
+
# ====Parameters:
|
122
|
+
# [child_class]
|
123
|
+
# ?
|
124
|
+
#
|
125
|
+
# ====Returns:
|
126
|
+
#
|
127
|
+
#
|
62
128
|
def self.inherited(child_class)
|
63
129
|
#
|
64
130
|
# Initialize the class instance variables.
|
@@ -71,6 +137,25 @@ class BaseConfig
|
|
71
137
|
end
|
72
138
|
end
|
73
139
|
|
140
|
+
#
|
141
|
+
# ====Description:
|
142
|
+
#
|
143
|
+
#
|
144
|
+
# ====Parameters:
|
145
|
+
# [name]
|
146
|
+
# ?
|
147
|
+
# [value_class]
|
148
|
+
# ?
|
149
|
+
# [is_required]
|
150
|
+
# ?
|
151
|
+
# [default_value]
|
152
|
+
# ?
|
153
|
+
# [validate_value_block]
|
154
|
+
# ?
|
155
|
+
#
|
156
|
+
# ====Returns:
|
157
|
+
#
|
158
|
+
#
|
74
159
|
def self.add_param(name,
|
75
160
|
value_class,
|
76
161
|
is_required,
|
@@ -132,6 +217,21 @@ class BaseConfig
|
|
132
217
|
end
|
133
218
|
private_class_method :add_param
|
134
219
|
|
220
|
+
#
|
221
|
+
# ====Description:
|
222
|
+
#
|
223
|
+
#
|
224
|
+
# ====Parameters:
|
225
|
+
# [name]
|
226
|
+
# ?
|
227
|
+
# [value_class]
|
228
|
+
# ?
|
229
|
+
# [validate_value_block]
|
230
|
+
# ?
|
231
|
+
#
|
232
|
+
# ====Returns:
|
233
|
+
#
|
234
|
+
#
|
135
235
|
def self.add_required_param(name,
|
136
236
|
value_class,
|
137
237
|
&validate_value_block)
|
@@ -139,6 +239,23 @@ class BaseConfig
|
|
139
239
|
end
|
140
240
|
private_class_method :add_required_param
|
141
241
|
|
242
|
+
#
|
243
|
+
# ====Description:
|
244
|
+
#
|
245
|
+
#
|
246
|
+
# ====Parameters:
|
247
|
+
# [name]
|
248
|
+
# ?
|
249
|
+
# [value_class]
|
250
|
+
# ?
|
251
|
+
# [default_value]
|
252
|
+
# ?
|
253
|
+
# [validate_value_block]
|
254
|
+
# ?
|
255
|
+
#
|
256
|
+
# ====Returns:
|
257
|
+
#
|
258
|
+
#
|
142
259
|
def self.add_optional_param(name,
|
143
260
|
value_class,
|
144
261
|
default_value,
|
@@ -148,6 +265,14 @@ class BaseConfig
|
|
148
265
|
private_class_method :add_optional_param
|
149
266
|
|
150
267
|
attr_reader :containing_object_name
|
268
|
+
|
269
|
+
#
|
270
|
+
# ====Description:
|
271
|
+
#
|
272
|
+
#
|
273
|
+
# ====Returns:
|
274
|
+
#
|
275
|
+
#
|
151
276
|
def initialize
|
152
277
|
@containing_object_name = ""
|
153
278
|
@params_with_values = Set.new()
|
@@ -157,6 +282,17 @@ class BaseConfig
|
|
157
282
|
end
|
158
283
|
end
|
159
284
|
|
285
|
+
#
|
286
|
+
# ====Description:
|
287
|
+
#
|
288
|
+
#
|
289
|
+
# ====Parameters:
|
290
|
+
# [operation_name]
|
291
|
+
# ?
|
292
|
+
#
|
293
|
+
# ====Returns:
|
294
|
+
#
|
295
|
+
#
|
160
296
|
def enforce_specs(operation_name)
|
161
297
|
#
|
162
298
|
# Iterate through the parameters without values. If any are
|
@@ -207,9 +343,17 @@ class BaseConfig
|
|
207
343
|
private :enforce_specs
|
208
344
|
|
209
345
|
#
|
346
|
+
# ====Description:
|
210
347
|
# Because the to_s in Ruby 1.8 for the Array and Hash classes
|
211
348
|
# are horrible...
|
212
|
-
#
|
349
|
+
#
|
350
|
+
# ====Parameters:
|
351
|
+
# [value]
|
352
|
+
# ?
|
353
|
+
#
|
354
|
+
# ====Returns:
|
355
|
+
#
|
356
|
+
#
|
213
357
|
def construct_value_str(value)
|
214
358
|
if(value.is_a?(Array))
|
215
359
|
str = "["
|
@@ -243,6 +387,21 @@ class BaseConfig
|
|
243
387
|
end
|
244
388
|
private :construct_value_str
|
245
389
|
|
390
|
+
#
|
391
|
+
# ====Description:
|
392
|
+
#
|
393
|
+
#
|
394
|
+
# ====Parameters:
|
395
|
+
# [param_name]
|
396
|
+
# ?
|
397
|
+
# [value]
|
398
|
+
# ?
|
399
|
+
# [message]
|
400
|
+
# ?
|
401
|
+
#
|
402
|
+
# ====Returns:
|
403
|
+
#
|
404
|
+
#
|
246
405
|
def construct_error_message(param_name, value, message)
|
247
406
|
if(@containing_object_name.empty?)
|
248
407
|
full_param_name = ""
|
@@ -256,10 +415,32 @@ class BaseConfig
|
|
256
415
|
end
|
257
416
|
private :construct_error_message
|
258
417
|
|
418
|
+
#
|
419
|
+
# ====Description:
|
420
|
+
#
|
421
|
+
#
|
422
|
+
# ====Parameters:
|
423
|
+
# [message]
|
424
|
+
# ?
|
425
|
+
#
|
426
|
+
# ====Returns:
|
427
|
+
#
|
428
|
+
#
|
259
429
|
def raise_error(message)
|
260
430
|
raise Error, message, caller()
|
261
431
|
end
|
262
432
|
|
433
|
+
#
|
434
|
+
# ====Description:
|
435
|
+
#
|
436
|
+
#
|
437
|
+
# ====Parameters:
|
438
|
+
# [rhs]
|
439
|
+
# ?
|
440
|
+
#
|
441
|
+
# ====Returns:
|
442
|
+
#
|
443
|
+
#
|
263
444
|
def ==(rhs)
|
264
445
|
if(rhs == nil)
|
265
446
|
return false
|
@@ -274,6 +455,19 @@ class BaseConfig
|
|
274
455
|
return true
|
275
456
|
end
|
276
457
|
|
458
|
+
#
|
459
|
+
# ====Description:
|
460
|
+
#
|
461
|
+
#
|
462
|
+
# ====Parameters:
|
463
|
+
# [value_class]
|
464
|
+
# ?
|
465
|
+
# [value]
|
466
|
+
# ?
|
467
|
+
#
|
468
|
+
# ====Returns:
|
469
|
+
#
|
470
|
+
#
|
277
471
|
def dump_value_impl(value_class, value)
|
278
472
|
if(value_class < BaseConfig)
|
279
473
|
return value.dump_impl({})
|
@@ -289,6 +483,17 @@ class BaseConfig
|
|
289
483
|
end
|
290
484
|
private :dump_value_impl
|
291
485
|
|
486
|
+
#
|
487
|
+
# ====Description:
|
488
|
+
#
|
489
|
+
#
|
490
|
+
# ====Parameters:
|
491
|
+
# [containing_object_hash]
|
492
|
+
# ?
|
493
|
+
#
|
494
|
+
# ====Returns:
|
495
|
+
#
|
496
|
+
#
|
292
497
|
def dump_impl(containing_object_hash)
|
293
498
|
#
|
294
499
|
# Configuration never will be dumped without the
|
@@ -304,6 +509,17 @@ class BaseConfig
|
|
304
509
|
end
|
305
510
|
protected :dump_impl
|
306
511
|
|
512
|
+
#
|
513
|
+
# ====Description:
|
514
|
+
#
|
515
|
+
#
|
516
|
+
# ====Parameters:
|
517
|
+
# [writer]
|
518
|
+
# ?
|
519
|
+
#
|
520
|
+
# ====Returns:
|
521
|
+
#
|
522
|
+
#
|
307
523
|
def dump(writer)
|
308
524
|
dump_hash = {}
|
309
525
|
containing_object_hash = dump_hash
|
@@ -318,6 +534,21 @@ class BaseConfig
|
|
318
534
|
writer.write(dump_hash)
|
319
535
|
end
|
320
536
|
|
537
|
+
#
|
538
|
+
# ====Description:
|
539
|
+
#
|
540
|
+
#
|
541
|
+
# ====Parameters:
|
542
|
+
# [param_name]
|
543
|
+
# ?
|
544
|
+
# [value_class]
|
545
|
+
# ?
|
546
|
+
# [value]
|
547
|
+
# ?
|
548
|
+
#
|
549
|
+
# ====Returns:
|
550
|
+
#
|
551
|
+
#
|
321
552
|
def load_value_impl(param_name, value_class, value)
|
322
553
|
if(value.class <= value_class)
|
323
554
|
#
|
@@ -409,6 +640,19 @@ class BaseConfig
|
|
409
640
|
end
|
410
641
|
private :load_value_impl
|
411
642
|
|
643
|
+
#
|
644
|
+
# ====Description:
|
645
|
+
#
|
646
|
+
#
|
647
|
+
# ====Parameters:
|
648
|
+
# [containing_object_hash]
|
649
|
+
# ?
|
650
|
+
# [containing_object_name]
|
651
|
+
# ?
|
652
|
+
#
|
653
|
+
# ====Returns:
|
654
|
+
#
|
655
|
+
#
|
412
656
|
def load_impl(containing_object_hash, containing_object_name)
|
413
657
|
@containing_object_name = containing_object_name
|
414
658
|
@params_with_values.clear()
|
@@ -438,6 +682,19 @@ class BaseConfig
|
|
438
682
|
end
|
439
683
|
protected :load_impl
|
440
684
|
|
685
|
+
#
|
686
|
+
# ====Description:
|
687
|
+
#
|
688
|
+
#
|
689
|
+
# ====Parameters:
|
690
|
+
# [reader]
|
691
|
+
# ?
|
692
|
+
# [containing_object_name = ""]
|
693
|
+
# ?
|
694
|
+
#
|
695
|
+
# ====Returns:
|
696
|
+
#
|
697
|
+
#
|
441
698
|
def load(reader, containing_object_name = "")
|
442
699
|
param_hash = reader.read
|
443
700
|
|
@@ -478,12 +735,42 @@ class BaseConfig
|
|
478
735
|
load_impl(containing_object_hash, containing_object_name)
|
479
736
|
end
|
480
737
|
|
738
|
+
#
|
739
|
+
# ====Description:
|
740
|
+
#
|
741
|
+
#
|
742
|
+
# ====Parameters:
|
743
|
+
# [reader]
|
744
|
+
# ?
|
745
|
+
# [containing_object_name = ""]
|
746
|
+
# ?
|
747
|
+
#
|
748
|
+
# ====Returns:
|
749
|
+
#
|
750
|
+
#
|
481
751
|
def self.load(reader, containing_object_name = "")
|
482
752
|
instance = new()
|
483
753
|
instance.load(reader, containing_object_name)
|
484
754
|
return instance
|
485
755
|
end
|
486
756
|
|
757
|
+
#
|
758
|
+
# ====Description:
|
759
|
+
#
|
760
|
+
#
|
761
|
+
# ====Parameters:
|
762
|
+
# [str]
|
763
|
+
# ?
|
764
|
+
# [indent]
|
765
|
+
# ?
|
766
|
+
# [value_class]
|
767
|
+
# ?
|
768
|
+
# [value]
|
769
|
+
# ?
|
770
|
+
#
|
771
|
+
# ====Returns:
|
772
|
+
#
|
773
|
+
#
|
487
774
|
def write_value_impl(str, indent, value_class, value)
|
488
775
|
nesting_indent = indent + NESTING_INDENT
|
489
776
|
if(value != nil)
|
@@ -522,6 +809,19 @@ class BaseConfig
|
|
522
809
|
end
|
523
810
|
private :write_value_impl
|
524
811
|
|
812
|
+
#
|
813
|
+
# ====Description:
|
814
|
+
#
|
815
|
+
#
|
816
|
+
# ====Parameters:
|
817
|
+
# [str]
|
818
|
+
# ?
|
819
|
+
# [indent]
|
820
|
+
# ?
|
821
|
+
#
|
822
|
+
# ====Returns:
|
823
|
+
#
|
824
|
+
#
|
525
825
|
def write_impl(str, indent)
|
526
826
|
self.class.param_spec_list.each do |param_spec|
|
527
827
|
name_field_length = self.class.longest_param_name_length
|
@@ -533,6 +833,13 @@ class BaseConfig
|
|
533
833
|
end
|
534
834
|
protected :write_impl
|
535
835
|
|
836
|
+
#
|
837
|
+
# ====Description:
|
838
|
+
#
|
839
|
+
#
|
840
|
+
# ====Returns:
|
841
|
+
#
|
842
|
+
#
|
536
843
|
def to_s
|
537
844
|
#
|
538
845
|
# Print out config file name and the containing object_name and then
|
@@ -2,13 +2,19 @@
|
|
2
2
|
module ConfigToolkit
|
3
3
|
|
4
4
|
#
|
5
|
-
# All exceptions thrown from the
|
6
|
-
# this one;
|
5
|
+
# All exceptions thrown from the ConfigToolkit descend from
|
6
|
+
# this one; while right now it is the only exception thrown
|
7
|
+
# from the ConfigToolkit, at some point, an exception class hierarchy
|
7
8
|
# rooted in this class might be developed.
|
8
9
|
#
|
9
10
|
class Error < RuntimeError; end
|
10
11
|
|
11
12
|
end
|
12
13
|
|
14
|
+
#
|
15
|
+
# Load up the files necessary to specify a config.
|
16
|
+
# Users will need to load explicitly whichever readers
|
17
|
+
# and writers they wish to use.
|
18
|
+
#
|
13
19
|
require 'configtoolkit/types'
|
14
20
|
require 'configtoolkit/baseconfig'
|
data/lib/configtoolkit/types.rb
CHANGED
@@ -3,27 +3,27 @@ module ConfigToolkit
|
|
3
3
|
|
4
4
|
#
|
5
5
|
# Since Ruby does not have a boolean type (TrueClass and FalseClass classes
|
6
|
-
# exist, but they descend from
|
7
|
-
# can be passed into the BaseConfig methods
|
8
|
-
# to indicate that the parameter is a boolean
|
9
|
-
# be FalseClass or TrueClass, however).
|
6
|
+
# for boolean values exist, but they descend from Object),
|
7
|
+
# define an empty marker class that can be passed into the BaseConfig methods
|
8
|
+
# to add new parameters in order to indicate that the parameter is a boolean
|
9
|
+
# (the value of the parameter will be FalseClass or TrueClass, however).
|
10
10
|
#
|
11
11
|
class Boolean; end
|
12
12
|
|
13
13
|
#
|
14
14
|
# The ConstrainedArray models an Array with a specified size
|
15
|
-
# and with all elements being a specified
|
16
|
-
# the arrays generally offerred by
|
15
|
+
# and with all elements being a specified class (basically, it models
|
16
|
+
# the arrays generally offerred by statically typed languages).
|
17
17
|
# A ConstrainedArray has:
|
18
|
-
# 1.) A minimum number of elements
|
19
|
-
# 2.) A maximum number of elements
|
20
|
-
# 3.) An element
|
18
|
+
# 1.) A minimum number of elements (could be zero)
|
19
|
+
# 2.) A maximum number of elements (could be infinity)
|
20
|
+
# 3.) An element class
|
21
21
|
#
|
22
22
|
# A future enhancement might be to allow users to specify a different
|
23
|
-
#
|
24
|
-
# elements to be instances of a child class of its element
|
25
|
-
# just instances of its element
|
26
|
-
#
|
23
|
+
# class for each element. Note that the ConstrainedArray also allows
|
24
|
+
# elements to be instances of a child class of its element class, not
|
25
|
+
# just instances of its element class. Thus, a ConstrainedArray containing
|
26
|
+
# class Object essentially would have no class constraints.
|
27
27
|
#
|
28
28
|
# class ConstrainedArray actually is a class generator, similar to Struct.
|
29
29
|
# Its new() method does *not* return a ConstrainedArray instance, but
|
@@ -31,7 +31,7 @@ class Boolean; end
|
|
31
31
|
# descends from ConstrainedArray. The class returned by new() is meant
|
32
32
|
# to be used in the BaseConfig methods to add new parameters. The
|
33
33
|
# value of one of these parameters actually will be a native Ruby
|
34
|
-
# Array,
|
34
|
+
# Array, but one that satisifes the constraints contained in
|
35
35
|
# the ConstrainedArray class.
|
36
36
|
#
|
37
37
|
class ConstrainedArray
|
@@ -45,6 +45,32 @@ class ConstrainedArray
|
|
45
45
|
attr_reader :max_num_elements
|
46
46
|
end
|
47
47
|
|
48
|
+
#
|
49
|
+
# ====Description:
|
50
|
+
# This method does *not* return a ConstrainedArray instance. Instead,
|
51
|
+
# it returns a new ConstrainedArray child class that represents
|
52
|
+
# an array with the constraints specified in the method arguments.
|
53
|
+
# This class can be passed as a parameter class into the BaseConfig methods
|
54
|
+
# to add parameters.
|
55
|
+
#
|
56
|
+
# ====Parameters:
|
57
|
+
# [element_class]
|
58
|
+
# This constrains all elements of the generated ConstrainedArray
|
59
|
+
# class to be of this class or one of its child classes.
|
60
|
+
# If this argument is object, then this constraint effectively
|
61
|
+
# disappears.
|
62
|
+
# [min_num_elements = nil]
|
63
|
+
# This constrains the generated ConstrainedArray class to have
|
64
|
+
# at least min_num_elements elements; if this argument is nil or zero,
|
65
|
+
# the constraint effectively disappears.
|
66
|
+
# [max_num_elements = nil]
|
67
|
+
# This constrains the generated ConstrainedArray class to have
|
68
|
+
# at most max_num_elements elements; if this argument is nil,
|
69
|
+
# the constraint effectively disappears.
|
70
|
+
#
|
71
|
+
# ====Returns:
|
72
|
+
# A ConstrainedArray child class with the specified constraints.
|
73
|
+
#
|
48
74
|
def self.new(element_class, min_num_elements = nil, max_num_elements = nil)
|
49
75
|
return Class.new(ConstrainedArray) do
|
50
76
|
@element_class = element_class
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configtoolkit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- DesigningPatterns
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-05-
|
12
|
+
date: 2008-05-14 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|