configuration_service 2.0.4 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NWUxN2M4Yzc3YjM2MmJmZjE5NGQ4YWIwNmQxYjZiMzI3YTkzZDQ5NQ==
4
+ NjZmYTRlOWVjZTY2N2NlMjhlNjIwMTBmNmY2ZGU5YWVjZGYyMTY5OA==
5
5
  data.tar.gz: !binary |-
6
- NTI2Yjg0YTgzYWEyZjU2OTdiNDIxYTgyY2ZjZWUyYWIwODg2ZWFhZQ==
6
+ YjQ2YzUwMWM1YTFlMWY5ZTM1MzBiOTgyM2I4ZDJlNWI3Y2U5OWVhYg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- Y2M0NDZiYmYxMjQwNWE2NmI0ZmJlZjA0NTY1Yjg3ZDg1ZDhkNTk1OTQ5YjAy
10
- ZWUwNzhkZGIyOWFmNWU0ZTA3Yjc3MGQ1YmE2MWU5NzVlYmMxYzA5Zjg5ODlk
11
- NWMzYmJlZGIxZmFjYTcyNzYwYzU0NWY1NjQ2YmRiOWZmODc2MWE=
9
+ ZmU3YTI3OTcwMTBkMWQyYmMzNDZiNDQzMzU2MWMzODIzMGU3ZWY4ZWM1YWI3
10
+ ZGI2ZDYwOWNjOGUxMmQzOGEwYmQxMDUzZWEwMjkxNTIzNWVhNThmYjRmZWY2
11
+ YTQ3NmZiNmY4MzAzZDI2YTUwYTljY2RhYmU4YjQ1ZTcxMWFiYmU=
12
12
  data.tar.gz: !binary |-
