configtoolkit 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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