Skip to content

Commit 1f17cd8

Browse files
authored
feat: added extra sources in initializer (#366)
1 parent 97b3e8c commit 1f17cd8

File tree

6 files changed

+73
-3
lines changed

6 files changed

+73
-3
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,22 @@ Example production environment config file:
154154
#{Rails.root}/config/environments/production.yml
155155
```
156156

157+
### Extra sources
158+
159+
You can load extra sources during initialization by setting the `extra_sources` configuration option.
160+
161+
```ruby
162+
Config.setup do |config|
163+
config.extra_sources = [
164+
'path/to/extra_source.yml', # String: loads extra_source.yml
165+
{ api_key: ENV['API_KEY'] }, # Hash: direct hash source
166+
MyCustomSource.new, # Object: custom source object that responds to `load`
167+
]
168+
end
169+
```
170+
171+
This will also overwrite the same config entries from the main file.
172+
157173
### Developer specific config files
158174

159175
If you want to have local settings, specific to your machine or development environment, you can use the following files, which are automatically `.gitignore` :

lib/config.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ module Config
2929
merge_hash_arrays: false,
3030
validation_contract: nil,
3131
evaluate_erb_in_yaml: true,
32-
environment: nil
32+
environment: nil,
33+
extra_sources: []
3334
)
3435

3536
def self.setup
@@ -57,7 +58,10 @@ def self.load_files(*sources)
5758
def self.load_and_set_settings(*sources)
5859
name = Config.const_name
5960
Object.send(:remove_const, name) if Object.const_defined?(name)
60-
Object.const_set(name, Config.load_files(sources))
61+
62+
# Include extra sources in the loading process
63+
all_sources = [sources, Config.extra_sources].flatten.compact
64+
Object.const_set(name, Config.load_files(*all_sources))
6165
end
6266

6367
def self.setting_files(config_root, env)

lib/generators/config/templates/config.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,13 @@
6565
#
6666
# config.file_name = 'settings'
6767
# config.dir_name = 'settings'
68+
69+
# Load extra sources from a path. These can be file paths (strings),
70+
# hashes, or custom source objects that respond to 'load'
71+
#
72+
# config.extra_sources = [
73+
# 'path/to/extra_source.yml', # String: loads extra_source.yml
74+
# { api_key: ENV['API_KEY'] }, # Hash: direct hash source
75+
# MyCustomSource.new, # Custom source object
76+
# ]
6877
end

spec/config_env_spec.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77

88
context 'when overriding settings via ENV variables is enabled' do
99
let(:config) do
10-
Config.load_files "#{fixture_path}/settings.yml", "#{fixture_path}/multilevel.yml"
10+
config_instance = Config.load_files "#{fixture_path}/settings.yml", "#{fixture_path}/multilevel.yml"
11+
# Ensure the Settings constant is set to the same instance for Config.reload! to work
12+
Object.send(:remove_const, 'Settings') if Object.const_defined?('Settings')
13+
Object.const_set('Settings', config_instance)
14+
config_instance
1115
end
1216

1317
after :all do

spec/config_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,30 @@
3838
expect(config.root['google.com']).to eq(3)
3939
end
4040

41+
it "should load extra_sources and support different types" do
42+
test_hash = { 'extra_key' => 'extra_value' }
43+
object_source = double 'source'
44+
45+
allow(object_source).to receive(:load) do
46+
{ 'server' => 'google.com' }
47+
end
48+
49+
Config.setup do |config|
50+
config.extra_sources = [
51+
"#{fixture_path}/settings2.yml",
52+
test_hash,
53+
object_source
54+
]
55+
end
56+
57+
Config.load_and_set_settings("#{fixture_path}/settings.yml")
58+
59+
expect(Settings.size).to eq(1)
60+
expect(Settings.extra_key).to eq('extra_value')
61+
expect(Settings.another).to eq("something")
62+
expect(Settings.server).to eq('google.com')
63+
end
64+
4165
it "should load 2 basic config files" do
4266
config = Config.load_files("#{fixture_path}/settings.yml", "#{fixture_path}/settings2.yml")
4367
expect(config.size).to eq(1)

spec/spec_helper.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ def fixture_path
8484

8585
# Extend Config module with ability to reset configuration to the default values
8686
def self.reset
87+
# Clear any existing Settings constant and its sources to prevent mock leakage
88+
current_const_name = self.const_name
89+
if Object.const_defined?(current_const_name)
90+
settings_instance = Object.const_get(current_const_name)
91+
# Clear the config sources to prevent mock doubles from leaking
92+
if settings_instance.respond_to?(:instance_variable_set)
93+
settings_instance.instance_variable_set(:@config_sources, [])
94+
end
95+
Object.send(:remove_const, current_const_name)
96+
end
97+
98+
# Reset configuration to defaults
8799
self.const_name = 'Settings'
88100
self.use_env = false
89101
self.knockout_prefix = nil
@@ -93,6 +105,7 @@ def self.reset
93105
self.fail_on_missing = false
94106
self.file_name = 'settings'
95107
self.dir_name = 'settings'
108+
self.extra_sources = []
96109
instance_variable_set(:@_ran_once, false)
97110
end
98111
end

0 commit comments

Comments
 (0)