anyway_config 1.4.4 → 2.0.0.pre
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/README.md +187 -51
- data/lib/anyway.rb +22 -2
- data/lib/anyway/config.rb +116 -98
- data/lib/anyway/dynamic_config.rb +27 -0
- data/lib/anyway/env.rb +2 -5
- data/lib/anyway/ext/deep_dup.rb +4 -4
- data/lib/anyway/ext/deep_freeze.rb +5 -0
- data/lib/anyway/ext/jruby.rb +9 -4
- data/lib/anyway/ext/string_serialize.rb +1 -7
- data/{spec/dummy/config.ru → lib/anyway/loaders/env_loader.rb} +0 -0
- data/lib/anyway/loaders/secrets_loader.rb +0 -0
- data/lib/anyway/loaders/yaml_loader.rb +0 -0
- data/lib/anyway/option_parser_builder.rb +2 -2
- data/lib/anyway/optparse_config.rb +90 -0
- data/lib/anyway/rails/config.rb +76 -24
- data/lib/anyway/railtie.rb +11 -0
- data/lib/anyway/testing.rb +13 -0
- data/lib/anyway/testing/helpers.rb +36 -0
- data/lib/anyway/version.rb +1 -1
- metadata +46 -48
- data/.gem_release.yml +0 -3
- data/.gitignore +0 -40
- data/.rubocop.yml +0 -50
- data/.travis.yml +0 -30
- data/CHANGELOG.md +0 -112
- data/Gemfile +0 -21
- data/Rakefile +0 -23
- data/anyway_config.gemspec +0 -29
- data/config/cool.yml +0 -5
- data/gemfiles/jruby.gemfile +0 -7
- data/gemfiles/rails42.gemfile +0 -6
- data/gemfiles/rails5.gemfile +0 -6
- data/gemfiles/railsmaster.gemfile +0 -7
- data/spec/anyway.yml +0 -2
- data/spec/config_spec.rb +0 -337
- data/spec/config_spec_norails.rb +0 -86
- data/spec/dummy/config/application.rb +0 -13
- data/spec/dummy/config/boot.rb +0 -5
- data/spec/dummy/config/cool.yml +0 -5
- data/spec/dummy/config/cool_custom.yml +0 -2
- data/spec/dummy/config/database.yml +0 -25
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/test.rb +0 -2
- data/spec/dummy/config/routes.rb +0 -2
- data/spec/dummy/config/secrets.yml +0 -30
- data/spec/env_spec.rb +0 -50
- data/spec/ext/deep_dup_spec.rb +0 -38
- data/spec/ext/deep_freeze_spec.rb +0 -32
- data/spec/ext/hash_spec.rb +0 -39
- data/spec/ext/string_serialize_spec.rb +0 -32
- data/spec/spec_helper.rb +0 -31
- data/spec/spec_norails_helper.rb +0 -26
- data/spec/support/cool_config.rb +0 -10
- data/spec/support/print_warning_matcher.rb +0 -34
- data/spec/support/small_config.rb +0 -7
- data/spec/support/test_config.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d8ed2249df0baa740893d459922e839793eab4cef51b9410e2c618393ba88a7
|
4
|
+
data.tar.gz: 587d0578b716af5035e393ab29eabff5aea163d44f705ed9b245eb51d083b4f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5fb7bcf6b692b6fc75f4eb0ca3170787defac2063d646ca8c9ec77d3563e526c58dc16af77e42bf6d293da21d8303d6d82afca723e2b97e528b243702f1c38b5
|
7
|
+
data.tar.gz: b89c278a7436c024f61894f59c885704c2cf4ae539bb382825181fe13d5f787662c6aafdc39b7d49ba9f4ee1c9535128e3fadb7904016c790907010e165996b9
|
data/README.md
CHANGED
@@ -3,7 +3,10 @@
|
|
3
3
|
|
4
4
|
# Anyway Config
|
5
5
|
|
6
|
-
|
6
|
+
**NOTE:** this readme shows doc for the upcoming 2.0 version (`2.0.0.pre` is available on RubyGems).
|
7
|
+
For version 1.x see [1-4-stable branch](https://github.com/palkan/anyway_config/tree/1-4-stable).
|
8
|
+
|
9
|
+
Rails/Ruby plugin/application configuration tool which allows you to load parameters from different sources: YAML, Rails secrets/credentials, environment.
|
7
10
|
|
8
11
|
Allows you to easily follow the [twelve-factor application](https://12factor.net/config) principles and adds zero complexity to your development process.
|
9
12
|
|
@@ -15,6 +18,8 @@ Libraries using Anyway Config:
|
|
15
18
|
|
16
19
|
- [Sniffer](https://github.com/aderyabin/sniffer)
|
17
20
|
|
21
|
+
- [Blood Contracts](https://github.com/sclinede/blood_contracts)
|
22
|
+
|
18
23
|
- [and others](https://github.com/palkan/anyway_config/network/dependents).
|
19
24
|
|
20
25
|
## Installation
|
@@ -24,9 +29,9 @@ Libraries using Anyway Config:
|
|
24
29
|
```ruby
|
25
30
|
# my-cool-gem.gemspec
|
26
31
|
Gem::Specification.new do |spec|
|
27
|
-
...
|
28
|
-
spec.add_dependency "anyway_config", "
|
29
|
-
...
|
32
|
+
# ...
|
33
|
+
spec.add_dependency "anyway_config", "2.0.0.pre"
|
34
|
+
# ...
|
30
35
|
end
|
31
36
|
```
|
32
37
|
|
@@ -34,7 +39,7 @@ end
|
|
34
39
|
|
35
40
|
```ruby
|
36
41
|
# Gemfile
|
37
|
-
gem "anyway_config", "
|
42
|
+
gem "anyway_config", "2.0.0.pre"
|
38
43
|
```
|
39
44
|
|
40
45
|
3) Install globally:
|
@@ -50,11 +55,11 @@ $ gem install anyway_config
|
|
50
55
|
Create configuration class:
|
51
56
|
|
52
57
|
```ruby
|
53
|
-
require
|
58
|
+
require "anyway"
|
54
59
|
|
55
60
|
module MyCoolGem
|
56
61
|
class Config < Anyway::Config
|
57
|
-
attr_config user:
|
62
|
+
attr_config user: "root", password: "root", host: "localhost"
|
58
63
|
end
|
59
64
|
end
|
60
65
|
```
|
@@ -62,7 +67,7 @@ end
|
|
62
67
|
`attr_config` creates accessors and default values. If you don't need default values just write:
|
63
68
|
|
64
69
|
```ruby
|
65
|
-
attr_config :user, :password, host:
|
70
|
+
attr_config :user, :password, host: "localhost", options: {}
|
66
71
|
```
|
67
72
|
|
68
73
|
Then create an instance of the config class and use it:
|
@@ -74,33 +79,43 @@ module MyCoolGem
|
|
74
79
|
end
|
75
80
|
end
|
76
81
|
|
77
|
-
MyCoolGem.config.user #=>
|
82
|
+
MyCoolGem.config.user #=> "root"
|
78
83
|
```
|
79
84
|
|
80
|
-
####
|
85
|
+
#### Config name
|
86
|
+
|
87
|
+
Anyway Config relies on the notion of _config name_ to populate data.
|
88
|
+
|
89
|
+
By default, Anyway Config uses the config class name to infer the config name using the following rules:
|
90
|
+
- if the class name has a form of `<Module>::Config` then use the module name (`SomeModule::Config => "somemodule"`)
|
91
|
+
- if the class name has a form of `<Something>Config` then use the class name prefix (`SomeConfig => "some"`)
|
81
92
|
|
82
|
-
|
93
|
+
**NOTE:** in both cases the config name is a **downcased** module/class prefix, not underscored.
|
94
|
+
|
95
|
+
You can also specify the config name explicitly (it's required in cases when you class name doesn't match any of the patterns above):
|
83
96
|
|
84
97
|
```ruby
|
85
98
|
module MyCoolGem
|
86
99
|
class Config < Anyway::Config
|
87
100
|
config_name :cool
|
88
|
-
attr_config user:
|
101
|
+
attr_config user: "root", password: "root", host: "localhost", options: {}
|
89
102
|
end
|
90
103
|
end
|
91
104
|
```
|
92
105
|
|
93
106
|
#### Customize env variable names prefix
|
94
107
|
|
95
|
-
By default, Anyway Config uses
|
96
|
-
`config_name :my_app` will result to parsing `
|
97
|
-
|
108
|
+
By default, Anyway Config uses upcased config name as a prefix for env variable names (e.g.
|
109
|
+
`config_name :my_app` will result to parsing `MY_APP_` prefix).
|
110
|
+
|
111
|
+
You can set env prefix explicitly:
|
98
112
|
|
99
113
|
```ruby
|
100
114
|
module MyCoolGem
|
101
115
|
class Config < Anyway::Config
|
116
|
+
config_name :cool_gem
|
102
117
|
env_prefix :really_cool # now variables, starting wih `REALLY_COOL_`, will be parsed
|
103
|
-
attr_config user:
|
118
|
+
attr_config user: "root", password: "root", host: "localhost", options: {}
|
104
119
|
end
|
105
120
|
end
|
106
121
|
```
|
@@ -108,18 +123,16 @@ end
|
|
108
123
|
#### Provide explicit values
|
109
124
|
|
110
125
|
Sometimes it's useful to set some parameters explicitly during config initialization.
|
111
|
-
You can do that
|
126
|
+
You can do that by passing a Hash into `.new` method:
|
112
127
|
|
113
128
|
```ruby
|
114
129
|
config = MyCoolGem::Config.new(
|
115
|
-
|
116
|
-
|
117
|
-
password: 'rubyisnotdead'
|
118
|
-
}
|
130
|
+
user: "john",
|
131
|
+
password: "rubyisnotdead"
|
119
132
|
)
|
120
133
|
|
121
134
|
# The value would not be overriden from other sources (such as YML file, env)
|
122
|
-
config.user ==
|
135
|
+
config.user == "john"
|
123
136
|
```
|
124
137
|
|
125
138
|
### Dynamic configuration
|
@@ -127,32 +140,121 @@ config.user == 'john'
|
|
127
140
|
You can also create configuration objects without pre-defined schema (just like `Rails.application.config_for` but more [powerful](#railsapplicationconfig_for-vs-anywayconfigfor)):
|
128
141
|
|
129
142
|
```ruby
|
130
|
-
# load data from config/my_app.yml, secrets.my_app (if using Rails), ENV["
|
143
|
+
# load data from config/my_app.yml, secrets.my_app (if using Rails), ENV["MY_APP_*"]
|
144
|
+
# MY_APP_VALUE=42
|
131
145
|
config = Anyway::Config.for(:my_app)
|
146
|
+
config.value #=> 42
|
147
|
+
|
148
|
+
# you can specify the config file path or env prefix
|
149
|
+
config = Anyway::Config.for(:my_app, config_path: "my_config.yml", env_prefix: "MYAPP")
|
132
150
|
```
|
133
151
|
|
134
152
|
### Using with Rails
|
135
153
|
|
154
|
+
**NOTE:** version 2.x supports Rails >= 5.0; for Rails 4.x use version 1.x of the gem.
|
155
|
+
|
136
156
|
Your config will be filled up with values from the following sources (ordered by priority from low to high):
|
137
157
|
|
138
|
-
- `RAILS_ROOT/config/my_cool_gem.yml` (for the current `RAILS_ENV`, supports `ERB`)
|
139
|
-
through special environment variable – 'MYCOOLGEM_CONF' – containing the path to the YAML file.
|
158
|
+
- `RAILS_ROOT/config/my_cool_gem.yml` (for the current `RAILS_ENV`, supports `ERB`):
|
140
159
|
|
141
|
-
|
160
|
+
```yml
|
161
|
+
test:
|
162
|
+
host: localhost
|
163
|
+
port: 3002
|
164
|
+
|
165
|
+
development:
|
166
|
+
host: localhost
|
167
|
+
port: 3000
|
168
|
+
```
|
169
|
+
|
170
|
+
**NOTE:** you can override the default YML lookup path by setting `MYCOOLGEM_CONF` env variable.
|
171
|
+
|
172
|
+
- `Rails.application.secrets.my_cool_gem` (if `secrets.yml` present):
|
173
|
+
|
174
|
+
```yml
|
175
|
+
# config/secrets.yml
|
176
|
+
development:
|
177
|
+
my_cool_gem:
|
178
|
+
port: 4444
|
179
|
+
```
|
180
|
+
|
181
|
+
- `Rails.application.credentials` (if supported):
|
182
|
+
|
183
|
+
```yml
|
184
|
+
my_cool_gem:
|
185
|
+
host: secret.host
|
186
|
+
```
|
142
187
|
|
143
188
|
- `ENV['MYCOOLGEM_*']`.
|
144
189
|
|
190
|
+
#### `app/configs`
|
191
|
+
|
192
|
+
You can store application-level config classes in `app/configs` folder.
|
193
|
+
|
194
|
+
Anyway Config automatically adds this folder to Rails autoloading system to make it possible to
|
195
|
+
autoload configs even during the configuration phase.
|
196
|
+
|
197
|
+
Consider an example: setting the Action Mailer host name for Heroku review apps.
|
198
|
+
|
199
|
+
We have the following config to fetch the Heroku provided [metadata](https://devcenter.heroku.com/articles/dyno-metadata):
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
# This data is provided by Heroku Dyno Metadadata add-on.
|
203
|
+
class HerokuConfig < Anyway::Config
|
204
|
+
attr_config :app_id, :app_name,
|
205
|
+
:dyno_id, :release_version,
|
206
|
+
:slug_commit
|
207
|
+
|
208
|
+
def hostname
|
209
|
+
"#{app_name}.herokuapp.com"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
```
|
213
|
+
|
214
|
+
Then in `config/application.rb` you can do the following:
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
config.action_mailer.default_url_options = {host: HerokuConfig.new.hostname}
|
218
|
+
```
|
219
|
+
|
145
220
|
### Using with Ruby
|
146
221
|
|
147
|
-
|
148
|
-
|
222
|
+
When you're using Anyway Config in non-Rails environment, we're looking for a YANL config file
|
223
|
+
at `./config/<config-name>.yml`.
|
149
224
|
|
150
|
-
|
225
|
+
You can override this setting through special environment variable – 'MYCOOLGEM_CONF' – containing the path to the YAML file.
|
151
226
|
|
227
|
+
**NOTE:** in pure Ruby apps we have no knowledge of _environments_ (`test`, `development`, `production`, etc.); thus we assume that the YAML contains values for a single environment:
|
152
228
|
|
153
|
-
|
229
|
+
```yml
|
230
|
+
host: localhost
|
231
|
+
port: 3000
|
232
|
+
```
|
233
|
+
|
234
|
+
Environmental variables work the same way as with Rails.
|
235
|
+
|
236
|
+
### Local files
|
237
|
+
|
238
|
+
It's useful to have personal, user-specific configuration in development, which extends the project-wide one.
|
239
|
+
|
240
|
+
We support this by looking at _local_ files when loading the configuration data:
|
241
|
+
- `<config_name>.local.yml` files (next to\* the _global_ `<config_name>.yml`)
|
242
|
+
- `config/credentials/local.yml.enc` (for Rails >= 6, generate it via `rails credentials:edit --environment local`).
|
243
|
+
|
244
|
+
\* If the YAML config path is not default (i.e. set via `<CONFIG_NAME>_CONF`), we lookup the local
|
245
|
+
config at this location, too.
|
246
|
+
|
247
|
+
Local configs are meant for using in development and only loaded if `Anyway::Settings.use_local_files` is `true` (which is true by default if `RACK_ENV` or `RAILS_ENV` env variable is equal to `"development"`).
|
248
|
+
|
249
|
+
**NOTE:** in Rails apps you can use `Rails.applicaiton.configuration.anyway_config.use_local_files`.
|
154
250
|
|
155
|
-
|
251
|
+
Don't forget to add `*.local.yml` (and `config/credentials/local.*`) to your `.gitignore`.
|
252
|
+
|
253
|
+
**NOTE:** local YAML configs for Rails app must be environment-free (i.e. you shouldn't have top-level `development:` key).
|
254
|
+
|
255
|
+
### Reload configuration
|
256
|
+
|
257
|
+
There are `#clear` and `#reload` methods which do exactly what they state.
|
156
258
|
|
157
259
|
Note: `#reload` also accepts `overrides` key to provide explicit values (see above).
|
158
260
|
|
@@ -194,7 +296,7 @@ end
|
|
194
296
|
|
195
297
|
config = MyConfig.new
|
196
298
|
|
197
|
-
config.parse_options!(%w
|
299
|
+
config.parse_options!(%w[--host localhost --port 3333 --log-level debug])
|
198
300
|
|
199
301
|
config.host # => "localhost"
|
200
302
|
config.port # => 3333
|
@@ -211,10 +313,12 @@ Rails 4.2 introduced new feature: `Rails.application.config_for`. It looks very
|
|
211
313
|
|
212
314
|
| Feature | Rails | Anyway Config |
|
213
315
|
| ------------- |:-------------:| -----:|
|
214
|
-
| load data from `config/app.yml`
|
215
|
-
| load data from `secrets` | no
|
216
|
-
| load data from
|
217
|
-
|
|
316
|
+
| load data from `config/app.yml` | yes | yes |
|
317
|
+
| load data from `secrets` | no | yes |
|
318
|
+
| load data from `credentials` | no | yes |
|
319
|
+
| load data from environment | no | yes |
|
320
|
+
| local config files | no | yes |
|
321
|
+
| return Hash with indifferent access | no | yes |
|
218
322
|
| support ERB within `config/app.yml` | yes | yes* |
|
219
323
|
| raise errors if file doesn't exist | yes | no |
|
220
324
|
|
@@ -224,23 +328,18 @@ But the main advantage of Anyway::Config is that it can be used [without Rails](
|
|
224
328
|
|
225
329
|
## How to set env vars
|
226
330
|
|
227
|
-
Environmental variables for your config should start with your config name, uppercased
|
228
|
-
|
229
|
-
For example, if your module is called "MyCoolGem" then the env var "MYCOOLGEM_PASSWORD" is used as `config.password`.
|
331
|
+
Environmental variables for your config should start with your config name, uppercased.
|
230
332
|
|
231
|
-
|
232
|
-
|
233
|
-
Examples:
|
333
|
+
For example, if your config name is "mycoolgem" then the env var "MYCOOLGEM_PASSWORD" is used as `config.password`.
|
234
334
|
|
335
|
+
Environment variables are automatically serialized:
|
235
336
|
- `"True"`, `"t"` and `"yes"` to `true`;
|
236
|
-
|
237
337
|
- `"False"`, `"f"` and `"no"` to `false`;
|
238
|
-
|
239
338
|
- `"nil"` and `"null"` to `nil` (do you really need it?);
|
240
|
-
|
241
339
|
- `"123"` to 123 and `"3.14"` to 3.14.
|
242
340
|
|
243
341
|
*Anyway Config* supports nested (_hashed_) env variables. Just separate keys with double-underscore.
|
342
|
+
|
244
343
|
For example, "MYCOOLGEM_OPTIONS__VERBOSE" is parsed as `config.options["verbose"]`.
|
245
344
|
|
246
345
|
Array values are also supported:
|
@@ -253,13 +352,50 @@ config.ids #=> [1,2,3]
|
|
253
352
|
If you want to provide a text-like env variable which contains commas then wrap it into quotes:
|
254
353
|
|
255
354
|
```ruby
|
256
|
-
MYCOOLGEM="Nif-Nif, Naf-Naf and Nouf-Nouf"
|
355
|
+
MYCOOLGEM = "Nif-Nif, Naf-Naf and Nouf-Nouf"
|
257
356
|
```
|
258
357
|
|
358
|
+
## Test helpers
|
359
|
+
|
360
|
+
We provide the `with_env` test helper to test code in the context of the specified environment variables values:
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
describe HerokuConfig, type: :config do
|
364
|
+
subject { described_class.new }
|
365
|
+
|
366
|
+
specify do
|
367
|
+
# Ensure that the env vars are set to the specified
|
368
|
+
# values within the block and reset to the previous values
|
369
|
+
# outside of it.
|
370
|
+
with_env(
|
371
|
+
"HEROKU_APP_NAME" => "kin-web-staging",
|
372
|
+
"HEROKU_APP_ID" => "abc123",
|
373
|
+
"HEROKU_DYNO_ID" => "ddyy",
|
374
|
+
"HEROKU_RELEASE_VERSION" => "v0",
|
375
|
+
"HEROKU_SLUG_COMMIT" => "3e4d5a"
|
376
|
+
) do
|
377
|
+
is_expected.to have_attributes(
|
378
|
+
app_name: "kin-web-staging",
|
379
|
+
app_id: "abc123",
|
380
|
+
dyno_id: "ddyy",
|
381
|
+
release_version: "v0",
|
382
|
+
slug_commit: "3e4d5a"
|
383
|
+
)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
```
|
388
|
+
|
389
|
+
If you want to delete the env var, pass `nil` as the value.
|
390
|
+
|
391
|
+
This helper is automatically included to RSpec if `RAILS_ENV` or `RACK_ENV` env variable is equal to "test". It's only available for the example with the tag `type: :config` or with the path `spec/configs/...`.
|
392
|
+
|
393
|
+
You can add it manually by requiring `"anyway/testing/helpers"` and including the `Anyway::Test::Helpers` module (into RSpec configuration or Minitest test class).
|
394
|
+
|
259
395
|
## Contributing
|
260
396
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
397
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/palkan/anyway_config.
|
398
|
+
|
399
|
+
## License
|
400
|
+
|
401
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/lib/anyway.rb
CHANGED
@@ -2,11 +2,31 @@
|
|
2
2
|
|
3
3
|
module Anyway # :nodoc:
|
4
4
|
require "anyway/version"
|
5
|
+
|
5
6
|
require "anyway/config"
|
6
7
|
require "anyway/rails/config" if defined?(::Rails::VERSION)
|
7
8
|
require "anyway/env"
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
# Use Settings name to not confuse with Config.
|
11
|
+
#
|
12
|
+
# Settings contain the library-wide configuration.
|
13
|
+
class Settings
|
14
|
+
class << self
|
15
|
+
# Define whether to load data from
|
16
|
+
# *.yml.local (or credentials/local.yml.enc)
|
17
|
+
attr_accessor :use_local_files
|
18
|
+
end
|
19
|
+
|
20
|
+
# By default, use local files only in development (that's the purpose if the local files)
|
21
|
+
self.use_local_files = (ENV["RACK_ENV"] == "development" || ENV["RAILS_ENV"] == "development")
|
11
22
|
end
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def env
|
26
|
+
@env ||= ::Anyway::Env.new
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
require "anyway/railtie" if defined?(::Rails::VERSION)
|
31
|
+
require "anyway/testing" if ENV["RACK_ENV"] == "test" || ENV["RAILS_ENV"] == "test"
|
12
32
|
end
|
data/lib/anyway/config.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
3
|
+
require "anyway/optparse_config"
|
4
|
+
require "anyway/dynamic_config"
|
5
|
+
|
6
|
+
require "anyway/ext/jruby" if defined? JRUBY_VERSION
|
7
|
+
require "anyway/ext/deep_dup"
|
8
|
+
require "anyway/ext/deep_freeze"
|
9
|
+
require "anyway/ext/hash"
|
10
|
+
require "anyway/ext/string_serialize"
|
9
11
|
|
10
12
|
module Anyway # :nodoc:
|
11
13
|
if defined? JRUBY_VERSION
|
@@ -21,108 +23,116 @@ module Anyway # :nodoc:
|
|
21
23
|
# Provides `attr_config` method to describe
|
22
24
|
# configuration parameters and set defaults
|
23
25
|
class Config
|
24
|
-
|
25
|
-
|
26
|
+
include OptparseConfig
|
27
|
+
include DynamicConfig
|
26
28
|
|
29
|
+
class << self
|
27
30
|
def attr_config(*args, **hargs)
|
28
|
-
@defaults ||= {}
|
29
|
-
@config_attributes ||= []
|
30
|
-
|
31
31
|
new_defaults = hargs.deep_dup
|
32
32
|
new_defaults.stringify_keys!
|
33
|
+
|
33
34
|
defaults.merge! new_defaults
|
34
35
|
|
35
36
|
new_keys = (args + new_defaults.keys) - config_attributes
|
36
|
-
|
37
|
+
config_attributes.push(*new_keys)
|
37
38
|
attr_accessor(*new_keys)
|
38
39
|
end
|
39
40
|
|
40
|
-
def
|
41
|
-
return
|
41
|
+
def defaults
|
42
|
+
return @defaults if instance_variable_defined?(:@defaults)
|
42
43
|
|
43
|
-
@
|
44
|
-
|
44
|
+
@defaults =
|
45
|
+
if superclass < Anyway::Config
|
46
|
+
superclass.defaults.deep_dup
|
47
|
+
else
|
48
|
+
{}
|
49
|
+
end
|
45
50
|
end
|
46
51
|
|
47
|
-
def
|
48
|
-
|
49
|
-
option_parser_descriptors[name.to_s][:ignore] = true
|
50
|
-
end
|
51
|
-
end
|
52
|
+
def config_attributes
|
53
|
+
return @config_attributes if instance_variable_defined?(:@config_attributes)
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
@config_attributes =
|
56
|
+
if superclass < Anyway::Config
|
57
|
+
superclass.config_attributes.dup
|
58
|
+
else
|
59
|
+
[]
|
60
|
+
end
|
57
61
|
end
|
58
62
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
63
|
+
def config_name(val = nil)
|
64
|
+
return (@explicit_config_name = val.to_s) unless val.nil?
|
65
|
+
|
66
|
+
return @config_name if instance_variable_defined?(:@config_name)
|
64
67
|
|
65
|
-
|
66
|
-
@option_parser_extension = block
|
68
|
+
@config_name = explicit_config_name || build_config_name
|
67
69
|
end
|
68
70
|
|
69
|
-
def
|
70
|
-
|
71
|
-
descriptor = option_parser_descriptors[key.to_s]
|
72
|
-
next if descriptor[:ignore] == true
|
71
|
+
def explicit_config_name
|
72
|
+
return @explicit_config_name if instance_variable_defined?(:@explicit_config_name)
|
73
73
|
|
74
|
-
|
75
|
-
|
74
|
+
@explicit_config_name =
|
75
|
+
if superclass.respond_to?(:explicit_config_name)
|
76
|
+
superclass.explicit_config_name
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def explicit_config_name?
|
81
|
+
!explicit_config_name.nil?
|
76
82
|
end
|
77
83
|
|
78
84
|
def env_prefix(val = nil)
|
79
|
-
return (@env_prefix = val.to_s) unless val.nil?
|
85
|
+
return (@env_prefix = val.to_s.upcase) unless val.nil?
|
80
86
|
|
81
|
-
@env_prefix
|
82
|
-
end
|
87
|
+
return @env_prefix if instance_variable_defined?(:@env_prefix)
|
83
88
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
def for(name)
|
91
|
-
new(name: name, load: false).load_from_sources
|
89
|
+
@env_prefix =
|
90
|
+
if superclass < Anyway::Config && superclass.explicit_config_name?
|
91
|
+
superclass.env_prefix
|
92
|
+
else
|
93
|
+
config_name.upcase
|
94
|
+
end
|
92
95
|
end
|
93
96
|
|
94
97
|
private
|
95
98
|
|
96
|
-
def
|
97
|
-
|
98
|
-
|
99
|
+
def build_config_name
|
100
|
+
unless name
|
101
|
+
raise "Please, specify config name explicitly for anonymous class " \
|
102
|
+
"via `config_name :my_config`"
|
103
|
+
end
|
99
104
|
|
100
|
-
|
101
|
-
|
105
|
+
# handle two cases:
|
106
|
+
# - SomeModule::Config => "some_module"
|
107
|
+
# - SomeConfig => "some"
|
108
|
+
unless name =~ /^(\w+)(\:\:)?Config$/
|
109
|
+
raise "Couldn't infer config name, please, specify it explicitly" \
|
110
|
+
"via `config_name :my_config`"
|
111
|
+
end
|
102
112
|
|
103
|
-
|
104
|
-
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
105
|
-
word.downcase!
|
106
|
-
word
|
113
|
+
Regexp.last_match[1].tap(&:downcase!)
|
107
114
|
end
|
108
115
|
end
|
109
116
|
|
110
117
|
attr_reader :config_name, :env_prefix
|
111
118
|
|
112
|
-
# Instantiate config
|
119
|
+
# Instantiate config instance.
|
113
120
|
#
|
114
121
|
# Example:
|
115
122
|
#
|
116
|
-
# my_config = Anyway::Config.new(
|
123
|
+
# my_config = Anyway::Config.new()
|
124
|
+
#
|
125
|
+
# # provide some values explicitly
|
126
|
+
# my_config = Anyway::Config.new({some: :value})
|
117
127
|
#
|
118
|
-
def initialize(
|
119
|
-
@config_name =
|
128
|
+
def initialize(overrides = {})
|
129
|
+
@config_name = self.class.config_name
|
120
130
|
|
121
131
|
raise ArgumentError, "Config name is missing" unless @config_name
|
122
132
|
|
123
|
-
@env_prefix = self.class.env_prefix
|
133
|
+
@env_prefix = self.class.env_prefix
|
124
134
|
|
125
|
-
|
135
|
+
load(overrides)
|
126
136
|
end
|
127
137
|
|
128
138
|
def reload(overrides = {})
|
@@ -139,43 +149,49 @@ module Anyway # :nodoc:
|
|
139
149
|
end
|
140
150
|
|
141
151
|
def load(overrides = {})
|
142
|
-
|
152
|
+
base_config = (self.class.defaults || {}).deep_dup
|
153
|
+
|
154
|
+
base_config.deep_merge!(
|
155
|
+
load_from_sources(
|
156
|
+
name: config_name,
|
157
|
+
env_prefix: env_prefix,
|
158
|
+
config_path: resolve_config_path(config_name, env_prefix)
|
159
|
+
)
|
160
|
+
)
|
161
|
+
|
162
|
+
base_config.merge!(overrides) unless overrides.nil?
|
143
163
|
|
144
|
-
|
145
|
-
config.each do |key, val|
|
164
|
+
base_config.each do |key, val|
|
146
165
|
set_value(key, val)
|
147
166
|
end
|
148
167
|
end
|
149
168
|
|
150
|
-
def load_from_sources(
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
169
|
+
def load_from_sources(**options)
|
170
|
+
base_config = {}
|
171
|
+
each_source(options) do |config|
|
172
|
+
base_config.deep_merge!(config) if config
|
173
|
+
end
|
174
|
+
base_config
|
156
175
|
end
|
157
176
|
|
158
|
-
def
|
159
|
-
|
160
|
-
|
177
|
+
def each_source(options)
|
178
|
+
yield load_from_file(options)
|
179
|
+
yield load_from_env(options)
|
161
180
|
end
|
162
181
|
|
163
|
-
def
|
164
|
-
|
165
|
-
config
|
166
|
-
end
|
182
|
+
def load_from_file(name:, env_prefix:, config_path:, **_options)
|
183
|
+
file_config = load_from_yml(config_path)
|
167
184
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
set_value(key, arg.is_a?(String) ? arg.serialize : arg)
|
172
|
-
end
|
173
|
-
self.class.option_parser_extension&.call(parser, self) || parser
|
185
|
+
if Anyway::Settings.use_local_files
|
186
|
+
local_config_path = config_path.sub(/\.yml/, ".local.yml")
|
187
|
+
file_config.deep_merge!(load_from_yml(local_config_path))
|
174
188
|
end
|
189
|
+
|
190
|
+
file_config
|
175
191
|
end
|
176
192
|
|
177
|
-
def
|
178
|
-
|
193
|
+
def load_from_env(name:, env_prefix:, **_options)
|
194
|
+
Anyway.env.fetch(env_prefix)
|
179
195
|
end
|
180
196
|
|
181
197
|
def to_h
|
@@ -184,26 +200,28 @@ module Anyway # :nodoc:
|
|
184
200
|
end.deep_dup.deep_freeze
|
185
201
|
end
|
186
202
|
|
203
|
+
def resolve_config_path(name, env_prefix)
|
204
|
+
Anyway.env.fetch(env_prefix).delete("conf") || default_config_path(name)
|
205
|
+
end
|
206
|
+
|
187
207
|
private
|
188
208
|
|
189
|
-
def
|
190
|
-
|
209
|
+
def set_value(key, val)
|
210
|
+
send("#{key}=", val) if respond_to?(key)
|
191
211
|
end
|
192
212
|
|
193
|
-
def
|
194
|
-
|
195
|
-
end
|
213
|
+
def load_from_yml(path)
|
214
|
+
return {} unless File.file?(path)
|
196
215
|
|
197
|
-
|
198
|
-
"./config/#{config_name}.yml"
|
216
|
+
parse_yml(path)
|
199
217
|
end
|
200
218
|
|
201
|
-
def
|
202
|
-
|
219
|
+
def default_config_path(name)
|
220
|
+
"./config/#{name}.yml"
|
203
221
|
end
|
204
222
|
|
205
223
|
def parse_yml(path)
|
206
|
-
require
|
224
|
+
require "yaml"
|
207
225
|
if defined?(ERB)
|
208
226
|
YAML.safe_load(ERB.new(File.read(path)).result, [], [], true)
|
209
227
|
else
|