diff --git a/docsite/source/settings.html.md b/docsite/source/settings.html.md
index e5c69324..b42425d2 100644
--- a/docsite/source/settings.html.md
+++ b/docsite/source/settings.html.md
@@ -19,6 +19,10 @@ Application.register_provider(:settings, from: :dry_system) do
require "your/types/module"
end
+ configure do |config|
+ config.prefix = 'SOME_PREFIX_'
+ end
+
settings do
setting :database_url, constructor: Types::String.constrained(filled: true)
@@ -29,7 +33,7 @@ Application.register_provider(:settings, from: :dry_system) do
end
```
-Your provider will then map `ENV` variables to a struct object giving access to your settings as their own methods, which you can use throughout your application:
+An optional prefix can be specified with the `config.prefix` setting inside a `configure` block. Your provider will then map `ENV` variables with the given prefix to a struct object giving access to your settings as their own methods, which you can use throughout your application:
```ruby
Application[:settings].database_url # => "postgres://..."
@@ -65,3 +69,56 @@ Or as an injected dependency in your classes:
end
end
```
+
+## Multiple Settings Providers
+
+In some situations you may wish to have multiple settings providers registered to different namespaces, e.g `config.database` and `config.api`. This can be achieved using the `register_as` configuration option:
+
+```ruby
+# system/providers/database_settings.rb:
+
+require "dry/system/provider_sources"
+
+Application.register_provider(:database_settings, from: :dry_system, source: :settings) do
+ before :prepare do
+ require "your/types/module"
+ end
+
+ configure do |config|
+ config.register_as = 'config.database'
+ end
+
+ settings do
+ setting :url, constructor: Types::String.constrained(filled: true)
+ end
+end
+```
+
+```ruby
+# system/providers/api_settings.rb:
+
+require "dry/system/provider_sources"
+
+Application.register_provider(:api_settings, from: :dry_system, source: :settings) do
+ before :prepare do
+ require "your/types/module"
+ end
+
+ configure do |config|
+ config.register_as = 'config.api'
+ end
+
+ settings do
+ setting :base_url, constructor: Types::String.constrained(filled: true)
+ end
+end
+```
+
+The individual settings namespaces can then be accessed from the container seperately:
+
+```ruby
+Application.start(:database_settings)
+Application.start(:api_settings)
+Application['config.database'].url # => "postgres://..."
+Application['config.api'].base_url # => "https://..."
+```
diff --git a/lib/dry/system/provider_sources/settings.rb b/lib/dry/system/provider_sources/settings.rb
index 21d6a886..809c8b5c 100644
--- a/lib/dry/system/provider_sources/settings.rb
+++ b/lib/dry/system/provider_sources/settings.rb
@@ -6,13 +6,17 @@ module ProviderSources
module Settings
class Source < Dry::System::Provider::Source
setting :store
+ setting :register_as, default: :settings
+ setting :prefix, default: ""
def prepare
require "dry/system/provider_sources/settings/config"
end
def start
- register(:settings, settings.load(root: target.root, env: target.config.env))
+ register(config.register_as,
+ settings.load(root: target.root, env: target.config.env,
+ prefix: config.prefix))
end
def settings(&block)
diff --git a/lib/dry/system/provider_sources/settings/config.rb b/lib/dry/system/provider_sources/settings/config.rb
index 2af16e37..de4c9efe 100644
--- a/lib/dry/system/provider_sources/settings/config.rb
+++ b/lib/dry/system/provider_sources/settings/config.rb
@@ -27,14 +27,14 @@ def setting_errors(errors)
# @api private
class Config
# @api private
- def self.load(root:, env:, loader: Loader)
+ def self.load(root:, env:, prefix: "", loader: Loader)
loader = loader.new(root: root, env: env)
new.tap do |settings_obj|
errors = {}
settings.to_a.each do |setting|
- value = loader[setting.name.to_s.upcase]
+ value = loader[prefix + setting.name.to_s.upcase]
begin
if value
diff --git a/spec/integration/settings_component_spec.rb b/spec/integration/settings_component_spec.rb
index 12c2592c..2ffce20f 100644
--- a/spec/integration/settings_component_spec.rb
+++ b/spec/integration/settings_component_spec.rb
@@ -168,4 +168,101 @@
end
end
end
+
+ context "With a custom prefix" do
+ subject(:system) do
+ Class.new(Dry::System::Container) do
+ setting :env
+
+ configure do |config|
+ config.root = SPEC_ROOT.join("fixtures").join("settings_test")
+ config.env = :test
+ end
+
+ register_provider(:settings, from: :dry_system) do
+ configure do |config|
+ config.prefix = "CUSTOM_PREFIX_"
+ end
+
+ before(:prepare) do
+ target_container.require_from_root "types"
+ end
+
+ settings do
+ setting :string_value, constructor: SettingsTest::Types::String
+ end
+ end
+ end
+ end
+
+ before do
+ ENV["CUSTOM_PREFIX_STRING_VALUE"] = "foo"
+ end
+
+ after do
+ ENV.delete("CUSTOM_PREFIX_STRING_VALUE")
+ end
+
+ it "sets up system settings component via ENV and .env" do
+ expect(settings.string_value).to eql("foo")
+ end
+ end
+
+ context "With multiple settings providers" do
+ subject(:system) do
+ Class.new(Dry::System::Container) do
+ setting :env
+
+ configure do |config|
+ config.root = SPEC_ROOT.join("fixtures").join("settings_test")
+ config.env = :test
+ end
+
+ register_provider(:settings_provider1, from: :dry_system, source: :settings) do
+ configure do |config|
+ config.register_as = "database_settings"
+ end
+
+ before(:prepare) do
+ target_container.require_from_root "types"
+ end
+
+ settings do
+ setting :example_port, constructor: SettingsTest::Types::Coercible::Integer
+ end
+ end
+
+ register_provider(:settings_provider2, from: :dry_system, source: :settings) do
+ configure do |config|
+ config.register_as = "api_settings"
+ end
+
+ before(:prepare) do
+ target_container.require_from_root "types"
+ end
+
+ settings do
+ setting :example_token, constructor: SettingsTest::Types::String
+ end
+ end
+ end
+ end
+
+ before do
+ ENV["EXAMPLE_PORT"] = "19"
+ ENV["EXAMPLE_TOKEN"] = "abc123"
+ system.start(:settings_provider1)
+ system.start(:settings_provider2)
+ end
+
+ after do
+ ENV.delete("EXAMPLE_PORT")
+ ENV.delete("EXAMPLE_TOKENT")
+ end
+
+ it "sets up system settings component via ENV and .env" do
+ expect(system["database_settings"].example_port).to eql(19)
+ expect(system["api_settings"].example_token).to eql("abc123")
+ end
+ end
end