13
- ZGI1MjlkOTI5NzM0OWMzZTAyM2M0NmU0YTkzNzBlY2M0YTkxZmJjNmI4ODQ1
14
- MjJlYjQ4MDliMTc4MWM3MjkyOTgzOGI1NWZjMWQyMjZlY2JkZmQ4NGFiNzBk
15
- YjEyMGU5NWQzOTFhNjZlZTlkZDk1MjIyOWM2NzRkZGIwYmQ4ZTQ=
13
+ MTY0ZjJkZWYzNWI2ZDdlYjMzZDlkZWMzZmQ0MTg5Y2QyZDdjM2NjYWU4YjQ3
14
+ OWNiMzNhNzFkYzQ3OGJkMDc0NjQxNTAwMDExYzAzYjdiZWY0OWYzZDRiNDEx
15
+ OTNjMGZmZmY4YWY5NWQ5MGJjMGE1ZGUyNmVlNzRjYmY2NDk5MTY=
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --no-private
2
+ -
3
+ features/*.feature
data/README.rdoc CHANGED
@@ -1,34 +1,32 @@
1
1
  = Configuration service
2
2
 
3
3
  The configuration service provides
4
- {authorized}[link:features/authorization_feature.html]
5
- {publication}[link:features/publishing_feature.html] and
6
- {consumption}[link:features/consuming_feature.html]
4
+ {file:features/authorization.feature authorized}
5
+ {file:features/publishing.feature publication} and
6
+ {file:features/consuming.feature consumption}
7
7
  of identified configuration data with metadata.
8
+ The service supports {file:features/bootstrapping.feature bootstrapping}.
8
9
 
9
- A pluggable Ruby API is provided in ConfigurationService::Base.
10
+ A pluggable Ruby API is provided in {ConfigurationService::Base}.
10
11
 
11
- The declarative specification of the service is implemented with
12
- cucumber, using a pluggable imperative orchestration providers. This
13
- allows for implementations that are not providers to the Ruby API.
14
- See ConfigurationService::Test.
12
+ The declarative specification of the service is implemented with cucumber, using a pluggable imperative orchestration providers.
13
+ This allows for implementations that are not providers to the Ruby API.
14
+ See {ConfigurationService::Test}.
15
15
 
16
- A stub service provider is provided in
17
- ConfigurationService::Provider::Stub. Other providers are avialable as gems.
16
+ A stub service provider is provided in {ConfigurationService::Provider::Stub}.
17
+ This is used to validate the test framework architecture, and may be used as a stub configuration service in tests.
18
+ {https://rubygems.org/search?query=configuration_service-provider Other providers} are available as gems.
18
19
 
19
- Service providers are registered against the
20
- ConfigurationService::ProviderRegistry.
20
+ Service providers are registered against the {ConfigurationService::ProviderRegistry}.
21
21
 
22
- Factories for creating and configuring service instances are provided in
23
- ConfigurationService::Factory.
22
+ Factories for creating and configuring service instances are provided in {ConfigurationService::Factory}.
24
23
 
25
24
  == Usage
26
25
 
27
- The recommended approach to creating a configuration service client is to use
28
- a Factory.
26
+ The recommended approach to creating a configuration service client is to use a {ConfigurationService::Factory Factory}.
29
27
 
30
- For example, we can use the EnvironmentContext factory to create and configure
31
- a configuration service client backed by the vault provider as follows.
28
+ For example, we can use the {ConfigurationService::Factory::EnvironmentContext EnvironmentContext} factory
29
+ to create and configure a configuration service client backed by the vault provider as follows.
32
30
 
33
31
  Our +main.rb+ (or +config.ru+ or whatever) is simple:
34
32
 
@@ -39,15 +37,15 @@ Our +main.rb+ (or +config.ru+ or whatever) is simple:
39
37
  configuraton = service.request_configuration
40
38
  AcmeApplication.new(configuration.data).run
41
39
 
42
- This relies on a bundler Gemfile to load the gem that contains whatever
43
- service provider we configure in the environment:
40
+ This relies on a {http://bundler.io/ bundler} {http://bundler.io/gemfile.html Gemfile} to load the gem
41
+ that contains whatever service provider we configure in the environment:
44
42
 
45
43
  source 'https://rubygems.org'
46
44
 
47
45
  gem 'configuration_service-provider-vault'
48
46
  gem 'acme_application'
49
47
 
50
- Now we use the process environment to configure the EnvironmentContext factory:
48
+ Now we use the process environment to configure the {ConfigurationService::Factory::EnvironmentContext EnvironmentContext} factory:
51
49
 
52
50
  CFGSRV_IDENTIFIER="acme" \
53
51
  CFGSRV_TOKEN="0b2a80f4-54ce-45f4-8267-f6558fee64af" \
@@ -55,13 +53,14 @@ Now we use the process environment to configure the EnvironmentContext factory:
55
53
  CFGSRV_PROVIDER_ADDRESS="http://127.0.0.1:8200" \
56
54
  bundle exec main.rb
57
55
 
58
- Note that +main.rb+ is completely decoupled from the selection of provider and
59
- provider configuration. We could swap and/or reconfigure the provider by
60
- manipulating only the Gemfile and the environment.
56
+ Note that +main.rb+ is completely decoupled from the selection of provider and provider configuration.
57
+ We could swap and/or reconfigure the provider by manipulating only the +Gemfile+ and the environment.
61
58
 
62
- If you prefer to hard-code everything, or if your strategy for bootstrapping
63
- the configuration service isn't expressed by an existing factory yet, you can
64
- construct the service yourself:
59
+ If you prefer to hard-code everything,
60
+ or if your strategy for bootstrapping the configuration service isn't expressed by an existing factory yet,
61
+ you can construct the service yourself:
62
+
63
+ # Bad example (hardcoding token into source):
65
64
 
66
65
  require 'configuration_service/provider/vault'
67
66
  require 'acme_application'
@@ -3,32 +3,28 @@ module ConfigurationService
3
3
  ##
4
4
  # The configuration service API
5
5
  #
6
- # The service provides
7
- # {authorized}[link:features/authorization_feature.html]
8
- # {publication}[link:features/publishing_feature.html] and
9
- # {consumption}[link:features/consuming_feature.html]
10
- # of identified configuration data with metadata.
6
+ # See {file:README.rdoc} for a summary of the service, including links to user stories.
11
7
  #
12
- # It is recommended that consumers use a Factory to create
13
- # and configure the service.
8
+ # It is recommended that consumers use a {ConfigurationService::Factory} to create and configure the service.
14
9
  #
15
10
  class Base
16
11
 
17
12
  ##
18
- # Creates a new API instance for the service +provider+
13
+ # Creates a new configuration service API instance
19
14
  #
20
- # The +identifier+ is a string that uniquely identifies some configuration data and associated metadata.
21
- # It might be the name of a service or service component. It might include an environment label (e.g.
22
- # production, staging, etc.) For example:
15
+ # @param [String] identifier
16
+ # the unique identity of some configuration data and its associated metadata.
17
+ # It might be the name of a service or service component. It might include an environment label
18
+ # (e.g. production, staging, etc.) For example:
23
19
  #
24
- # * billing.acme.com
25
- # * billing-web1.acme.com
26
- # * billing/production/web1
27
- #
28
- # The +token+ is a string that authorizes the client to access the configuration data and associated metadata.
29
- # Interpretation of the +token+ is provider-dependent; it is opaque to the API and client.
30
- #
31
- # The +provider+ is a configured service provider instance.
20
+ # * billing.acme.com
21
+ # * billing-web1.acme.com
22
+ # * billing/production/web1
23
+ # @param [String] token
24
+ # opaque string representing authority to access the configuration data and associated metadata.
25
+ # Interpretation of the token is provider-dependent; it is opaque to the API and client.
26
+ # @param [Object] provider
27
+ # a configured service provider instance, to which requests will be delegated.
32
28
  #
33
29
  def initialize(identifier, token, provider)
34
30
  @identifier = identifier
@@ -37,13 +33,13 @@ module ConfigurationService
37
33
  end
38
34
 
39
35
  ##
40
- # Requests the configuration data and metadata for the +identifier+
36
+ # Requests the configuration data and metadata
41
37
  #
42
- # Delegates the request to the provider.
38
+ # Delegates the request to the configured +provider+.
43
39
  #
44
- # Returns a Configuration object or raises an Error on failure.
45
- # Raises ConfigurationNotFoundError if no matching configuration
46
- # was found.
40
+ # @return [ConfigurationService::Configuration] object containing the configuration data, metadata and identifier
41
+ # @raise [ConfigurationService::ConfigurationNotFoundError] if no configuration was found for the configured +identifier+
42
+ # @raise [ConfigurationService::Error] if the request failed
47
43
  #
48
44
  def request_configuration
49
45
  @provider.request_configuration(@identifier, @token) or
@@ -51,17 +47,25 @@ module ConfigurationService
51
47
  end
52
48
 
53
49
  ##
54
- # Publishes configuration +data+ and optional +metadata+
50
+ # Publishes configuration data and metadata
55
51
  #
56
- # The +data+ and the +metadata+ (if specified) must be dictionaries (responding to #to_hash or #to_h).
57
- # The provider receives a a Configuration object, whose +metadata+ is decorated with the following keys:
52
+ # The +metadata+ is decorated with the following keys:
58
53
  #
59
54
  # * "timestamp" - the current UTC time in ISO8601 format
60
55
  # * "revision" - a UUID for this publication
61
56
  #
62
- # Returns a Configuration object or raises an Error on failure. When a Configuration object
63
- # is returned, its +metadata+ is the decorated copy, allowing access to additional metadata
64
- # added by the API or the provider.
57
+ # Delegates the request to the configured +provider+. The provider may further decorate the +metadata+.
58
+ #
59
+ # It is recommended that both the +data+ and +metadata+ dictionaries use strings as keys,
60
+ # and that values be limited to those that can be serialized to JSON.
61
+ #
62
+ # @param [Hash] data
63
+ # dictionary of probably sensitive configuration data intended for an application, which providers are expected to secure
64
+ # @param [Hash] metadata
65
+ # dictionary of data about the configuration data, which providers are not expected to secure
66
+ #
67
+ # @return [ConfigurationService::Configuration] object containing the configuration data, decorated metadata and identifier
68
+ # @raise [ConfigurationService::Error] if publication failed
65
69
  #
66
70
  def publish_configuration(data, metadata = {})
67
71
  dictionary?(data) or raise ConfigurationService::Error, "data must be a dictionary"
@@ -1,24 +1,28 @@
1
1
  module ConfigurationService
2
2
 
3
3
  ##
4
- # Encapsulates configuration +data+ and its +metadata+
4
+ # Encapsulates identified configuration data and its metadata
5
5
  #
6
- # * +identifier is the string identifier of the data and metadata.
7
- # * +data+ is a dictionary of (possibly sensitive) configuration data,
8
- # which providers are expected to secure.
9
- # * +metadata+ is a dictionary of data about the configuration data,
10
- # which providers are not expected to secure.
6
+ # @attr_reader [String] identifier
7
+ # the unique identity of some configuration data and its associated metadata
8
+ # @attr_reader [Hash] data
9
+ # dictionary of probably sensitive configuration data intended for an application, which providers are expected to secure
10
+ # @attr_reader [Hash] metadata
11
+ # dictionary of data about the configuration data, which providers are not expected to secure
11
12
  #
12
- # It is recommended that both dictionaries use strings as keys, and that
13
- # values be limited to those that can be serialized to JSON.
13
+ # @see ConfigurationService::Base#publish_configuration
14
14
  #
15
15
  class Configuration
16
16
 
17
- attr_reader :identifier, :data, :metadata # :nodoc:
17
+ attr_reader :identifier, :data, :metadata
18
18
 
19
19
  ##
20
20
  # Returns a new Configuration
21
21
  #
22
+ # @param [String] identifier unique identity
23
+ # @param [Hash] data sensitive configuration data
24
+ # @param [Hash] metadata non-sensitive configuration metadata
25
+ #
22
26
  def initialize(identifier, data, metadata)
23
27
  @identifier = identifier
24
28
  @data = data
@@ -3,14 +3,11 @@ module ConfigurationService
3
3
  ##
4
4
  # The base of the configuration service exception tree
5
5
  #
6
- # * Error
7
- # * AuthorizationError
8
- #
9
6
  class Error < StandardError
10
7
  end
11
8
 
12
9
  ##
13
- # A configuration service authorization Error
10
+ # A configuration service authorization error
14
11
  #
15
12
  class AuthorizationError < Error
16
13
  end
@@ -4,7 +4,7 @@ module ConfigurationService
4
4
 
5
5
  class EnvironmentContext
6
6
 
7
- class EnvDict < Hash # :nodoc:
7
+ class EnvDict < Hash
8
8
 
9
9
  def initialize(env, *path)
10
10
  @env = env
@@ -3,7 +3,9 @@ module ConfigurationService
3
3
  module Factory
4
4
 
5
5
  ##
6
- # Creates a Base bootstrapped with environmental configuration
6
+ # A factory for creating a configuration service bootstrapped from environmental configuration
7
+ #
8
+ # @example Requesting configuration from the {https://github.com/hetznerZA/configuration_service-provider-vault Vault service provider}
7
9
  #
8
10
  # # With the following in the environment:
9
11
  # #
@@ -25,17 +27,15 @@ module ConfigurationService
25
27
  # require 'bundler'
26
28
  # Bundler.require(:default) # Registers the vault provider
27
29
  #
28
- # service = ConfigurationService::Factory::EnvironmentContext.create
29
- # configuraton = service.request_configuration
30
+ # configuration_service = ConfigurationService::Factory::EnvironmentContext.create
31
+ # configuraton = configuration_service.request_configuration
30
32
  # AcmeApplication.new(configuration.data).run
31
33
  #
34
+ # @attr_reader [String] prefix
35
+ # prefix for matching environment variable names. Names match if they begin with the prefix and an underscore.
36
+ #
32
37
  class EnvironmentContext
33
38
 
34
- ##
35
- # The prefix for matching environment variable names
36
- #
37
- # Names match if they begin with the prefix and an underscore.
38
- #
39
39
  attr_reader :prefix
40
40
 
41
41
  ##
@@ -46,11 +46,13 @@ module ConfigurationService
46
46
  ##
47
47
  # Returns a new factory
48
48
  #
49
- # The +env+ defaults to the process ENV and the +prefix+ defaults
50
- # to the DEFAULT_PREFIX.
49
+ # @param [Hash] env
50
+ # the string-keyed environment
51
+ # @param [String] prefix
52
+ # the prefix for matching environment variable names
51
53
  #
52
- # Most consumers will not need to call this method; they can use
53
- # .create which instantiates a factory with default +env+ and +prefix+
54
+ # Most consumers will not need to call this method;
55
+ # they can use {.create} which instantiates a factory with default +env+ and +prefix+
54
56
  # and uses that internally.
55
57
  #
56
58
  def initialize(env = ENV, prefix = DEFAULT_PREFIX)
@@ -58,33 +60,30 @@ module ConfigurationService
58
60
  end
59
61
 
60
62
  ##
61
- # Return a Base bootstrapped with environmental configuration
63
+ # Create a configuration service bootstrapped with environmental configuration
62
64
  #
63
- # The environment is scanned for #prefix matches, within which
64
- # the following variables are used:
65
+ # The environment is scanned for {#prefix} matches, within which the following variables are used:
65
66
  #
66
67
  # [IDENTIFIER] the unique identity of the configuration data
67
- # (see Base#initialize)
68
+ # (see {ConfigurationService::Base#initialize})
68
69
  # [TOKEN] authorization token for the identified configuration data
69
- # (see Base#initialize)
70
+ # (see {ConfigurationService::Base#initialize})
70
71
  # [PROVIDER] the unique identity of the service provider
71
- # (see ProviderRegistry)
72
+ # (see {ConfigurationService::ProviderRegistry})
72
73
  # [PROVIDER_*] configuration options for the service provider
73
- # (see provider documentation)
74
+ # (see service provider documentation)
74
75
  #
75
- # The service provider class is fetched from the ProviderRegistry using
76
- # +PROVIDER+. A service provider instance is then constructed with a
77
- # dictionary of the +PROVIDER_*+ variables, in which the keys are the
78
- # name of the variable without +PROVIDER_+, downcased and intern'd.
76
+ # The service provider class is fetched from the {ConfigurationService::ProviderRegistry} using +PROVIDER+.
77
+ # A service provider instance is then constructed with a dictionary of the +PROVIDER_*+ variables,
78
+ # in which the keys are the name of the variable without +PROVIDER_+, downcased and intern'd.
79
79
  #
80
- # Then a service Base is constructed with the +IDENTIFIER+, +TOKEN+
81
- # and service provider instance.
80
+ # Then a service {ConfigurationService::Base} is constructed with the +IDENTIFIER+, +TOKEN+ and service provider instance.
82
81
  #
83
- # And finally, the environment is scrubbed of the variables used, to
84
- # protect them from accidental exposure (e.g. in an exception handler
85
- # that prints the environment).
82
+ # And finally, the environment is scrubbed of the variables used, to protect them from accidental exposure
83
+ # (e.g. in an exception handler that prints the environment).
86
84
  #
87
- # Returns the constructed service Base.
85
+ # @return [ConfigurationService::Base] the configuration service instance created
86
+ # @raise [ProviderNotFoundError] if no service provider has been registered with the name given by +PROVIDER+
88
87
  #
89
88
  def create
90
89
  ConfigurationService.new(@env[:identifier], @env[:token], provider).tap do
@@ -93,11 +92,11 @@ module ConfigurationService
93
92
  end
94
93
 
95
94
  ##
96
- # Return a Base bootstrapped with environmental configuration
95
+ # Return a configuration service bootstrapped with environmental configuration
97
96
  #
98
- # See #create.
97
+ # Instantiates a new factory with the process +ENV+ and the {DEFAULT_PREFIX} and uses it to create a configuration service.
99
98
  #
100
- # Uses the process ENV and the DEFAULT_PREFIX.
99
+ # @see #create
101
100
  #
102
101
  def self.create
103
102
  new.create
@@ -3,11 +3,7 @@ Dir.glob(File.expand_path("../factory/**/*.rb", __FILE__), &method(:require))
3
3
  module ConfigurationService
