configuration_service 3.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.rdoc +3 -3
- data/lib/configuration_service/client.rb +28 -9
- data/lib/configuration_service/configuration.rb +1 -1
- data/lib/configuration_service/factory/context.rb +11 -6
- data/lib/configuration_service/factory/environment_context.rb +2 -2
- data/lib/configuration_service/factory/environment_context_backward_compatibility.rb +4 -4
- data/lib/configuration_service/factory.rb +10 -5
- data/lib/configuration_service/provider/broken.rb +1 -1
- data/lib/configuration_service/provider/stub.rb +2 -2
- data/lib/configuration_service/provider.rb +1 -1
- data/lib/configuration_service/test/orchestration_provider.rb +10 -10
- data/lib/configuration_service/test/orchestrator.rb +3 -3
- data/lib/configuration_service/version.rb +1 -1
- data/lib/configuration_service.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9022efdb20bd55a2a9f466600df663186ef5e068
|
4
|
+
data.tar.gz: f4050743be268be3f4c2127da10446209d5bdda2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30da71e127b2c489218cf8b8b9aa0e95f4ad8784870cf1fda4fac1fdd123e2437e2c1604fd069a43ee7877127e02139e1d1494cfb7873fc8e1c1b3dbc3ab8b39
|
7
|
+
data.tar.gz: e56102407e1a649e409dffddc1a19483d48147336454ada41633f27967158fa02e1005c91b693e601cbe1ecaae4b6f67ead1ab81e9ac8e0a5e5ee24d87f2e03a
|
data/README.rdoc
CHANGED
@@ -7,7 +7,7 @@ The configuration service provides
|
|
7
7
|
of identified configuration data with metadata.
|
8
8
|
The service supports {file:features/bootstrapping.feature bootstrapping}.
|
9
9
|
|
10
|
-
A pluggable Ruby API is provided in {ConfigurationService::
|
10
|
+
A pluggable Ruby API is provided in {ConfigurationService::Client}.
|
11
11
|
|
12
12
|
The declarative specification of the service is implemented with cucumber, using a pluggable imperative orchestration providers.
|
13
13
|
This allows for implementations that are not providers to the Ruby API.
|
@@ -87,7 +87,7 @@ In practice, the administrative context would most likely come from the configur
|
|
87
87
|
|
88
88
|
In the following example, the {ConfigurationService::Factory} defaults to using the
|
89
89
|
{ConfigurationService::Factory::EnvironmentContext EnvironmentContext} to acquire application configuration
|
90
|
-
from a non-administrative {ConfigurationService::
|
90
|
+
from a non-administrative {ConfigurationService::Client} client.
|
91
91
|
Part of the application configuration is then used as the context for an administrative {ConfigurationService::AdminClient},
|
92
92
|
which is used as a model in the application.
|
93
93
|
|
@@ -127,7 +127,7 @@ If this configuration data was stored under the configuration identifier "acme",
|
|
127
127
|
|
128
128
|
So this application would use the token "0b2...4af" to access its configuration data
|
129
129
|
under the identifier "acme"
|
130
|
-
with a non-administrative {ConfigurationService::
|
130
|
+
with a non-administrative {ConfigurationService::Client} client.
|
131
131
|
Part of its configuration data, in this case under the key "cs_config",
|
132
132
|
provides {ConfigurationService::Factory::Context} for creating an administrative {ConfigurationService::AdminClient},
|
133
133
|
which it would then use the token "c39...48a" to operate over multiple configuration identifiers on behalf of users.
|
@@ -11,23 +11,30 @@ module ConfigurationService
|
|
11
11
|
# Interpretation of the credentials is provider-dependent; it is opaque to the API and client.
|
12
12
|
# @param [Object] provider
|
13
13
|
# a configured service provider instance, to which requests will be delegated.
|
14
|
-
# @
|
14
|
+
# @param [String] identifier
|
15
|
+
# unique configuration identifier (optional). If omitted, instance methods will require the +identifier+ argument.
|
15
16
|
#
|
16
|
-
def initialize(credentials, provider)
|
17
|
+
def initialize(credentials: nil, provider: nil, identifier: nil)
|
18
|
+
#raise(ArgumentError, "missing argument credentials") unless credentials
|
19
|
+
raise(ArgumentError, "missing argument provider") unless provider
|
17
20
|
@credentials = credentials
|
18
21
|
@provider = provider
|
22
|
+
@identifier = identifier
|
19
23
|
end
|
20
24
|
|
21
25
|
##
|
22
26
|
# Requests the configuration data and metadata
|
23
27
|
# Delegates the request to the configured +provider+.
|
24
28
|
#
|
25
|
-
# @param [String] identifier
|
29
|
+
# @param [String] identifier
|
30
|
+
# unique identifier of configuration. Required if the instance was initialized with a context that provided no +identifier+.
|
26
31
|
# @return [ConfigurationService::Configuration] object containing the configuration data, metadata and identifier
|
27
|
-
# @raise [ConfigurationService::ConfigurationNotFoundError] if no configuration was found for the
|
32
|
+
# @raise [ConfigurationService::ConfigurationNotFoundError] if no configuration was found for the +identifier+
|
33
|
+
# @raise [ConfigurationService::Error] if no +identifier+ is given as an argument or supplied in the initialized context.
|
28
34
|
# @raise [ConfigurationService::Error] if the request failed
|
29
35
|
#
|
30
|
-
def request_configuration(identifier)
|
36
|
+
def request_configuration(identifier: nil)
|
37
|
+
identifier = identifier_argument_or_instance_variable(identifier)
|
31
38
|
@provider.request_configuration(identifier, @credentials) or
|
32
39
|
raise ConfigurationNotFoundError, "configuration not found for identifier: #{identifier}"
|
33
40
|
end
|
@@ -46,15 +53,17 @@ module ConfigurationService
|
|
46
53
|
# and that values be limited to those that can be serialized to JSON.
|
47
54
|
#
|
48
55
|
# @param [String] identifier
|
49
|
-
# unique configuration identifier
|
56
|
+
# unique identifier of configuration. Required if the instance was initialized with a context that provided no +identifier+.
|
50
57
|
# @param [Hash] data
|
51
58
|
# dictionary of probably sensitive configuration data intended for an application, which providers are expected to secure
|
52
59
|
# @param [Hash] metadata
|
53
60
|
# dictionary of data about the configuration data, which providers are not expected to secure
|
54
61
|
# @return [ConfigurationService::Configuration] object containing the configuration data, decorated metadata and identifier
|
62
|
+
# @raise [ConfigurationService::Error] if no +identifier+ is given as an argument or supplied in the initialized context.
|
55
63
|
# @raise [ConfigurationService::Error] if publication failed
|
56
64
|
#
|
57
|
-
def publish_configuration(identifier, data, metadata
|
65
|
+
def publish_configuration(identifier: nil, data: nil, metadata: {})
|
66
|
+
identifier = identifier_argument_or_instance_variable(identifier)
|
58
67
|
Utils.dictionary?(data) or raise ConfigurationService::Error, "data must be a dictionary"
|
59
68
|
Utils.dictionary?(metadata) or raise ConfigurationService::Error, "metadata must be a dictionary"
|
60
69
|
|
@@ -67,16 +76,26 @@ module ConfigurationService
|
|
67
76
|
# Authorize consumption of a configuration ie. get credentials to consume configurations ie. get a token to consume configurations
|
68
77
|
#
|
69
78
|
# @param [String] identifier
|
70
|
-
# unique identifier of configuration
|
79
|
+
# unique identifier of configuration. Required if the instance was initialized with a context that provided no +identifier+.
|
71
80
|
# @return [String] credentials allowing consumption of the provided configuration
|
72
81
|
# @raise [ConfigurationService::ConfigurationNotFoundError] if no configuration was found for the configured +identifier+
|
82
|
+
# @raise [ConfigurationService::Error] if no +identifier+ is given as an argument or supplied in the initialized context.
|
73
83
|
# @raise [ConfigurationService::Error] if the request failed
|
74
84
|
##
|
75
|
-
def authorize_consumption(identifier)
|
85
|
+
def authorize_consumption(identifier: nil)
|
86
|
+
identifier = identifier_argument_or_instance_variable(identifier)
|
76
87
|
@provider.authorize_consumption(identifier, @credentials) or
|
77
88
|
raise ConfigurationNotFoundError, "configuration not found for identifier: #{identifier}"
|
78
89
|
end
|
79
90
|
|
91
|
+
private
|
92
|
+
|
93
|
+
def identifier_argument_or_instance_variable(identifier)
|
94
|
+
identifier ||= @identifier
|
95
|
+
raise(ConfigurationService::Error, "missing argument identifier (required when initialized without identifier)") unless identifier
|
96
|
+
identifier
|
97
|
+
end
|
98
|
+
|
80
99
|
end
|
81
100
|
|
82
101
|
end
|
@@ -10,7 +10,7 @@ module ConfigurationService
|
|
10
10
|
# @attr_reader [Hash] metadata
|
11
11
|
# dictionary of data about the configuration data, which providers are not expected to secure
|
12
12
|
#
|
13
|
-
# @see ConfigurationService::
|
13
|
+
# @see ConfigurationService::Client#publish_configuration
|
14
14
|
#
|
15
15
|
class Configuration
|
16
16
|
|
@@ -7,11 +7,10 @@ module ConfigurationService
|
|
7
7
|
##
|
8
8
|
# A factory context for static factory configuration
|
9
9
|
#
|
10
|
-
# The typical use case for this class is in constructing
|
10
|
+
# The typical use case for this class is in constructing a multi-identifier {ConfigurationService::Client Client}
|
11
11
|
# using a data structure acquired from a secure source that does not need to be scrubbed.
|
12
12
|
#
|
13
13
|
# @see ConfigurationService::Factory.create_client
|
14
|
-
# @see ConfigurationService::Factory.create_admin_client
|
15
14
|
#
|
16
15
|
class Context
|
17
16
|
|
@@ -24,9 +23,9 @@ module ConfigurationService
|
|
24
23
|
# The following keys are used by the {ConfigurationService::Factory}:
|
25
24
|
#
|
26
25
|
# [identifier] the unique identity of the configuration data
|
27
|
-
# (see {ConfigurationService::
|
26
|
+
# (see {ConfigurationService::Client#initialize})
|
28
27
|
# [token] authorization token for the identified configuration data
|
29
|
-
# (see {ConfigurationService::
|
28
|
+
# (see {ConfigurationService::Client#initialize})
|
30
29
|
# [provider_id] the unique identity of the service provider
|
31
30
|
# (see {ConfigurationService::ProviderRegistry})
|
32
31
|
# [provider_config] configuration options for the service provider
|
@@ -39,12 +38,18 @@ module ConfigurationService
|
|
39
38
|
##
|
40
39
|
# The unique identity of the configuration data
|
41
40
|
#
|
42
|
-
# Required for {ConfigurationService::Base}. Not used by {ConfigurationService::AdminClient}.
|
43
|
-
#
|
44
41
|
def identifier
|
45
42
|
@env[:identifier]
|
46
43
|
end
|
47
44
|
|
45
|
+
##
|
46
|
+
#
|
47
|
+
# Whether the context includes an +identifier+
|
48
|
+
#
|
49
|
+
def identifier?
|
50
|
+
@env.include?(:identifier)
|
51
|
+
end
|
52
|
+
|
48
53
|
##
|
49
54
|
# Authorization token for the identified configuration data
|
50
55
|
#
|
@@ -39,9 +39,9 @@ module ConfigurationService
|
|
39
39
|
# The sources are scanned for {#prefix} matches, within which the following variables are used:
|
40
40
|
#
|
41
41
|
# [IDENTIFIER] the unique identity of the configuration data
|
42
|
-
# (see {ConfigurationService::
|
42
|
+
# (see {ConfigurationService::Client#initialize})
|
43
43
|
# [TOKEN] authorization token for the identified configuration data
|
44
|
-
# (see {ConfigurationService::
|
44
|
+
# (see {ConfigurationService::Client#initialize})
|
45
45
|
# [PROVIDER] the unique identity of the service provider
|
46
46
|
# (see {ConfigurationService::ProviderRegistry})
|
47
47
|
# [PROVIDER_*] configuration options for the service provider
|
@@ -19,9 +19,9 @@ module ConfigurationService
|
|
19
19
|
# The environment is scanned for {EnvironmentContext#prefix} matches, within which the following variables are used:
|
20
20
|
#
|
21
21
|
# [IDENTIFIER] the unique identity of the configuration data
|
22
|
-
# (see {ConfigurationService::
|
22
|
+
# (see {ConfigurationService::Client#initialize})
|
23
23
|
# [TOKEN] authorization token for the identified configuration data
|
24
|
-
# (see {ConfigurationService::
|
24
|
+
# (see {ConfigurationService::Client#initialize})
|
25
25
|
# [PROVIDER] the unique identity of the service provider
|
26
26
|
# (see {ConfigurationService::ProviderRegistry})
|
27
27
|
# [PROVIDER_*] configuration options for the service provider
|
@@ -34,13 +34,13 @@ module ConfigurationService
|
|
34
34
|
# A service provider instance is then constructed with a dictionary of the +PROVIDER_*+ variables,
|
35
35
|
# in which the keys are the name of the variable without +PROVIDER_+, downcased and intern'd.
|
36
36
|
#
|
37
|
-
# Then a service {ConfigurationService::
|
37
|
+
# Then a service {ConfigurationService::Client} is constructed with the +IDENTIFIER+, +TOKEN+ and service provider instance.
|
38
38
|
#
|
39
39
|
# And finally, the environment is scrubbed of the variables used, to protect them from accidental exposure
|
40
40
|
# (e.g. in an exception handler that prints the environment). On JRuby, system properties are scrubbed of variables used as well,
|
41
41
|
# regardless of whether they were overridden by environment variables.
|
42
42
|
#
|
43
|
-
# @return [ConfigurationService::
|
43
|
+
# @return [ConfigurationService::Client] the configuration service instance created
|
44
44
|
# @raise [ProviderNotFoundError] if no service provider has been registered with the name given by +PROVIDER+
|
45
45
|
#
|
46
46
|
# @deprecated Use {ConfigurationService::Factory} instead.
|
@@ -33,15 +33,18 @@ module ConfigurationService
|
|
33
33
|
# configuraton = configuration_service.request_configuration
|
34
34
|
# AcmeApplication.new(configuration.data).run
|
35
35
|
#
|
36
|
-
# @example Creating
|
36
|
+
# @example Creating a multi-identifier client with static bootstrap configuration
|
37
37
|
#
|
38
|
-
# admin_client = ConfigurationService::Factory.
|
38
|
+
# admin_client = ConfigurationService::Factory.create_client(
|
39
39
|
# "token" => "c3935418-f621-40de-ada3-cc8169f1348a",
|
40
|
+
# # Note: no identifier provided
|
40
41
|
# "provider_id" => "vault",
|
41
42
|
# "provider_config" => {
|
42
43
|
# "address" => "http://127.0.0.1:8200"
|
43
44
|
# }
|
44
45
|
# )
|
46
|
+
# acme_config = admin_client.request_configuration(identifier: "acme")
|
47
|
+
# wile_config = admin_client.request_configuration(identifier: "wile")
|
45
48
|
#
|
46
49
|
module Factory
|
47
50
|
|
@@ -50,19 +53,21 @@ module ConfigurationService
|
|
50
53
|
#
|
51
54
|
# @param [ConfigurationService::Factory::EnvironmentContext, ConfigurationService::Factory::Context, Hash] context
|
52
55
|
# the factory context
|
53
|
-
# @return [ConfigurationService::
|
56
|
+
# @return [ConfigurationService::Client] the configuration service client created
|
54
57
|
#
|
55
58
|
# When the +context+ is a Hash, it is wrapped in a {ConfigurationService::Factory::Context}, which does not scrub
|
56
59
|
# sources after the configuration service client is created. For this reason, the process +ENV+ should never
|
57
60
|
# be given as the +context+; rather give no +context+, so that the default {ConfigurationService::Factory::EnvironmentContext}
|
58
61
|
# will be used to safely scrub the process +ENV+ and (on JRuby) system properties after the configuration service client is created.
|
59
62
|
#
|
60
|
-
#
|
63
|
+
# If the context does not provide an +identifier+ property, the instance methods on the client object will require
|
64
|
+
# an +identifier+ argument.
|
61
65
|
#
|
62
66
|
def self.create_client(context = EnvironmentContext.new)
|
63
67
|
context = Context.new(context) if context.is_a?(Hash)
|
64
68
|
provider = create_provider(context)
|
65
|
-
|
69
|
+
identifier = context.identifier? ? context.identifier : nil
|
70
|
+
ConfigurationService::Client.new(credentials: context.token, provider: provider, identifier: identifier)
|
66
71
|
ensure
|
67
72
|
context.scrub!
|
68
73
|
end
|
@@ -50,7 +50,7 @@ module ConfigurationService
|
|
50
50
|
# @return [nil] if not found
|
51
51
|
# @raise [ConfigurationService::AuthorizationError] if not authorized for the +:consumer+ role
|
52
52
|
#
|
53
|
-
# @see ConfigurationService::
|
53
|
+
# @see ConfigurationService::Client#request_configuration
|
54
54
|
#
|
55
55
|
def request_configuration(identifier, credentials)
|
56
56
|
authorize_request(:consumer, credentials)
|
@@ -71,7 +71,7 @@ module ConfigurationService
|
|
71
71
|
# @return [ConfigurationService::Configuration] published configuration
|
72
72
|
# @raise [ConfigurationService::Error] on failure.
|
73
73
|
#
|
74
|
-
# @see ConfigurationService::
|
74
|
+
# @see ConfigurationService::Client#publish_configuration
|
75
75
|
#
|
76
76
|
def publish_configuration(configuration, credentials)
|
77
77
|
authorize_request(:publisher, credentials)
|
@@ -2,7 +2,7 @@ module ConfigurationService
|
|
2
2
|
|
3
3
|
##
|
4
4
|
# A configuration service provider is an imperative implementation of the configuration service API,
|
5
|
-
# to be plugged into a {ConfigurationService::
|
5
|
+
# to be plugged into a {ConfigurationService::Client}.
|
6
6
|
#
|
7
7
|
# A {ConfigurationService::Provider::Stub} implementation is provided to validate the test framework architecture.
|
8
8
|
#
|
@@ -11,7 +11,7 @@ module ConfigurationService
|
|
11
11
|
#
|
12
12
|
# Extend this class if you want your test orchestration provider toconstrain your implementation's interface
|
13
13
|
# to work as a configuration service provider.
|
14
|
-
# If you have no intention of plugging your implementation into {ConfigurationService::
|
14
|
+
# If you have no intention of plugging your implementation into {ConfigurationService::Client},
|
15
15
|
# build your own test orchestration provider from scratch, using {ConfigurationService::Test::Orchestrator}
|
16
16
|
# and {ConfigurationService::Test::StubOrchestrationProvider} as a guide.
|
17
17
|
#
|
@@ -63,7 +63,7 @@ module ConfigurationService
|
|
63
63
|
##
|
64
64
|
# The service provider under test
|
65
65
|
#
|
66
|
-
# @return [Object] a provider to be plugged into {ConfigurationService::
|
66
|
+
# @return [Object] a provider to be plugged into {ConfigurationService::Client}
|
67
67
|
#
|
68
68
|
def service_provider
|
69
69
|
raise NotImplementedError, "#{self.class} must implement service_provider"
|
@@ -72,7 +72,7 @@ module ConfigurationService
|
|
72
72
|
##
|
73
73
|
# A broken service provider
|
74
74
|
#
|
75
|
-
# @return [Object] a provider to be plugged into {ConfigurationService::
|
75
|
+
# @return [Object] a provider to be plugged into {ConfigurationService::Client}.
|
76
76
|
# The service provider's +publish_configuration+ and +request_configuration+ methods
|
77
77
|
# must raise an {ConfigurationService::Error} other than {ConfigurationService::AuthorizationError}.
|
78
78
|
#
|
@@ -175,11 +175,11 @@ module ConfigurationService
|
|
175
175
|
#
|
176
176
|
# @return [ConfigurationService::Test::Response]
|
177
177
|
#
|
178
|
-
# @see ConfigurationService::
|
178
|
+
# @see ConfigurationService::Client#request_configuration
|
179
179
|
#
|
180
180
|
def request_configuration
|
181
181
|
wrap_response do
|
182
|
-
@requested_configuration = service.request_configuration(@identifier)
|
182
|
+
@requested_configuration = service.request_configuration(identifier: @identifier)
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
@@ -189,7 +189,7 @@ module ConfigurationService
|
|
189
189
|
# @return [String] credentials allowing consumption of a configuration
|
190
190
|
##
|
191
191
|
def authorize_consumption
|
192
|
-
@credentials = service.authorize_consumption(@identifier)
|
192
|
+
@credentials = service.authorize_consumption(identifier: @identifier)
|
193
193
|
end
|
194
194
|
|
195
195
|
def credentials_allow_consumption?
|
@@ -210,14 +210,14 @@ module ConfigurationService
|
|
210
210
|
#
|
211
211
|
# @return [ConfigurationService::Test::Response]
|
212
212
|
#
|
213
|
-
# @see ConfigurationService::
|
213
|
+
# @see ConfigurationService::Client#publish_configuration
|
214
214
|
#
|
215
215
|
def publish_configuration
|
216
216
|
wrap_response do
|
217
217
|
if @metadata
|
218
|
-
service.publish_configuration(@identifier, configuration, @metadata)
|
218
|
+
service.publish_configuration(identifier: @identifier, data: configuration, metadata: @metadata)
|
219
219
|
else
|
220
|
-
service.publish_configuration(@identifier, configuration)
|
220
|
+
service.publish_configuration(identifier: @identifier, data: configuration)
|
221
221
|
end
|
222
222
|
end
|
223
223
|
end
|
@@ -272,7 +272,7 @@ module ConfigurationService
|
|
272
272
|
provider = broken_service_provider
|
273
273
|
end
|
274
274
|
|
275
|
-
ConfigurationService::Client.new(@credentials, provider)
|
275
|
+
ConfigurationService::Client.new(credentials: @credentials, provider: provider)
|
276
276
|
end
|
277
277
|
|
278
278
|
def authorized_as(role)
|
@@ -14,11 +14,11 @@ module ConfigurationService
|
|
14
14
|
# It keeps no domain state, because that would couple it to the
|
15
15
|
# service implementation. By making no assumptions at all about the API
|
16
16
|
# or data, it allows implementors to produce service implementations
|
17
|
-
# that do not adhere to the anticipated {ConfigurationService::
|
17
|
+
# that do not adhere to the anticipated {ConfigurationService::Client} API,
|
18
18
|
# by writing their own test orchestration provider from scratch
|
19
19
|
# instead of extending {ConfigurationService::Test::OrchestrationProvider}.
|
20
20
|
#
|
21
|
-
# However, implementors who are trying to produce {ConfigurationService::
|
21
|
+
# However, implementors who are trying to produce {ConfigurationService::Client}
|
22
22
|
# providers should extend {ConfigurationService::Test::OrchestrationProvider},
|
23
23
|
# which anticipates a compatible provider API.
|
24
24
|
#
|
@@ -280,7 +280,7 @@ module ConfigurationService
|
|
280
280
|
#
|
281
281
|
def bootstrapped_configuration_service_functional?
|
282
282
|
response = begin
|
283
|
-
ConfigurationService::Test::Response::Success.new(@service.request_configuration('test'))
|
283
|
+
ConfigurationService::Test::Response::Success.new(@service.request_configuration(identifier: 'test'))
|
284
284
|
rescue ConfigurationService::Error => e
|
285
285
|
ConfigurationService::Test::Response::Failure.new(e)
|
286
286
|
end
|
@@ -15,6 +15,7 @@ module ConfigurationService
|
|
15
15
|
# Creates a new {ConfigurationService::Base}
|
16
16
|
#
|
17
17
|
# @see ConfigurationService::Base#initialize
|
18
|
+
# @deprecated use ConfigurationService::Client instead
|
18
19
|
#
|
19
20
|
def self.new(identifier, token, provider)
|
20
21
|
ConfigurationService::Base.new(identifier, token, provider)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: configuration_service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sheldon Hearn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -158,3 +158,4 @@ signing_key:
|
|
158
158
|
specification_version: 4
|
159
159
|
summary: Configuration service
|
160
160
|
test_files: []
|
161
|
+
has_rdoc:
|