configmanager 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/configmanager.rb +27 -26
- data/lib/configmanager/combined_configuration.rb +65 -65
- data/lib/configmanager/configuration.rb +168 -165
- data/lib/configmanager/exceptions.rb +18 -18
- data/lib/configmanager/interpolators.rb +65 -65
- data/lib/configmanager/loaders.rb +182 -182
- data/lib/configmanager/version.rb +8 -8
- data/lib/samples/test 1.properties +17 -17
- data/lib/samples/test 1.yaml +14 -14
- data/lib/samples/test 2.properties +9 -9
- data/lib/samples/test 2.yaml +8 -8
- data/lib/test_configmanager.rb +28 -26
- metadata +57 -26
- data/lib/options_arg.rb +0 -66
data/lib/configmanager.rb
CHANGED
@@ -1,27 +1,28 @@
|
|
1
|
-
#
|
2
|
-
# 16 Jul 2012
|
3
|
-
#
|
4
|
-
|
5
|
-
require "
|
6
|
-
|
7
|
-
|
8
|
-
require "configmanager/
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# @param [
|
19
|
-
# @param [
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
configuration
|
25
|
-
|
26
|
-
|
1
|
+
#
|
2
|
+
# 16 Jul 2012
|
3
|
+
#
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
require "options_arg"
|
7
|
+
|
8
|
+
require "configmanager/configuration"
|
9
|
+
require "configmanager/loaders"
|
10
|
+
|
11
|
+
# General purpose configuration manager.
|
12
|
+
# Loads properties from YAML files and makes them available through a same hash like interface.
|
13
|
+
# Supports ${} and $() style references. All references are evaluated only when a property's value is requested.
|
14
|
+
module ConfigManager
|
15
|
+
|
16
|
+
# Loads properties from the specified file.
|
17
|
+
#
|
18
|
+
# @param [String] file_path the file to load properties from.
|
19
|
+
# @param [Object] loader any object that can respond to the 'load_properties(file_path, configuration)' method and return a hash.
|
20
|
+
# @param [ConfigManager::Configuration] configuration the configuration to load the properties into.
|
21
|
+
#
|
22
|
+
# @return [ConfigManager::Configuration] the configuration object wrapping the properties loaded from the file.
|
23
|
+
def self.load_from_file(file_path, loader = YAMLPropertiesLoader, configuration = ConfigManager::Configuration.new())
|
24
|
+
loader.load_properties(file_path, configuration)
|
25
|
+
configuration
|
26
|
+
end
|
27
|
+
|
27
28
|
end
|
@@ -1,65 +1,65 @@
|
|
1
|
-
#
|
2
|
-
# 20 Jul 2012
|
3
|
-
#
|
4
|
-
|
5
|
-
require "configmanager/configuration"
|
6
|
-
require "configmanager/exceptions"
|
7
|
-
|
8
|
-
module ConfigManager
|
9
|
-
|
10
|
-
# A configuration class that can merge multiple configuration trees into a single configuration tree.
|
11
|
-
# Each addition, overwrites any properties that already existed.
|
12
|
-
class CombinedConfiguration < ConfigManager::Configuration
|
13
|
-
|
14
|
-
# Creates a new empty combined configuration.
|
15
|
-
#
|
16
|
-
# @param [Hash] options configuration options. Supported keys are:
|
17
|
-
# :interpolator - an object that can respond to the 'interpolate' method. Default is the DefaultInterpolator.
|
18
|
-
# :use_interpolator - global flag to specify if the interpolator should be used for this configuration. Default is true.
|
19
|
-
def initialize(options = {})
|
20
|
-
super
|
21
|
-
|
22
|
-
@configurations = {}
|
23
|
-
end
|
24
|
-
|
25
|
-
# Adds a configuration to be merged into this configuration. All existing properties are overwritten.
|
26
|
-
#
|
27
|
-
# @param [String] name a unique name for this configuration, it can be retrieved later with this name.
|
28
|
-
# @param [ConfigManager::Configuration] configuration the configuration to be merged.
|
29
|
-
#
|
30
|
-
# @return [NilClass]
|
31
|
-
def add_configuration(name, configuration)
|
32
|
-
raise ConfigManager::KeyError.new("Cannot add - Configuration '#{name}' already exists!") if @configurations.has_key?(name)
|
33
|
-
@configurations[name] = configuration
|
34
|
-
merge_configuration(configuration)
|
35
|
-
|
36
|
-
nil
|
37
|
-
end
|
38
|
-
|
39
|
-
# Get the configuration identified by the specified name. Raises an exception if the configuration does not exist.
|
40
|
-
# Modifying the returned configuration does not update this combined configuration.
|
41
|
-
#
|
42
|
-
# @param [String] name the configuration to get.
|
43
|
-
#
|
44
|
-
# @return [ConfigManager::Configuration] the configuration.
|
45
|
-
def get_configuration(name)
|
46
|
-
raise ConfigManager::PropertyNotFoundError("Cannot get - Configuration '#{name}' does not exist!") unless @configurations.has_key?(name)
|
47
|
-
@configurations[name]
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
# Merges the specified configuration with this configuration. Existing nodes are overwritten!
|
53
|
-
#
|
54
|
-
# @param [ConfigManager::Configuration] configuration the configuration to merge.
|
55
|
-
#
|
56
|
-
# @return [NilClass]
|
57
|
-
def merge_configuration(configuration)
|
58
|
-
values = configuration.get_property("")
|
59
|
-
at = ""
|
60
|
-
add_properties(values, at, :overwrite => true)
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
1
|
+
#
|
2
|
+
# 20 Jul 2012
|
3
|
+
#
|
4
|
+
|
5
|
+
require "configmanager/configuration"
|
6
|
+
require "configmanager/exceptions"
|
7
|
+
|
8
|
+
module ConfigManager
|
9
|
+
|
10
|
+
# A configuration class that can merge multiple configuration trees into a single configuration tree.
|
11
|
+
# Each addition, overwrites any properties that already existed.
|
12
|
+
class CombinedConfiguration < ConfigManager::Configuration
|
13
|
+
|
14
|
+
# Creates a new empty combined configuration.
|
15
|
+
#
|
16
|
+
# @param [Hash] options configuration options. Supported keys are:
|
17
|
+
# :interpolator - an object that can respond to the 'interpolate' method. Default is the DefaultInterpolator.
|
18
|
+
# :use_interpolator - global flag to specify if the interpolator should be used for this configuration. Default is true.
|
19
|
+
def initialize(options = {})
|
20
|
+
super
|
21
|
+
|
22
|
+
@configurations = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
# Adds a configuration to be merged into this configuration. All existing properties are overwritten.
|
26
|
+
#
|
27
|
+
# @param [String] name a unique name for this configuration, it can be retrieved later with this name.
|
28
|
+
# @param [ConfigManager::Configuration] configuration the configuration to be merged.
|
29
|
+
#
|
30
|
+
# @return [NilClass]
|
31
|
+
def add_configuration(name, configuration)
|
32
|
+
raise ConfigManager::KeyError.new("Cannot add - Configuration '#{name}' already exists!") if @configurations.has_key?(name)
|
33
|
+
@configurations[name] = configuration
|
34
|
+
merge_configuration(configuration)
|
35
|
+
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get the configuration identified by the specified name. Raises an exception if the configuration does not exist.
|
40
|
+
# Modifying the returned configuration does not update this combined configuration.
|
41
|
+
#
|
42
|
+
# @param [String] name the configuration to get.
|
43
|
+
#
|
44
|
+
# @return [ConfigManager::Configuration] the configuration.
|
45
|
+
def get_configuration(name)
|
46
|
+
raise ConfigManager::PropertyNotFoundError("Cannot get - Configuration '#{name}' does not exist!") unless @configurations.has_key?(name)
|
47
|
+
@configurations[name]
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Merges the specified configuration with this configuration. Existing nodes are overwritten!
|
53
|
+
#
|
54
|
+
# @param [ConfigManager::Configuration] configuration the configuration to merge.
|
55
|
+
#
|
56
|
+
# @return [NilClass]
|
57
|
+
def merge_configuration(configuration)
|
58
|
+
values = configuration.get_property("")
|
59
|
+
at = ""
|
60
|
+
add_properties(values, at, :overwrite => true)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -1,165 +1,168 @@
|
|
1
|
-
#
|
2
|
-
# 20 Jul 2012
|
3
|
-
#
|
4
|
-
|
5
|
-
require "configmanager/exceptions"
|
6
|
-
require "configmanager/interpolators"
|
7
|
-
|
8
|
-
module ConfigManager
|
9
|
-
|
10
|
-
# Represents a collection of properties stored as a hash.
|
11
|
-
class Configuration
|
12
|
-
|
13
|
-
# Creates a new empty configuration.
|
14
|
-
#
|
15
|
-
# @param [Hash] options configuration options. Supported keys are:
|
16
|
-
# :interpolator - an object that can respond to the 'interpolate' method. Default is the DefaultInterpolator.
|
17
|
-
# :use_interpolator - global flag to specify if the interpolator should be used for this configuration. Default is true.
|
18
|
-
|
19
|
-
|
20
|
-
@
|
21
|
-
@
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
#
|
27
|
-
#
|
28
|
-
# @param [Hash]
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
# @param [
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
at_array =
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
# :
|
83
|
-
# :
|
84
|
-
# :
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
#
|
103
|
-
final_value
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
#
|
127
|
-
#
|
128
|
-
# @
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# If the
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
1
|
+
#
|
2
|
+
# 20 Jul 2012
|
3
|
+
#
|
4
|
+
|
5
|
+
require "configmanager/exceptions"
|
6
|
+
require "configmanager/interpolators"
|
7
|
+
|
8
|
+
module ConfigManager
|
9
|
+
|
10
|
+
# Represents a collection of properties stored as a hash.
|
11
|
+
class Configuration
|
12
|
+
|
13
|
+
# Creates a new empty configuration.
|
14
|
+
#
|
15
|
+
# @param [Hash] options configuration options. Supported keys are:
|
16
|
+
# :interpolator - an object that can respond to the 'interpolate' method. Default is the DefaultInterpolator.
|
17
|
+
# :use_interpolator - global flag to specify if the interpolator should be used for this configuration. Default is true.
|
18
|
+
# :tolerate_missing_reference - global flag to specify if missing references should raise an exception.
|
19
|
+
def initialize(options = {})
|
20
|
+
@root = {}
|
21
|
+
@use_interpolator = get_option(options, :use_interpolator, false, true)
|
22
|
+
@interpolator = get_option(options, :interpolator, false, ConfigManager::DefaultInterpolator)
|
23
|
+
@tolerate_missing_references = get_option(options, :tolerate_missing_references, false, false)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Adds a hash of properties to this configuration.
|
27
|
+
#
|
28
|
+
# @param [Hash] values the values to add to this configuration.
|
29
|
+
# @param [String] at the node under which to add these properties. Default is the root node.
|
30
|
+
# @param [Hash] options configuration options. Supported key are
|
31
|
+
# :overwrite - true to overwrite existing properties, false to raise an exception if a property exists. Default is false.
|
32
|
+
#
|
33
|
+
# @return [NilClass]
|
34
|
+
def add_properties(values, at = "", options = {})
|
35
|
+
# Add each item in the hash - Nested hashes call this method recursively.
|
36
|
+
at_array = at.split(".")
|
37
|
+
values.each_pair do |key, value|
|
38
|
+
full_key = (at_array + [key]).join(".")
|
39
|
+
value.kind_of?(Hash) ? add_properties(value, full_key, options) : add_property(full_key, value, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Adds a property to this configuration. The key is a '.' separated string that fully qualifies this property.
|
46
|
+
# So the property a.b identifies the property 'b' inside the group 'a'. Similarly a.b.c identifies the property
|
47
|
+
# 'c' inside the group 'b' which is inside the group 'a'.
|
48
|
+
#
|
49
|
+
# @param [String] key the unique key to identify this property.
|
50
|
+
# @param [Object] value the value of this property.
|
51
|
+
# @param [Hash] options configuration options. Supported keys are:
|
52
|
+
# :overwrite - true to overwrite existing properties, false to raise an exception if a property exists. Default is false.
|
53
|
+
# :at - an optional node's name under which to add this property. Default is the root node.
|
54
|
+
#
|
55
|
+
# @return [NilClass]
|
56
|
+
def add_property(key, value, options = {})
|
57
|
+
# Default options.
|
58
|
+
at = get_option(options, :at, false, "")
|
59
|
+
overwrite = get_option(options, :overwrite, false, false)
|
60
|
+
# Create and add the property.
|
61
|
+
key_array = key.split(".")
|
62
|
+
at_array = at.split(".")
|
63
|
+
leaf = key_array[-1]
|
64
|
+
at_array = at_array + key_array[0..-2]
|
65
|
+
at_node = get_node(at_array, create = true)
|
66
|
+
# Got the node, now add the property, unless it already exists.
|
67
|
+
raise ConfigManager::KeyError.new("Cannot add - '#{at_array.join(".")}.#{leaf}' already exists!") if at_node.has_key?(leaf) and not overwrite
|
68
|
+
at_node[leaf] = value
|
69
|
+
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
# Get the value of the specified property. The key is a '.' separated string that fully qualifies this property.
|
74
|
+
# So the property a.b identifies the property 'b' inside the group 'a'. Similarly a.b.c identifies the property
|
75
|
+
# 'c' inside the group 'b' which is inside the group 'a'.
|
76
|
+
#
|
77
|
+
# If enabled, the property's value is interpolated.
|
78
|
+
# Finally the list of post-processors are invoked and the value is returned.
|
79
|
+
#
|
80
|
+
# @param [String] key the property to get.
|
81
|
+
# @param [Hash] options configuration options. Supported keys are:
|
82
|
+
# :use_interpolator - flag to indicate if the interpolator should be used. Uses the value specified when creating this configuration by default.
|
83
|
+
# :interpolator - the interpolator to use. Uses the value specified when creating this configuration by default.
|
84
|
+
# :post_processors - an array of callable procs. Each one is invoked with the output of the previous one. The first one is invoked with the fully interpolated value.
|
85
|
+
# :replacements - a hash containing replacement values for references. References are looked up in this before being looked up in this configuration.
|
86
|
+
# :tolerate_missing_references: a flag to indicate if missing references should raise an exception.
|
87
|
+
#
|
88
|
+
# Note : Interpolator implementations may support additional options too.
|
89
|
+
#
|
90
|
+
# @return [Object] the property's value.
|
91
|
+
def get_property(key, options = {})
|
92
|
+
use_interpolator = get_option(options, :use_interpolator, false, @use_interpolator)
|
93
|
+
interpolator = get_option(options, :interpolator, false, @interpolator)
|
94
|
+
tolerate_missing_references = set_option(options, :tolerate_missing_references, @tolerate_missing_references, false)
|
95
|
+
post_processors = pop_option(options, :post_processors, false, [])
|
96
|
+
# Get the required property's raw value.
|
97
|
+
key_array = key.split(".")
|
98
|
+
create = false
|
99
|
+
raw_value = get_node(key_array, create)
|
100
|
+
# Interpolate.
|
101
|
+
raw_value = interpolator.interpolate(key, raw_value, self, options) if use_interpolator
|
102
|
+
# Post-process.
|
103
|
+
final_value = raw_value
|
104
|
+
post_processors.each { |processor| final_value = processor.call(final_value) }
|
105
|
+
# All done.
|
106
|
+
final_value
|
107
|
+
end
|
108
|
+
|
109
|
+
# Check to see if the specified property is defined for this configuration. This method will throw an exception if
|
110
|
+
# the key is invalid.
|
111
|
+
#
|
112
|
+
# @param [String] key the property to check.
|
113
|
+
#
|
114
|
+
# @return [TrueClass, FalseClass] true if the property exists, false otherwise.
|
115
|
+
def has_property?(key)
|
116
|
+
key_array = key.split(".")
|
117
|
+
create = false
|
118
|
+
get_node(key_array, create)
|
119
|
+
return true
|
120
|
+
rescue ConfigManager::PropertyNotFoundError
|
121
|
+
return false
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
# Gets the node identified by the specified key. If the 'create' flag is true, missing nodes will be created.
|
127
|
+
#
|
128
|
+
# @param [Array] key_array the array representing the full key.
|
129
|
+
# @param [TrueClass, FalseClass] create true to create missing nodes, false otherwise.
|
130
|
+
#
|
131
|
+
# @return [Hash] the node identified by this key.
|
132
|
+
def get_node(key_array, create = false)
|
133
|
+
return @root if key_array.empty?
|
134
|
+
|
135
|
+
key_str = key_array.join(".")
|
136
|
+
processed_parts = []
|
137
|
+
current_node = @root
|
138
|
+
# Walk the property tree. What's left at the end, is the required node.
|
139
|
+
key_array.each do |part|
|
140
|
+
# If the current node is not a hash, it means the key is invalid.
|
141
|
+
unless current_node.kind_of?(Hash)
|
142
|
+
raise ConfigManager::KeyError.new("Invalid key '#{key_str}' - Reached leaf at '#{processed_parts.join(".")}'!")
|
143
|
+
end
|
144
|
+
|
145
|
+
# If the current node is a hash, then check if the next part of the key is present.
|
146
|
+
# If it present, make that the current node.
|
147
|
+
# If it isn't present and the create flag is true, create an empty node and make it the current node.
|
148
|
+
# If the create flag is false, raise an exception.
|
149
|
+
processed_parts << part
|
150
|
+
if current_node.has_key?(part)
|
151
|
+
current_node = current_node[part]
|
152
|
+
elsif create
|
153
|
+
current_node = current_node[part] = {}
|
154
|
+
else
|
155
|
+
raise ConfigManager::PropertyNotFoundError.new("Key '#{processed_parts.join(".")}' does not exist!")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
# The required node.
|
159
|
+
current_node
|
160
|
+
end
|
161
|
+
|
162
|
+
alias_method :[], :get_property
|
163
|
+
alias_method :[]=, :add_property
|
164
|
+
alias_method :set_property, :add_property
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|