4
4
 
5
5
  ##
6
- # Module containing configuration service factory classes
7
- #
8
- # Current implementations provided by this package:
9
- #
10
- # * EnvironmentContext
6
+ # Configuration service factories
11
7
  #
12
8
  module Factory
13
9
 
@@ -3,21 +3,21 @@ module ConfigurationService
3
3
  module Provider
4
4
 
5
5
  ##
6
- # A stub broken ConfigurationService::Base service provider
6
+ # A stub broken {ConfigurationService::Base} service provider
7
7
  #
8
8
  # Used to validate the test framework architecture.
9
9
  #
10
10
  class Broken
11
11
 
12
12
  ##
13
- # Raises Error
13
+ # @raise [ConfigurationService::Error] always
14
14
  #
15
15
  def publish_configuration(configuration, token)
16
16
  raise ConfigurationService::Error, "error requested by test"
17
17
  end
18
18
 
19
19
  ##
20
- # Raises Error
20
+ # @raise [ConfigurationService::Error] always
21
21
  #
22
22
  def request_configuration(identifier, token)
23
23
  raise ConfigurationService::Error, "error requested by test"
@@ -10,17 +10,14 @@ module ConfigurationService
10
10
  module Provider
11
11
 
12
12
  ##
13
- # A stub ConfigurationService::Base service provider
13
+ # A stub configuration service provider
14
14
  #
