configuration_service 2.0.4 → 2.0.5

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.
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