configtoolkit 1.0.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.
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ module ConfigToolkit
3
+
4
+ #
5
+ # All exceptions thrown from the Toolkit descend from
6
+ # this one; at some point, an exception class hierarchy
7
+ # rooted in this class might be developed.
8
+ #
9
+ class Error < RuntimeError; end
10
+
11
+ VERSION = '1.0.0'
12
+
13
+ end
14
+
15
+ require 'configtoolkit/types'
16
+ require 'configtoolkit/baseconfig'
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+ module ConfigToolkit
3
+
4
+ #
5
+ # Since Ruby does not have a boolean type (TrueClass and FalseClass classes
6
+ # exist, but they descend from object), define an empty marker class that
7
+ # can be passed into the BaseConfig methods to add new parameters in order
8
+ # to indicate that the parameter is a boolean (the value of the parameter will
9
+ # be FalseClass or TrueClass, however).
10
+ #
11
+ class Boolean; end
12
+
13
+ #
14
+ # The ConstrainedArray models an Array with a specified size
15
+ # and with all elements being a specified type (basically, it models
16
+ # the arrays generally offerred by static typing languages).
17
+ # A ConstrainedArray has:
18
+ # 1.) A minimum number of elements
19
+ # 2.) A maximum number of elements
20
+ # 3.) An element type
21
+ #
22
+ # A future enhancement might be to allow users to specify a different
23
+ # type for each element. Note that the Constrained Array also allows
24
+ # elements to be instances of a child class of its element type, not
25
+ # just instances of its element type. Thus, a ConstrainedArray containing
26
+ # type Object essentially would have no type constraints.
27
+ #
28
+ # class ConstrainedArray actually is a class generator, similar to Struct.
29
+ # Its new() method does *not* return a ConstrainedArray instance, but
30
+ # instead returns a new class with the specified constraints that
31
+ # descends from ConstrainedArray. The class returned by new() is meant
32
+ # to be used in the BaseConfig methods to add new parameters. The
33
+ # value of one of these parameters actually will be a native Ruby
34
+ # Array, just one that satisifes the constraints contained in
35
+ # the ConstrainedArray class.
36
+ #
37
+ class ConstrainedArray
38
+ #
39
+ # Define an accessor for some class instance variables used to
40
+ # store the constraints.
41
+ #
42
+ class << self
43
+ attr_reader :element_class
44
+ attr_reader :min_num_elements
45
+ attr_reader :max_num_elements
46
+ end
47
+
48
+ def self.new(element_class, min_num_elements = nil, max_num_elements = nil)
49
+ return Class.new(ConstrainedArray) do
50
+ @element_class = element_class
51
+ @min_num_elements = min_num_elements
52
+ @max_num_elements = max_num_elements
53
+ end
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ require 'yaml'
3
+
4
+ module ConfigToolkit
5
+
6
+ class YAMLReader
7
+ def initialize(stream)
8
+ if(stream.class == String)
9
+ @stream = File.open(stream, "r")
10
+ else
11
+ @stream = stream
12
+ end
13
+ end
14
+
15
+ def read
16
+ return YAML::load(@stream)
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+ require 'yaml'
3
+
4
+ module ConfigToolkit
5
+
6
+ class YAMLWriter
7
+ def initialize(stream, only_output_standard_yaml_types)
8
+ if(stream.class == String)
9
+ @stream = File.open(stream, "w")
10
+ else
11
+ @stream = stream
12
+ end
13
+
14
+ @only_output_standard_yaml_types = only_output_standard_yaml_types
15
+ end
16
+
17
+ def convert_value_to_standard_yaml_type(param_value)
18
+ if(param_value.class == Hash)
19
+ return convert_hash_values_to_standard_yaml_types(param_value)
20
+ elsif(param_value.class == Array)
21
+ new_param_value = []
22
+
23
+ param_value.each do |element|
24
+ new_param_value.push(convert_value_to_standard_yaml_type(element))
25
+ end
26
+
27
+ return new_param_value
28
+ elsif((param_value.class <= Integer) ||
29
+ (param_value.class <= Float) ||
30
+ (param_value.class == TrueClass) ||
31
+ (param_value.class == FalseClass) ||
32
+ (param_value.class == String))
33
+ return param_value
34
+ else
35
+ return param_value.to_s
36
+ end
37
+ end
38
+
39
+ def convert_hash_values_to_standard_yaml_types(config_hash)
40
+ standard_yaml_typed_config_hash = {}
41
+
42
+ config_hash.each do |param_name, param_value|
43
+ standard_yaml_typed_config_hash[param_name] = convert_value_to_standard_yaml_type(param_value)
44
+ end
45
+
46
+ return standard_yaml_typed_config_hash
47
+ end
48
+
49
+ def write(config_hash)
50
+ if(@only_output_standard_yaml_types)
51
+ output_config_hash = convert_hash_values_to_standard_yaml_types(config_hash)
52
+ else
53
+ output_config_hash = config_hash
54
+ end
55
+
56
+ YAML::dump(output_config_hash, @stream)
57
+ @stream.flush()
58
+ end
59
+ end
60
+
61
+ end
@@ -0,0 +1,3 @@
1
+ - 1
2
+ - 2
3
+ - 3
data/test/common.rb ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ def get_test_config_file_name(config_file_base_name)
4
+ return (Pathname.new(__FILE__).dirname() + config_file_base_name).to_s()
5
+ end
@@ -0,0 +1,22 @@
1
+ ---
2
+ contained_sample:
3
+ opt_integer: 42
4
+ req_uri: http://www.designingpatterns.com
5
+ req_float: 5.678
6
+ req_pathname: /usr/designingpatterns
7
+ req_integer: 5
8
+ req_string: sample string
9
+ req_boolean: false
10
+ req_symbol: sample_symbol
11
+ req_big_integer: 10000000000
12
+ nested_config:
13
+ req_nested_array:
14
+ - req_second_nested_pathname: /usr/designingpatterns/Applications
15
+ req_second_nested_array:
16
+ - 5
17
+ - 19
18
+ - req_second_nested_pathname: /usr/designingpatterns/Applications/etc
19
+ req_second_nested_array:
20
+ - 200
21
+ - 201
22
+ req_nested_integer: 33
@@ -0,0 +1,11 @@
1
+ ---
2
+ firewall:
3
+ name: durian
4
+ architecture: ultrasparc
5
+ os: Solaris
6
+ num_cpus: 8
7
+ contains_sensitive_data: false
8
+ behind_firewall: false
9
+ addresses:
10
+ - http://firewall.designingpatterns.com
11
+ - http://durian.designingpatterns.com
@@ -0,0 +1,100 @@
1
+ name: apple
2
+ architecture: powerpc
3
+ os: AIX
4
+ num_cpus: 32
5
+ behind_firewall: no
6
+ contains_sensitive_data: no
7
+ addresses:
8
+ - http://default.designingpatterns.com
9
+ - http://apple.designingpatterns.com
10
+
11
+ production:
12
+ name: orange
13
+ architecture: ultrasparc
14
+ os: Solaris
15
+ num_cpus: 64
16
+ contains_sensitive_data: yes
17
+ addresses:
18
+ - http://production.designingpatterns.com
19
+ - http://orange.designingpatterns.com
20
+
21
+ test:
22
+ name: bananna
23
+ architecture: itanium
24
+ os: Linux
25
+ num_cpus: 16
26
+ contains_sensitive_data: no
27
+ addresses:
28
+ - http://test.designingpatterns.com
29
+ - http://bananna.designingpatterns.com
30
+
31
+ bad_containing_object: 3
32
+
33
+ missing_num_cpus:
34
+ name: bananna
35
+ architecture: itanium
36
+ os: Linux
37
+ contains_sensitive_data: no
38
+ addresses:
39
+ - http://test.designingpatterns.com
40
+ - http://bananna.designingpatterns.com
41
+
42
+ missing_name_and_num_cpus:
43
+ architecture: itanium
44
+ os: Linux
45
+ contains_sensitive_data: no
46
+ addresses:
47
+ - http://test.designingpatterns.com
48
+ - http://bananna.designingpatterns.com
49
+
50
+ bad_num_cpus:
51
+ name: bananna
52
+ architecture: itanium
53
+ os: Linux
54
+ num_cpus: -2
55
+ contains_sensitive_data: no
56
+ addresses:
57
+ - http://test.designingpatterns.com
58
+ - http://bananna.designingpatterns.com
59
+
60
+ bad_addresses_element_type:
61
+ name: bananna
62
+ architecture: itanium
63
+ os: Linux
64
+ num_cpus: -2
65
+ contains_sensitive_data: no
66
+ addresses:
67
+ - 2
68
+ - http://bananna.designingpatterns.com
69
+
70
+ bad_addresses_max_num_elements:
71
+ name: bananna
72
+ architecture: itanium
73
+ os: Linux
74
+ num_cpus: -2
75
+ contains_sensitive_data: no
76
+ addresses:
77
+ - http://test.designingpatterns.com
78
+ - http://bananna.designingpatterns.com
79
+ - http://fruitsalad.designingpatterns.com
80
+ - http://parfait.designingpatterns.com
81
+
82
+ bad_addresses_min_num_elements:
83
+ name: bananna
84
+ architecture: itanium
85
+ os: Linux
86
+ num_cpus: -2
87
+ contains_sensitive_data: no
88
+ addresses:
89
+ - http://bananna.designingpatterns.com
90
+
91
+ bad_contains_sensitive_data_behind_firewall_combo:
92
+ name: bananna
93
+ architecture: itanium
94
+ os: Linux
95
+ num_cpus: 4
96
+ contains_sensitive_data: yes
97
+ behind_firewall: no
98
+ addresses:
99
+ - http://test.designingpatterns.com
100
+ - http://bananna.designingpatterns.com
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'configtoolkit'
4
+
5
+ require 'pathname'
6
+ require 'singleton'
7
+ require 'uri'
8
+
9
+ class SampleSecondNestedConfig < ConfigToolkit::BaseConfig
10
+ add_required_param(:req_second_nested_pathname, Pathname)
11
+ add_required_param(:req_second_nested_array,
12
+ ConfigToolkit::ConstrainedArray.new(Integer, 2, 2))
13
+ end
14
+
15
+ class SampleNestedConfig < ConfigToolkit::BaseConfig
16
+ add_required_param(:req_nested_integer, Integer)
17
+ add_required_param(:req_nested_array,
18
+ ConfigToolkit::ConstrainedArray.new(SampleSecondNestedConfig))
19
+ end
20
+
21
+ class SampleConfig < ConfigToolkit::BaseConfig
22
+ add_required_param(:req_integer, Integer)
23
+ add_required_param(:req_big_integer, Integer)
24
+ add_required_param(:req_float, Float)
25
+ add_required_param(:req_string, String)
26
+ add_required_param(:req_boolean, ConfigToolkit::Boolean)
27
+ add_required_param(:req_pathname, Pathname)
28
+ add_required_param(:req_uri, URI)
29
+ add_required_param(:req_symbol, Symbol)
30
+ add_required_param(:nested_config, SampleNestedConfig)
31
+ add_optional_param(:opt_integer, Fixnum, 123454321)
32
+ end
33
+
34
+ REFERENCE_SAMPLE_CONFIG = SampleConfig.new()
35
+ REFERENCE_SAMPLE_CONFIG.req_integer = 6
36
+ REFERENCE_SAMPLE_CONFIG.req_big_integer = 90000000000
37
+ REFERENCE_SAMPLE_CONFIG.req_float = 3.14
38
+ REFERENCE_SAMPLE_CONFIG.req_string = "sample string2"
39
+ REFERENCE_SAMPLE_CONFIG.req_boolean = true
40
+ REFERENCE_SAMPLE_CONFIG.req_pathname = Pathname.new("/usr/designingpatterns/bin")
41
+ REFERENCE_SAMPLE_CONFIG.req_uri = URI("http://blogs.designingpatterns.com")
42
+ REFERENCE_SAMPLE_CONFIG.req_symbol = :sample_symbol2
43
+ REFERENCE_SAMPLE_CONFIG.nested_config = SampleNestedConfig.new()
44
+ REFERENCE_SAMPLE_CONFIG.nested_config.req_nested_integer = 34
45
+ REFERENCE_SAMPLE_CONFIG.nested_config.req_nested_array =
46
+ [
47
+ SampleSecondNestedConfig.new(),
48
+ SampleSecondNestedConfig.new()
49
+ ]
50
+ REFERENCE_SAMPLE_CONFIG.nested_config.req_nested_array[0].req_second_nested_pathname = Pathname.new("/usr/designingpatterns/Applications/pattmake")
51
+ REFERENCE_SAMPLE_CONFIG.nested_config.req_nested_array[0].req_second_nested_array = [6, 20]
52
+ REFERENCE_SAMPLE_CONFIG.nested_config.req_nested_array[1].req_second_nested_pathname = Pathname.new("/usr")
53
+ REFERENCE_SAMPLE_CONFIG.nested_config.req_nested_array[1].req_second_nested_array = [205, 206]
54
+ REFERENCE_SAMPLE_CONFIG.opt_integer = 56
55
+
56
+ REFERENCE_CONTAINED_SAMPLE_CONFIG = SampleConfig.new()
57
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.req_integer = 5
58
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.req_big_integer = 10000000000
59
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.req_float = 5.678
60
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.req_string = "sample string"
61
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.req_boolean = false
62
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.req_pathname = Pathname.new("/usr/designingpatterns")
63
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.req_uri = URI("http://www.designingpatterns.com")
64
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.req_symbol = :sample_symbol
65
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config = SampleNestedConfig.new()
66
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_integer = 33
67
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_array =
68
+ [
69
+ SampleSecondNestedConfig.new(),
70
+ SampleSecondNestedConfig.new()
71
+ ]
72
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_array[0].req_second_nested_pathname = Pathname.new("/usr/designingpatterns/Applications")
73
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_array[0].req_second_nested_array = [5, 19]
74
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_array[1].req_second_nested_pathname = Pathname.new("/usr/designingpatterns/Applications/etc")
75
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.nested_config.req_nested_array[1].req_second_nested_array = [200, 201]
76
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.opt_integer = 42
77
+ REFERENCE_CONTAINED_SAMPLE_CONFIG.instance_variable_set(:@containing_object_name, "contained_sample")
78
+
79
+ module ReaderWriterTest
80
+ def run_reader_test(reader_class,
81
+ containing_object_name,
82
+ reference_config,
83
+ *reader_constructor_args)
84
+ reader = reader_class.new(*reader_constructor_args)
85
+ config = SampleConfig.load(reader, containing_object_name)
86
+ assert_equal(reference_config, config)
87
+ end
88
+
89
+ def get_sorted_file_contents(file_name)
90
+ file_contents = File.open(file_name, "r") do |file|
91
+ file.read()
92
+ end
93
+
94
+ return file_contents.split("\n").sort().join("\n").to_s()
95
+ end
96
+
97
+ def run_writer_test(writer_class,
98
+ reference_config,
99
+ reference_file_name,
100
+ dump_file_name,
101
+ *writer_constructor_args)
102
+ writer = writer_class.new(*writer_constructor_args)
103
+ reference_config.dump(writer)
104
+
105
+ assert_equal(get_sorted_file_contents(reference_file_name),
106
+ get_sorted_file_contents(dump_file_name))
107
+ end
108
+
109
+ def run_reader_writer_test(reader_class,
110
+ writer_class,
111
+ reference_config,
112
+ reader_constructor_args,
113
+ writer_constructor_args)
114
+ writer = writer_class.new(*writer_constructor_args)
115
+ reference_config.dump(writer)
116
+
117
+ reader = reader_class.new(*reader_constructor_args)
118
+ config = SampleConfig.load(reader, reference_config.containing_object_name)
119
+
120
+ assert_equal(reference_config, config)
121
+ end
122
+ end
@@ -0,0 +1,34 @@
1
+ ---
2
+ opt_integer: 56
3
+ req_uri: !ruby/object:URI::HTTP
4
+ fragment:
5
+ host: blogs.designingpatterns.com
6
+ opaque:
7
+ password:
8
+ path: ""
9
+ port: 80
10
+ query:
11
+ registry:
12
+ scheme: http
13
+ user:
14
+ req_float: 3.14
15
+ req_pathname: !ruby/object:Pathname
16
+ path: /usr/designingpatterns/bin
17
+ req_symbol: :sample_symbol2
18
+ req_boolean: true
19
+ req_string: sample string2
20
+ req_integer: 6
21
+ req_big_integer: 90000000000
22
+ nested_config:
23
+ req_nested_array:
24
+ - req_second_nested_pathname: !ruby/object:Pathname
25
+ path: /usr/designingpatterns/Applications/pattmake
26
+ req_second_nested_array:
27
+ - 6
28
+ - 20
29
+ - req_second_nested_pathname: !ruby/object:Pathname
30
+ path: /usr
31
+ req_second_nested_array:
32
+ - 205
33
+ - 206
34
+ req_nested_integer: 34