15
15
  # Used to validate the test framework architecture.
16
16
  #
17
- # Registered into the ProviderRegistry with identifier "stub".
17
+ # It is registered into the {ConfigurationService::ProviderRegistry} with identifier "stub".
18
18
  #
19
19
  class Stub
20
20
 
21
- ##
22
- # Maps roles to authorization tokens
23
- #
24
21
  BUILTIN_TOKENS = {
25
22
  :consumer => '64867ebd-6364-0bd3-3fda-81-requestor',
26
23
  :publisher => 'f53606cb-7f3c-4432-afe8-44-publisher',
@@ -28,10 +25,10 @@ module ConfigurationService
28
25
  } unless defined?(BUILTIN_TOKENS)
29
26
 
30
27
  ##
31
- # Returns a new Stub
32
28
  #
33
- # It requires an arbitrary +name+, used solely for testing factory
34
- # methods.
29
+ # @param [Hash] options
30
+ # @option options [String]
31
+ # :name arbitrary name, used solely for testing factory methods
35
32
  #
36
33
  def initialize(options = {})
37
34
  @name = options[:name] or raise ArgumentError, "missing required argument: name"
@@ -39,16 +36,15 @@ module ConfigurationService
39
36
  end
40
37
 
41
38
  ##
42
- # Requests configuration data and metadata
43
- #
44
- # See Base#request_configuration.
39
+ # Request configuration
45
40
  #
