config_files 0.1.7 → 0.2.1
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 +4 -4
- data/.github/workflows/ci.yml +94 -0
- data/.gitignore +2 -5
- data/.rubocop.yml +81 -0
- data/CHANGELOG.md +154 -0
- data/Gemfile +12 -1
- data/MULTI_RUBY_SETUP.md +158 -0
- data/README.md +246 -23
- data/Rakefile +26 -3
- data/TESTING.md +226 -0
- data/config_files.gemspec +12 -9
- data/docker/Dockerfile.test +32 -0
- data/lib/config_files/file_factory.rb +7 -3
- data/lib/config_files/loader_factory.rb +20 -11
- data/lib/config_files/loaders/base_parser.rb +133 -0
- data/lib/config_files/loaders/conf.rb +61 -0
- data/lib/config_files/loaders/default.rb +3 -1
- data/lib/config_files/loaders/ini.rb +48 -0
- data/lib/config_files/loaders/json.rb +3 -1
- data/lib/config_files/loaders/xml.rb +67 -0
- data/lib/config_files/loaders/yaml.rb +2 -0
- data/lib/config_files/loaders.rb +6 -1
- data/lib/config_files/version.rb +3 -1
- data/lib/config_files.rb +33 -18
- data/lib/meta.rb +3 -1
- data/scripts/install_rubies_asdf.sh +187 -0
- data/scripts/test_docker.sh +91 -0
- data/scripts/test_multiple_rubies.sh +290 -0
- data/test/comprehensive_multi_directory_test.rb +168 -0
- data/test/config/dummy.json +10 -0
- data/test/config/dummy.yml +6 -0
- data/test/config_files_test.rb +8 -6
- data/test/etc/dummy.conf +14 -2
- data/test/etc/dummy.ini +12 -0
- data/test/etc/dummy.xml +13 -0
- data/test/loader_factory_test.rb +10 -10
- data/test/loaders_test.rb +362 -0
- data/test/local/dummy.json +10 -0
- data/test/local/dummy.yml +6 -0
- data/test/mixed_format_test.rb +152 -0
- data/test/multi_directory_test.rb +126 -0
- data/test/test_helper.rb +3 -0
- metadata +49 -25
data/README.md
CHANGED
@@ -1,38 +1,261 @@
|
|
1
|
-
|
1
|
+
# ConfigFiles
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
[](https://github.com/blackrat/config_files/actions)
|
4
|
+
[](https://www.ruby-lang.org/en/downloads/)
|
5
|
+
[](https://badge.fury.io/rb/config_files)
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
5
7
|
|
6
|
-
|
8
|
+
Load configuration files from multiple directories and merge them together. Supports YAML, JSON, and other formats.
|
7
9
|
|
8
|
-
|
9
|
-
Allows for dynamically updated or static config files
|
10
|
+
## Features
|
10
11
|
|
11
|
-
|
12
|
+
- Load configs from multiple directories
|
13
|
+
- Merge YAML, JSON, and other file formats
|
14
|
+
- Directory precedence (first directory wins)
|
15
|
+
- Static (cached) or dynamic (reloaded) config files
|
16
|
+
- Returns `HashWithIndifferentAccess` for easy key access
|
12
17
|
|
13
|
-
|
18
|
+
## Installation
|
14
19
|
|
15
|
-
|
16
|
-
include ConfigFiles #mixin the config_directories and config_files generators
|
20
|
+
Add to your Gemfile:
|
17
21
|
|
18
|
-
|
19
|
-
|
22
|
+
```ruby
|
23
|
+
gem 'config_files'
|
24
|
+
```
|
20
25
|
|
21
|
-
|
22
|
-
static_config_files :dummy, :another_yaml_file
|
26
|
+
Or install it:
|
23
27
|
|
24
|
-
|
25
|
-
|
28
|
+
```bash
|
29
|
+
gem install config_files
|
30
|
+
```
|
26
31
|
|
27
|
-
|
28
|
-
some_method(Dummy.dummy[:key]) #extract the constant values from the :key in dummy.yml
|
29
|
-
another_method(Dummy.yet_another_yaml_file[:another_key]) #extract the constant value from the :another_key in yet_another_yaml_file.yml
|
30
|
-
end
|
32
|
+
## Usage
|
31
33
|
|
32
|
-
|
34
|
+
```ruby
|
35
|
+
require 'config_files'
|
33
36
|
|
37
|
+
class MyApp
|
38
|
+
include ConfigFiles
|
39
|
+
|
40
|
+
# Search these directories in order (first wins)
|
41
|
+
config_directories etc: [
|
42
|
+
'config/production',
|
43
|
+
'config/staging',
|
44
|
+
'config/defaults'
|
45
|
+
]
|
46
|
+
|
47
|
+
# Load these config files
|
48
|
+
static_config_files :database, :app_settings
|
49
|
+
dynamic_config_files :feature_flags
|
50
|
+
end
|
34
51
|
|
52
|
+
# Use the configs
|
53
|
+
MyApp.database[:host] # => "prod-db.example.com"
|
54
|
+
MyApp.app_settings[:debug] # => false
|
55
|
+
MyApp.feature_flags[:new_ui] # => true (reloaded each time)
|
56
|
+
```
|
35
57
|
|
36
|
-
|
58
|
+
## How it works
|
37
59
|
|
38
|
-
|
60
|
+
The gem searches for config files in each directory you specify. If you have:
|
61
|
+
|
62
|
+
```
|
63
|
+
config/production/database.yml
|
64
|
+
config/staging/database.yml
|
65
|
+
config/defaults/database.yml
|
66
|
+
```
|
67
|
+
|
68
|
+
And you configure directories as `['config/production', 'config/staging', 'config/defaults']`, then:
|
69
|
+
|
70
|
+
1. It loads all three files
|
71
|
+
2. Merges them together
|
72
|
+
3. Values from `production` override `staging` and `defaults`
|
73
|
+
4. Values from `staging` override `defaults`
|
74
|
+
5. Returns the merged result
|
75
|
+
|
76
|
+
## Multiple file formats
|
77
|
+
|
78
|
+
You can mix YAML and JSON files:
|
79
|
+
|
80
|
+
```
|
81
|
+
config/
|
82
|
+
├── app.yml # YAML format
|
83
|
+
├── app.json # JSON format
|
84
|
+
└── app.conf # Other formats
|
85
|
+
```
|
86
|
+
|
87
|
+
All files with the same base name get merged together. Files are processed alphabetically, so `app.json` loads before `app.yml`.
|
88
|
+
|
89
|
+
## Static vs Dynamic
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
class AppConfig
|
93
|
+
include ConfigFiles
|
94
|
+
config_directories etc: ['config']
|
95
|
+
|
96
|
+
# Static: loaded once and cached
|
97
|
+
static_config_files :database
|
98
|
+
|
99
|
+
# Dynamic: reloaded from disk each time
|
100
|
+
dynamic_config_files :feature_flags
|
101
|
+
end
|
102
|
+
|
103
|
+
AppConfig.database # Fast (cached)
|
104
|
+
AppConfig.feature_flags # Slower (reads from disk)
|
105
|
+
```
|
106
|
+
|
107
|
+
Use static for configs that don't change. Use dynamic for configs that might change while your app is running.
|
108
|
+
|
109
|
+
## Directory precedence
|
110
|
+
|
111
|
+
Earlier directories in the list win:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
config_directories etc: [
|
115
|
+
'config/production', # Highest priority
|
116
|
+
'config/staging', # Medium priority
|
117
|
+
'config/defaults' # Lowest priority
|
118
|
+
]
|
119
|
+
```
|
120
|
+
|
121
|
+
So if `production/app.yml` has `debug: false` and `defaults/app.yml` has `debug: true`, the result will have `debug: false`.
|
122
|
+
|
123
|
+
## Configuration merging
|
124
|
+
|
125
|
+
Configs are deep-merged. Given these files:
|
126
|
+
|
127
|
+
```yaml
|
128
|
+
# config/defaults/app.yml
|
129
|
+
database:
|
130
|
+
host: localhost
|
131
|
+
port: 5432
|
132
|
+
pool_size: 5
|
133
|
+
app:
|
134
|
+
debug: true
|
135
|
+
name: MyApp
|
136
|
+
```
|
137
|
+
|
138
|
+
```yaml
|
139
|
+
# config/production/app.yml
|
140
|
+
database:
|
141
|
+
host: prod-db.example.com
|
142
|
+
pool_size: 20
|
143
|
+
app:
|
144
|
+
debug: false
|
145
|
+
```
|
146
|
+
|
147
|
+
The result is:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
{
|
151
|
+
database: {
|
152
|
+
host: "prod-db.example.com", # from production
|
153
|
+
port: 5432, # from defaults
|
154
|
+
pool_size: 20 # from production
|
155
|
+
},
|
156
|
+
app: {
|
157
|
+
debug: false, # from production
|
158
|
+
name: "MyApp" # from defaults
|
159
|
+
}
|
160
|
+
}
|
161
|
+
```
|
162
|
+
|
163
|
+
## Custom directory keys
|
164
|
+
|
165
|
+
You can use different directory sets:
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
class AppConfig
|
169
|
+
include ConfigFiles
|
170
|
+
|
171
|
+
config_directories(
|
172
|
+
etc: ['config/app', '/etc/myapp'],
|
173
|
+
secrets: ['secrets/production', 'secrets/shared']
|
174
|
+
)
|
175
|
+
|
176
|
+
static_config_files :database # searches in 'etc' directories
|
177
|
+
end
|
178
|
+
|
179
|
+
# Access the directory paths
|
180
|
+
AppConfig.etc_dir # => ["/full/path/to/config/app", "/etc/myapp"]
|
181
|
+
AppConfig.secrets_dir # => ["/full/path/to/secrets/production", ...]
|
182
|
+
```
|
183
|
+
|
184
|
+
## Error handling
|
185
|
+
|
186
|
+
Missing files and directories are ignored:
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
class AppConfig
|
190
|
+
include ConfigFiles
|
191
|
+
|
192
|
+
config_directories etc: [
|
193
|
+
'config/nonexistent', # ignored
|
194
|
+
'config/existing' # used
|
195
|
+
]
|
196
|
+
|
197
|
+
static_config_files :missing_file
|
198
|
+
end
|
199
|
+
|
200
|
+
AppConfig.missing_file # => {} (empty hash)
|
201
|
+
```
|
202
|
+
|
203
|
+
## Testing
|
204
|
+
|
205
|
+
Run the tests:
|
206
|
+
|
207
|
+
```bash
|
208
|
+
bundle exec rake test
|
209
|
+
```
|
210
|
+
|
211
|
+
Test with multiple Ruby versions:
|
212
|
+
|
213
|
+
```bash
|
214
|
+
./scripts/test_multiple_rubies.sh
|
215
|
+
```
|
216
|
+
|
217
|
+
The gem is tested on Ruby 2.7+ with ActiveSupport 6.1+. See [TESTING.md](TESTING.md) for details.
|
218
|
+
|
219
|
+
## API
|
220
|
+
|
221
|
+
### config_directories(hash)
|
222
|
+
|
223
|
+
Define search directories:
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
config_directories etc: ['dir1', 'dir2']
|
227
|
+
```
|
228
|
+
|
229
|
+
### static_config_files(*files)
|
230
|
+
|
231
|
+
Load files once and cache them:
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
static_config_files :database, :app_settings
|
235
|
+
```
|
236
|
+
|
237
|
+
### dynamic_config_files(*files)
|
238
|
+
|
239
|
+
Reload files on each access:
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
dynamic_config_files :feature_flags
|
243
|
+
```
|
244
|
+
|
245
|
+
## Contributing
|
246
|
+
|
247
|
+
1. Fork it
|
248
|
+
2. Create your feature branch (`git checkout -b my-feature`)
|
249
|
+
3. Make your changes
|
250
|
+
4. Run the tests (`bundle exec rake test`)
|
251
|
+
5. Commit your changes (`git commit -am 'Add feature'`)
|
252
|
+
6. Push to the branch (`git push origin my-feature`)
|
253
|
+
7. Create a Pull Request
|
254
|
+
|
255
|
+
## License
|
256
|
+
|
257
|
+
MIT License. See [LICENCE.txt](LICENCE.txt) for details.
|
258
|
+
|
259
|
+
## Changelog
|
260
|
+
|
261
|
+
See [CHANGELOG.md](CHANGELOG.md) for version history and changes.
|
data/Rakefile
CHANGED
@@ -1,8 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rake/testtask'
|
2
4
|
|
3
|
-
Rake::TestTask.new do |t|
|
5
|
+
Rake::TestTask.new(:test) do |t|
|
4
6
|
t.libs << 'test'
|
7
|
+
t.libs << 'lib'
|
8
|
+
t.test_files = FileList['test/*_test.rb']
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task default: :test
|
13
|
+
|
14
|
+
desc "Run tests with verbose output"
|
15
|
+
task :test_verbose do
|
16
|
+
sh "find test -name '*_test.rb' -exec bundle exec ruby {} \\;"
|
5
17
|
end
|
6
18
|
|
7
|
-
desc "Run tests"
|
8
|
-
task :
|
19
|
+
desc "Run tests for a specific Ruby version (for local testing)"
|
20
|
+
task :test_ruby_version do
|
21
|
+
ruby_version = ENV['RUBY_VERSION'] || RUBY_VERSION
|
22
|
+
puts "Running tests with Ruby #{ruby_version}"
|
23
|
+
Rake::Task[:test].invoke
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Clean up test artifacts"
|
27
|
+
task :clean do
|
28
|
+
FileUtils.rm_rf('test/format_test')
|
29
|
+
FileUtils.rm_rf('test/comprehensive')
|
30
|
+
FileUtils.rm_rf('test/order_test')
|
31
|
+
end
|
data/TESTING.md
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
# Testing ConfigFiles
|
2
|
+
|
3
|
+
This document describes how to test the ConfigFiles gem across multiple Ruby versions and ActiveSupport versions.
|
4
|
+
|
5
|
+
## Supported Versions
|
6
|
+
|
7
|
+
### Ruby Versions
|
8
|
+
- **Ruby 2.7+**: Full support with ActiveSupport 6.1+ and 7.0+
|
9
|
+
- **Ruby 3.0+**: Full support with all ActiveSupport versions
|
10
|
+
- **Ruby 3.1+**: Full support with all ActiveSupport versions including 7.1+ and 7.2+
|
11
|
+
|
12
|
+
### ActiveSupport Versions
|
13
|
+
- **ActiveSupport 6.1**: Compatible with Ruby 2.7+
|
14
|
+
- **ActiveSupport 7.0**: Compatible with Ruby 2.7+
|
15
|
+
- **ActiveSupport 7.1**: Compatible with Ruby 3.1+
|
16
|
+
- **ActiveSupport 7.2**: Compatible with Ruby 3.1+
|
17
|
+
|
18
|
+
## Testing Methods
|
19
|
+
|
20
|
+
### 1. GitHub Actions (Recommended for CI/CD)
|
21
|
+
|
22
|
+
The project uses GitHub Actions for automated testing across multiple Ruby and ActiveSupport versions.
|
23
|
+
|
24
|
+
**Configuration**: `.github/workflows/ci.yml`
|
25
|
+
|
26
|
+
**Features**:
|
27
|
+
- Tests Ruby 2.7, 3.0, 3.1, 3.2, 3.3, and 3.4
|
28
|
+
- Tests ActiveSupport 6.1, 7.0, 7.1, and 7.2
|
29
|
+
- Automatically excludes incompatible combinations
|
30
|
+
- Includes linting with RuboCop
|
31
|
+
- Runs on every push and pull request
|
32
|
+
|
33
|
+
### 2. Local Testing with Multiple Ruby Versions
|
34
|
+
|
35
|
+
#### Using Multi-Manager Script (asdf/rbenv/rvm)
|
36
|
+
|
37
|
+
```bash
|
38
|
+
# The script automatically detects which Ruby version manager you have installed:
|
39
|
+
# - asdf (recommended)
|
40
|
+
# - rbenv
|
41
|
+
# - rvm
|
42
|
+
|
43
|
+
# Install Ruby versions (choose your manager):
|
44
|
+
# asdf: ./scripts/install_rubies_asdf.sh
|
45
|
+
# rbenv: rbenv install 2.7.8 3.0.6 3.1.4 3.2.2 3.3.0 3.4.1
|
46
|
+
# rvm: rvm install 2.7.8 3.0.6 3.1.4 3.2.2 3.3.0 3.4.1
|
47
|
+
|
48
|
+
# Run the multi-Ruby test script
|
49
|
+
./scripts/test_multiple_rubies.sh
|
50
|
+
```
|
51
|
+
|
52
|
+
This script will:
|
53
|
+
- Auto-detect your Ruby version manager (asdf, rbenv, or rvm)
|
54
|
+
- Check which Ruby versions are installed
|
55
|
+
- Offer to install missing Ruby versions
|
56
|
+
- Test each Ruby version with multiple ActiveSupport versions
|
57
|
+
- Skip incompatible combinations
|
58
|
+
- Provide a summary of results
|
59
|
+
|
60
|
+
#### asdf-Specific Installation
|
61
|
+
|
62
|
+
```bash
|
63
|
+
# Install all Ruby versions at once with asdf
|
64
|
+
./scripts/install_rubies_asdf.sh
|
65
|
+
|
66
|
+
# Then run tests
|
67
|
+
./scripts/test_multiple_rubies.sh
|
68
|
+
```
|
69
|
+
|
70
|
+
#### Using Docker
|
71
|
+
|
72
|
+
```bash
|
73
|
+
# Test all combinations using Docker
|
74
|
+
./scripts/test_docker.sh
|
75
|
+
|
76
|
+
# Test a specific Ruby version
|
77
|
+
docker build --build-arg RUBY_VERSION=3.3 --build-arg ACTIVESUPPORT_VERSION="~> 7.0" -f docker/Dockerfile.test -t config_files_test .
|
78
|
+
docker run --rm config_files_test
|
79
|
+
```
|
80
|
+
|
81
|
+
### 3. Single Version Testing
|
82
|
+
|
83
|
+
#### Standard Testing
|
84
|
+
```bash
|
85
|
+
# Install dependencies
|
86
|
+
bundle install
|
87
|
+
|
88
|
+
# Run all tests
|
89
|
+
bundle exec rake test
|
90
|
+
|
91
|
+
# Run tests with verbose output
|
92
|
+
bundle exec rake test_verbose
|
93
|
+
|
94
|
+
# Run individual test files
|
95
|
+
find test -name "*_test.rb" -exec bundle exec ruby {} \;
|
96
|
+
```
|
97
|
+
|
98
|
+
#### Testing with Specific ActiveSupport Version
|
99
|
+
```bash
|
100
|
+
# Create a custom Gemfile
|
101
|
+
cat > Gemfile.custom << EOF
|
102
|
+
source 'https://rubygems.org'
|
103
|
+
gemspec
|
104
|
+
gem 'activesupport', '~> 6.1.0'
|
105
|
+
gem 'minitest', '~> 5.20'
|
106
|
+
gem 'rake'
|
107
|
+
EOF
|
108
|
+
|
109
|
+
# Install and test
|
110
|
+
BUNDLE_GEMFILE=Gemfile.custom bundle install
|
111
|
+
BUNDLE_GEMFILE=Gemfile.custom bundle exec rake test
|
112
|
+
```
|
113
|
+
|
114
|
+
## Test Structure
|
115
|
+
|
116
|
+
### Test Files
|
117
|
+
- `test/config_files_test.rb` - Core functionality tests
|
118
|
+
- `test/loader_factory_test.rb` - File loader tests
|
119
|
+
- `test/multi_directory_test.rb` - Multi-directory functionality
|
120
|
+
- `test/mixed_format_test.rb` - Mixed YAML/JSON format tests
|
121
|
+
- `test/comprehensive_multi_directory_test.rb` - Complex scenarios
|
122
|
+
|
123
|
+
### Test Data
|
124
|
+
- `test/etc/` - Sample configuration files
|
125
|
+
- `test/config/` - Additional test configurations
|
126
|
+
- `test/local/` - Local override test files
|
127
|
+
|
128
|
+
## Compatibility Testing
|
129
|
+
|
130
|
+
### Ruby Version Compatibility
|
131
|
+
|
132
|
+
The gem uses these Ruby features that affect compatibility:
|
133
|
+
|
134
|
+
1. **Safe Navigation Operator (`&.`)** - Requires Ruby 2.3+
|
135
|
+
2. **Keyword Arguments** - Requires Ruby 2.0+
|
136
|
+
3. **ActiveSupport Dependencies** - Varies by version
|
137
|
+
|
138
|
+
### ActiveSupport Compatibility
|
139
|
+
|
140
|
+
Different ActiveSupport versions have different Ruby requirements:
|
141
|
+
|
142
|
+
- ActiveSupport 5.2: Ruby 2.2.2+
|
143
|
+
- ActiveSupport 6.0: Ruby 2.5.0+
|
144
|
+
- ActiveSupport 6.1: Ruby 2.5.0+
|
145
|
+
- ActiveSupport 7.0: Ruby 2.7.0+
|
146
|
+
- ActiveSupport 7.1: Ruby 3.1.0+
|
147
|
+
- ActiveSupport 7.2: Ruby 3.1.0+
|
148
|
+
|
149
|
+
## Troubleshooting
|
150
|
+
|
151
|
+
### Common Issues
|
152
|
+
|
153
|
+
1. **Safe Navigation Operator Error**
|
154
|
+
```
|
155
|
+
undefined method `&' for nil:NilClass
|
156
|
+
```
|
157
|
+
**Solution**: Use Ruby 2.3+ or replace `&.` with `&& obj.`
|
158
|
+
|
159
|
+
2. **ActiveSupport Version Conflicts**
|
160
|
+
```
|
161
|
+
Gem::ConflictError: Unable to activate activesupport
|
162
|
+
```
|
163
|
+
**Solution**: Check Ruby/ActiveSupport compatibility matrix above
|
164
|
+
|
165
|
+
3. **Minitest Version Issues**
|
166
|
+
```
|
167
|
+
cannot load such file -- mutex_m
|
168
|
+
```
|
169
|
+
**Solution**: Add `mutex_m` gem for Ruby 3.4+
|
170
|
+
|
171
|
+
### Running Specific Test Combinations
|
172
|
+
|
173
|
+
```bash
|
174
|
+
# Test Ruby 3.3 with ActiveSupport 7.0
|
175
|
+
RUBY_VERSION=3.3 ACTIVESUPPORT_VERSION="~> 7.0" ./scripts/test_combination.sh
|
176
|
+
|
177
|
+
# Test with Docker
|
178
|
+
docker build --build-arg RUBY_VERSION=3.3 --build-arg ACTIVESUPPORT_VERSION="~> 7.0" -f docker/Dockerfile.test -t test .
|
179
|
+
docker run --rm test
|
180
|
+
```
|
181
|
+
|
182
|
+
## CI/CD Integration
|
183
|
+
|
184
|
+
### GitHub Actions
|
185
|
+
|
186
|
+
The project automatically tests all supported combinations on:
|
187
|
+
- Push to main/master branch
|
188
|
+
- Pull requests
|
189
|
+
- Manual workflow dispatch
|
190
|
+
|
191
|
+
### Other CI Systems
|
192
|
+
|
193
|
+
The testing approach can be adapted for other CI systems:
|
194
|
+
|
195
|
+
- **GitLab CI**: Use similar matrix strategy with `.gitlab-ci.yml`
|
196
|
+
- **CircleCI**: Use workflow matrix with different Ruby Docker images
|
197
|
+
- **Jenkins**: Use pipeline with multiple Ruby environments
|
198
|
+
|
199
|
+
## Performance Testing
|
200
|
+
|
201
|
+
For performance testing across versions:
|
202
|
+
|
203
|
+
```bash
|
204
|
+
# Run benchmarks (if implemented)
|
205
|
+
bundle exec rake benchmark
|
206
|
+
|
207
|
+
# Memory usage testing
|
208
|
+
bundle exec ruby -r memory_profiler test/memory_test.rb
|
209
|
+
```
|
210
|
+
|
211
|
+
## Contributing
|
212
|
+
|
213
|
+
When adding new features:
|
214
|
+
|
215
|
+
1. Ensure tests pass on all supported Ruby versions
|
216
|
+
2. Add tests for new functionality
|
217
|
+
3. Update compatibility documentation if needed
|
218
|
+
4. Run the full test matrix before submitting PRs
|
219
|
+
|
220
|
+
```bash
|
221
|
+
# Quick local test
|
222
|
+
bundle exec rake test
|
223
|
+
|
224
|
+
# Full compatibility test
|
225
|
+
./scripts/test_multiple_rubies.sh
|
226
|
+
```
|
data/config_files.gemspec
CHANGED
@@ -1,25 +1,28 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
5
|
require 'config_files/version'
|
4
6
|
|
5
7
|
Gem::Specification.new do |spec|
|
6
8
|
spec.authors = ['Paul McKibbin']
|
7
9
|
spec.email = ['pmckibbin@gmail.com']
|
8
|
-
spec.description = '
|
10
|
+
spec.description = 'Configuration tool for cascading configuration files with multiple formats'
|
9
11
|
spec.summary = <<-SUMMARY
|
10
12
|
ConfigFiles is a configuration file access tool. It parses multiple configuration files in multiple formats and
|
11
|
-
presents a consistent block to the application with options to cache or use the files dynamically
|
12
|
-
|
13
|
+
presents a consistent block to the application with options to cache or use the files dynamically. It uses a priority
|
14
|
+
directory ordering to find the files, and an alphabetical ordering to give precedence to the files in that directory.
|
15
|
+
SUMMARY
|
13
16
|
|
14
17
|
spec.homepage = 'https://github.com/blackrat/config_files'
|
15
18
|
spec.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
16
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
19
|
spec.name = 'config_files'
|
18
20
|
spec.require_paths = ['lib']
|
19
21
|
spec.version = ConfigFiles::VERSION
|
20
22
|
spec.license = 'MIT'
|
21
|
-
spec.
|
23
|
+
spec.required_ruby_version = '>= 2.7.0'
|
22
24
|
|
23
|
-
spec.
|
24
|
-
spec.
|
25
|
-
|
25
|
+
spec.add_dependency 'activesupport', '>= 6.1', '< 8.0'
|
26
|
+
spec.add_dependency 'rexml', '~> 3.2'
|
27
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
ARG RUBY_VERSION=3.3
|
2
|
+
FROM ruby:${RUBY_VERSION}-slim
|
3
|
+
|
4
|
+
# Install system dependencies
|
5
|
+
RUN apt-get update && apt-get install -y \
|
6
|
+
build-essential \
|
7
|
+
git \
|
8
|
+
&& rm -rf /var/lib/apt/lists/*
|
9
|
+
|
10
|
+
# Set working directory
|
11
|
+
WORKDIR /app
|
12
|
+
|
13
|
+
# Copy gemspec and version file first for better caching
|
14
|
+
COPY config_files.gemspec ./
|
15
|
+
COPY lib/config_files/version.rb ./lib/config_files/
|
16
|
+
|
17
|
+
# Copy Gemfile if it exists
|
18
|
+
COPY Gemfile* ./
|
19
|
+
|
20
|
+
# Install gems
|
21
|
+
ARG ACTIVESUPPORT_VERSION="~> 7.0"
|
22
|
+
RUN echo "gem 'activesupport', '${ACTIVESUPPORT_VERSION}'" >> Gemfile.docker && \
|
23
|
+
echo "gem 'minitest', '~> 5.20'" >> Gemfile.docker && \
|
24
|
+
echo "gem 'mutex_m'" >> Gemfile.docker && \
|
25
|
+
echo "gem 'rake'" >> Gemfile.docker && \
|
26
|
+
BUNDLE_GEMFILE=Gemfile.docker bundle install
|
27
|
+
|
28
|
+
# Copy the rest of the application
|
29
|
+
COPY . .
|
30
|
+
|
31
|
+
# Run tests
|
32
|
+
CMD ["sh", "-c", "BUNDLE_GEMFILE=Gemfile.docker bundle exec rake test"]
|
@@ -1,14 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ConfigFiles
|
2
4
|
class FileFactory
|
3
5
|
class << self
|
4
6
|
private
|
7
|
+
|
5
8
|
def loader(file_name, options)
|
6
|
-
LoaderFactory.(file_name, options)
|
9
|
+
LoaderFactory.call(file_name, options)
|
7
10
|
end
|
8
11
|
|
9
12
|
public
|
10
|
-
|
11
|
-
|
13
|
+
|
14
|
+
def call(file_name, options = {})
|
15
|
+
loader(file_name, options).call(file_name)
|
12
16
|
end
|
13
17
|
end
|
14
18
|
end
|
@@ -1,19 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ConfigFiles
|
2
4
|
class LoaderFactory
|
3
5
|
class << self
|
4
|
-
|
5
|
-
def call(file_name, options={include_default: true})
|
6
|
+
def call(file_name, options = { include_default: true })
|
6
7
|
new(options).call(file_name)
|
7
8
|
end
|
8
9
|
end
|
9
10
|
|
10
11
|
private
|
12
|
+
|
11
13
|
attr_reader :options
|
12
14
|
|
13
15
|
def default_loaders
|
14
16
|
{
|
15
|
-
Loaders::Yaml => [
|
16
|
-
Loaders::Json =>
|
17
|
+
Loaders::Yaml => %w[yaml yml],
|
18
|
+
Loaders::Json => ['json'],
|
19
|
+
Loaders::Conf => ['conf'],
|
20
|
+
Loaders::Ini => ['ini'],
|
21
|
+
Loaders::Xml => ['xml'],
|
17
22
|
}
|
18
23
|
end
|
19
24
|
|
@@ -25,7 +30,7 @@ module ConfigFiles
|
|
25
30
|
{
|
26
31
|
include_default: true,
|
27
32
|
default_loader: Loaders::Yaml,
|
28
|
-
loaders: default_loaders
|
33
|
+
loaders: default_loaders,
|
29
34
|
}
|
30
35
|
end
|
31
36
|
|
@@ -37,16 +42,20 @@ module ConfigFiles
|
|
37
42
|
options[:loaders]
|
38
43
|
end
|
39
44
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
+
# Note the check below is necessary, because we only want to do it if it is explicity set
|
46
|
+
def initialize(options)
|
47
|
+
@options = default_options.merge(options)
|
48
|
+
return unless include_default_loaders?
|
49
|
+
|
50
|
+
@options[:loaders] = default_loaders.merge(loaders)
|
45
51
|
end
|
46
52
|
|
47
53
|
public
|
54
|
+
|
48
55
|
def call(file_name)
|
49
|
-
loaders.detect
|
56
|
+
loaders.detect do |_, extensions|
|
57
|
+
extensions.include?(::File.extname(file_name).strip.downcase[1..])
|
58
|
+
end&.first || default_loader
|
50
59
|
end
|
51
60
|
end
|
52
61
|
end
|