configmanager 0.0.2 → 0.0.3
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/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
|