46
- # Fetches configuration from the singleton StubStore.
41
+ # Fetches configuration from the singleton {ConfigurationService::StubStore}.
47
42
  #
48
- # Returns a Configuration object or raises AuthorizationError if the
49
- # +token+ is not for the +:consumer+ role.
43
+ # @return [ConfigurationService::Configuration] if authorized and found
44
+ # @return [nil] if not found
45
+ # @raise [ConfigurationService::AuthorizationError] if not authorized for the +:consumer+ role
50
46
  #
51
- # Returns +nil+ if no configuration was found for the +identifier+.
47
+ # @see ConfigurationService::Base#request_configuration
52
48
  #
53
49
  def request_configuration(identifier, token)
54
50
  authorize_request(:consumer, token)
@@ -59,13 +55,14 @@ module ConfigurationService
59
55
  end
60
56
 
61
57
  ##
62
- # Publishes configuration
58
+ # Publish configuration
63
59
  #
64
- # See Base#publish_configuration.
60
+ # @param [ConfigurationService::Configuration] configuration configuration to publish
65
61
  #
66
- # +configuration+ should be a Configuration object or similar.
62
+ # @return [ConfigurationService::Configuration] published configuration
63
+ # @raise [ConfigurationService::Error] on failure.
67
64
  #
68
- # Returns a Configuration object or raises an Error on failure.
65
+ # @see ConfigurationService::Base#publish_configuration
69
66
  #
70
67
  def publish_configuration(configuration, token)
71
68
  authorize_request(:publisher, token)
@@ -9,45 +9,65 @@ unless defined?(ConfigurationService::Provider::StubStore)
9
9
  ##
10
10
  # A singleton store for the Stub service provider
11
11
  #
12
+ # @example Storing data and metadata
13
+ #
14
+ # data = {"username" => "sheldonh", "password" => "secret123"}
15
+ # metadata = {"version" => "1.0.0"}
16
+ # StubStore.instance.store("acme", data, metadata)
17
+ #
18
+ # @example Fetching data and metadata
19
+ #
20
+ # data, metadata = StubStore.instance.fetch("acme")
21
+ # # data -> {"username" => "sheldonh", "password" => "secret123"}
22
+ # # metadata -> {"version" => "1.0.0"}
23
+ #
24
+ # @!method self.instance
25
+ # The singleton registry instance
26
+ #
27
+ # @return [ConfigurationService::ProviderRegistry] singleton instance
28
+ #
12
29
  class StubStore
13
30
 
14
31
  include Singleton
15
32
 
16
- def initialize # :nodoc:
17
- @configurations = {}
18
- end
19
-
20
33
  ##
21
- # Returns the configuration data and metadata for +identifier+
34
+ # Fetch configuration data and metadata
22
35
  #
23
- # The dictionaries are returned as an array, to be used as follows:
36
+ # @param [String] identifier the configuration identifier
24
37
  #
25
- # data, metadata = StubStore.instance.fetch("acme")
38
+ # @return [Array<Hash>] data and metadata as a tuple
26
39
  #
27
40
  def fetch(identifier)
28
41
  @configurations.fetch(identifier)
29
42
  end
30
43
 
31
44
  ##
32
- # Stores the +data+ and +metadata associated with the +identifier+
45
+ # Store configuration data and metadata
46
+ #
47
+ # @param [String] identifier the configuration identifier
48
+ # @param [Hash] data the configuration data
49
+ # @param [Hash] metadata the configuration metadata
33
50
  #
34
51
  def store(identifier, data, metadata)
35
52
  @configurations.store(identifier, [data, metadata])
36
53
  end
37
54
 
38
55
  ##
39
- # Deletes the data and metadata associated with the +identifier+
56
+ # Delete configuration data and metadata
57
+ #
58
+ # It is not an error to delete non-existent configuration
40
59
  #
41
- # It is not an error to delete a non-existent +identifier+
60
+ # @param [String] identifier the configuration identifier
42
61
  #
43
62
  def delete(identifier)
44
63
  @configurations.delete(identifier)
45
64
  nil
46
65
  end
47
66
 
48
- ##
49
- # Return the singleton store instance
50
- # :singleton-method: instance
67
+ # @private
68
+ def initialize
69
+ @configurations = {}
70
+ end
51
71
 
52
72
  end
53
73
 
@@ -1,11 +1,10 @@
1
1
  module ConfigurationService
2
2
 
3
3
  ##
4
- # A configuration service provider is an imperative implementation
5
- # of the ConfigurationService API, to be plugged into a
6
- # ConfigurationService::Base.
4
+ # A configuration service provider is an imperative implementation of the configuration service API,
5
+ # to be plugged into a {ConfigurationService::Base}.
7
6
  #
8
- # A Stub implementation is provided to validate the test framework architecture.
7
+ # A {ConfigurationService::Provider::Stub} implementation is provided to validate the test framework architecture.
9
8
  #
10
9
  module Provider
11
10
  end