anyway_config 2.0.0.pre2 → 2.0.0.rc1
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/CHANGELOG.md +350 -0
- data/LICENSE.txt +1 -1
- data/README.md +444 -119
- data/lib/.rbnext/2.7/anyway/auto_cast.rb +33 -0
- data/lib/.rbnext/2.7/anyway/config.rb +404 -0
- data/lib/.rbnext/2.7/anyway/option_parser_builder.rb +31 -0
- data/lib/.rbnext/2.7/anyway/tracing.rb +187 -0
- data/lib/anyway/auto_cast.rb +33 -0
- data/lib/anyway/config.rb +235 -58
- data/lib/anyway/dynamic_config.rb +1 -1
- data/lib/anyway/env.rb +29 -19
- data/lib/anyway/ext/hash.rb +14 -6
- data/lib/anyway/loaders.rb +79 -0
- data/lib/anyway/loaders/base.rb +23 -0
- data/lib/anyway/loaders/env.rb +16 -0
- data/lib/anyway/loaders/yaml.rb +46 -0
- data/lib/anyway/option_parser_builder.rb +6 -3
- data/lib/anyway/optparse_config.rb +10 -6
- data/lib/anyway/rails.rb +16 -0
- data/lib/anyway/rails/config.rb +2 -69
- data/lib/anyway/rails/loaders.rb +5 -0
- data/lib/anyway/rails/loaders/credentials.rb +64 -0
- data/lib/anyway/rails/loaders/secrets.rb +39 -0
- data/lib/anyway/rails/loaders/yaml.rb +19 -0
- data/lib/anyway/rails/settings.rb +58 -0
- data/lib/anyway/railtie.rb +14 -2
- data/lib/anyway/settings.rb +29 -0
- data/lib/anyway/tracing.rb +187 -0
- data/lib/anyway/version.rb +1 -1
- data/lib/anyway_config.rb +27 -21
- data/lib/generators/anyway/app_config/USAGE +9 -0
- data/lib/generators/anyway/app_config/app_config_generator.rb +17 -0
- data/lib/generators/anyway/config/USAGE +13 -0
- data/lib/generators/anyway/config/config_generator.rb +46 -0
- data/lib/generators/anyway/config/templates/config.rb.tt +9 -0
- data/lib/generators/anyway/config/templates/config.yml.tt +13 -0
- data/lib/generators/anyway/install/USAGE +4 -0
- data/lib/generators/anyway/install/install_generator.rb +43 -0
- data/lib/generators/anyway/install/templates/application_config.rb.tt +17 -0
- metadata +75 -10
- data/lib/anyway/ext/string_serialize.rb +0 -38
- data/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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c4661661a2d8cbce7e35a4eef45520a290855af228b1d20d69367708b11be3f
|
4
|
+
data.tar.gz: 97f07abb3e194f490069d6dc1ef7076a88f3775f5b06a3cc99d15314da845c54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9897240812d5ae7522b99c0d4ac2ec1c3e2ec5759ef481ff3db6d9fbeb1c46312a895ed64fd94fc6b3c1a416a3ccee9325458c1aeacd0ff7dbc9a10593fabf89
|
7
|
+
data.tar.gz: c590c11acb69e99ff0ada09fa7ebb4ae44f777da626f2f9dd053935d9d201fa6b3d6296642271e7d56260b9258d0baca65ade78fd10c9397e5205a03d8551b1a
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,350 @@
|
|
1
|
+
# Change log
|
2
|
+
|
3
|
+
## master
|
4
|
+
|
5
|
+
## 2.0.0.rc1 (2020-03-31)
|
6
|
+
|
7
|
+
- Add predicate methods for attributes with boolean defaults. ([@palkan][])
|
8
|
+
|
9
|
+
For example:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class MyConfig < Anyway::Config
|
13
|
+
attr_config :key, :secret, debug: false
|
14
|
+
end
|
15
|
+
|
16
|
+
MyConfig.new.debug? #=> false
|
17
|
+
MyConfig.new(debug: true).debug? #=> true
|
18
|
+
```
|
19
|
+
|
20
|
+
- Add `Config#deconstruct_keys`. ([@palkan][])
|
21
|
+
|
22
|
+
Now you can use configs in pattern matching:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
case AWSConfig.new
|
26
|
+
in bucket:, region: "eu-west-1"
|
27
|
+
setup_eu_storage(bucket)
|
28
|
+
in bucket:, region: "us-east-1"
|
29
|
+
setup_us_storage(bucket)
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
- Add pretty_print support. ([@palkan][])
|
34
|
+
|
35
|
+
Whenever you use `pp`, the output would contain pretty formatted config information
|
36
|
+
including the sources.
|
37
|
+
|
38
|
+
Example:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
pp CoolConfig.new
|
42
|
+
|
43
|
+
# #<CoolConfig
|
44
|
+
# config_name="cool"
|
45
|
+
# env_prefix="COOL"
|
46
|
+
# values:
|
47
|
+
# port => 3334 (type=load),
|
48
|
+
# host => "test.host" (type=yml path=./config/cool.yml),
|
49
|
+
# user =>
|
50
|
+
# name => "john" (type=env key=COOL_USER__NAME),
|
51
|
+
# password => "root" (type=yml path=./config/cool.yml)>
|
52
|
+
```
|
53
|
+
|
54
|
+
- Add source tracing support. ([@palkan][])
|
55
|
+
|
56
|
+
You can get the information on where a particular parameter value came from
|
57
|
+
(which loader) through via `#to_source_trace` method:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
conf = MyConfig.new
|
61
|
+
conf.to_source_trace
|
62
|
+
# {
|
63
|
+
# "host" => {value: "test.host", source: {type: :user, called_from: "/rails/root/config/application.rb:21"}},
|
64
|
+
# "user" => {
|
65
|
+
# "name" => {value: "john", source: {type: :env, key: "COOL_USER__NAME"}},
|
66
|
+
# "password" => {value: "root", source: {type: :yml, path: "config/cool.yml"}}
|
67
|
+
# },
|
68
|
+
# "port" => {value: 9292, source: {type: :defaults}}
|
69
|
+
# }
|
70
|
+
```
|
71
|
+
|
72
|
+
- Change the way Rails configs autoloading works. ([@palkan][])
|
73
|
+
|
74
|
+
In Rails 6, autoloading before initialization is [deprecated](https://github.com/rails/rails/commit/3e66ba91d511158e22f90ff96b594d61f40eda01). We can still
|
75
|
+
make it work by using our own autoloading mechanism (custom Zeitwerk loader).
|
76
|
+
|
77
|
+
This forces us to use a custom directory (not `app/`) for configs required at the boot time.
|
78
|
+
By default, we put _static_ configs into `config/configs` but you can still use `app/configs` for
|
79
|
+
_dynamic_ (runtime) configs.
|
80
|
+
|
81
|
+
**NOTE:** if you used `app/configs` with 2.0.0.preX and relied on configs during initialization,
|
82
|
+
you can set static configs path to `app/configs`:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
config.anyway_config.autoload_static_config_path = "app/configs"
|
86
|
+
```
|
87
|
+
|
88
|
+
You can do this by running the generator:
|
89
|
+
|
90
|
+
```sh
|
91
|
+
rails g anyway:install --configs-path=app/configs
|
92
|
+
```
|
93
|
+
|
94
|
+
- Add Rails generators. ([@palkan][])
|
95
|
+
|
96
|
+
You can create config classes with the predefined attributes like this:
|
97
|
+
|
98
|
+
```sh
|
99
|
+
rails generate config aws access_key_id secret_access_key region
|
100
|
+
```
|
101
|
+
|
102
|
+
- **BREAKING** The accessors generated by `attr_config` are not longer `attr_accessor`-s. ([@palkan][])
|
103
|
+
|
104
|
+
You cannot rely on instance variables anymore. Instead, you can use `super` when overriding accessors or
|
105
|
+
`values[name]`:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
attr_config :host, :port, :url, :meta
|
109
|
+
|
110
|
+
# override writer to handle type coercion
|
111
|
+
def meta=(val)
|
112
|
+
super JSON.parse(val)
|
113
|
+
end
|
114
|
+
|
115
|
+
# or override reader to handle missing values
|
116
|
+
def url
|
117
|
+
values[:url] ||= "#{host}:#{port}"
|
118
|
+
end
|
119
|
+
|
120
|
+
# in <2.1 it's still possible to read instance variables,
|
121
|
+
# i.e. the following would also work
|
122
|
+
def url
|
123
|
+
@url ||= "#{host}:#{port}"
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
**NOTE**: we still set instance variables in writers (for backward compatibility), but that would
|
128
|
+
be removed in 2.1.
|
129
|
+
|
130
|
+
- Add `Config#dig` method. ([@palkan][])
|
131
|
+
|
132
|
+
- Add ability to specify types for OptionParser options. ([@palkan][])
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
describe_options(
|
136
|
+
concurrency: {
|
137
|
+
desc: "number of threads to use",
|
138
|
+
type: String
|
139
|
+
}
|
140
|
+
)
|
141
|
+
```
|
142
|
+
|
143
|
+
- Add param presence validation. ([@palkan][])
|
144
|
+
|
145
|
+
You can specify some params as required, and the validation
|
146
|
+
error would be raised if they're missing or empty (only for strings):
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
class MyConfig < Anyway::Config
|
150
|
+
attr_config :api_key, :api_secret, :debug
|
151
|
+
|
152
|
+
required :api_key, :api_secret
|
153
|
+
end
|
154
|
+
|
155
|
+
MyConfig.new(api_secret: "") #=> raises Anyway::Config::ValidationError
|
156
|
+
```
|
157
|
+
|
158
|
+
You can change the validation behaviour by overriding the `#validate!` method in your config class.
|
159
|
+
|
160
|
+
- Validate config attribute names. ([@palkan][])
|
161
|
+
|
162
|
+
Do not allow using reserved names (`Anyway::Config` method names).
|
163
|
+
Allow only alphanumeric names (matching `/^[a-z_]([\w]+)?$/`).
|
164
|
+
|
165
|
+
- Add Loaders API. ([@palkan][])
|
166
|
+
|
167
|
+
All config sources have standardized via _loaders_ API. It's possible to define
|
168
|
+
custom loaders or change the sources order.
|
169
|
+
|
170
|
+
## 2.0.0.pre2 (2019-04-26)
|
171
|
+
|
172
|
+
- Fix bug with loading from credentials when local credentials are missing. ([@palkan][])
|
173
|
+
|
174
|
+
## 2.0.0.pre (2019-04-26)
|
175
|
+
|
176
|
+
- **BREAKING** Changed the way of providing explicit values. ([@palkan][])
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
# BEFORE
|
180
|
+
Config.new(overrides: data)
|
181
|
+
|
182
|
+
# AFTER
|
183
|
+
Config.new(data)
|
184
|
+
```
|
185
|
+
|
186
|
+
- Add Railtie. ([@palkan][])
|
187
|
+
|
188
|
+
`Anyway::Railtie` provides `Anyway::Settings` access via `Rails.applicaiton.configuration.anyway_config`.
|
189
|
+
|
190
|
+
It also adds `app/configs` path to autoload paths (low-level, `ActiveSupport::Dependencies`) to
|
191
|
+
make it possible to use configs in the app configuration files.
|
192
|
+
|
193
|
+
- Add test helpers. ([@palkan][])
|
194
|
+
|
195
|
+
Added `with_env` helper to test code in the context of the specified
|
196
|
+
environment variables.
|
197
|
+
|
198
|
+
Included automatically in RSpec for examples with the `type: :config` meta
|
199
|
+
or with the `spec/configs` path.
|
200
|
+
|
201
|
+
- Add support for _local_ files. ([@palkan][])
|
202
|
+
|
203
|
+
Now users can store their personal configurations in _local_ files:
|
204
|
+
- `<config_name>.local.yml`
|
205
|
+
- `config/credentials/local.yml.enc` (for Rails 6).
|
206
|
+
|
207
|
+
Local configs are meant for using in development and only loaded if
|
208
|
+
`Anyway::Settings.use_local_files` is `true` (which is true by default if
|
209
|
+
`RACK_ENV` or `RAILS_ENV` env variable is equal to `"development"`).
|
210
|
+
|
211
|
+
- Add Rails credentials support. ([@palkan][])
|
212
|
+
|
213
|
+
The data from credentials is loaded after the data from YAML config and secrets,
|
214
|
+
but before environmental variables (i.e. env variables are _stronger_)
|
215
|
+
|
216
|
+
- Update config name inference logic. ([@palkan][])
|
217
|
+
|
218
|
+
Config name is automatically inferred only if:
|
219
|
+
- the class name has a form of `<Module>::Config` (`SomeModule::Config => "some_module"`)
|
220
|
+
- the class name has a form of `<Something>Config` (`SomeConfig => "some"`)
|
221
|
+
|
222
|
+
- Fix config classes inheritance. ([@palkan][])
|
223
|
+
|
224
|
+
Previously, inheritance didn't work due to the lack of proper handling of class-level
|
225
|
+
configuration (naming, option parses settings, defaults).
|
226
|
+
|
227
|
+
Now it's possible to extend config classes without breaking the original classes functionality.
|
228
|
+
|
229
|
+
Noticeable features:
|
230
|
+
- if `config_name` is explicitly defined on class, it's inherited by subclasses:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
class MyAppBaseConfig < Anyway::Config
|
234
|
+
config_name :my_app
|
235
|
+
end
|
236
|
+
|
237
|
+
class MyServiceConfig < MyAppBaseConfig
|
238
|
+
end
|
239
|
+
|
240
|
+
MyServiceConfig.config_name #=> "my_app"
|
241
|
+
```
|
242
|
+
|
243
|
+
- defaults are merged leaving the parent class defaults unchanged
|
244
|
+
- option parse extension are not overriden, but added to the parent class extensions
|
245
|
+
|
246
|
+
- **Require Ruby >= 2.5.0.**
|
247
|
+
|
248
|
+
## 1.4.3 (2019-02-04)
|
249
|
+
|
250
|
+
- Add a temporary fix for JRuby regression [#5550](https://github.com/jruby/jruby/issues/5550). ([@palkan][])
|
251
|
+
|
252
|
+
## 1.4.2 (2018-01-05)
|
253
|
+
|
254
|
+
- Fix: detect Rails by presence of `Rails::VERSION` (instead of just `Rails`). ([@palkan][])
|
255
|
+
|
256
|
+
## 1.4.1 (2018-10-30)
|
257
|
+
|
258
|
+
- Add `.flag_options` to mark some params as flags (value-less) for OptionParse. ([@palkan][])
|
259
|
+
|
260
|
+
## 1.4.0 (2018-10-29)
|
261
|
+
|
262
|
+
- Add OptionParse integration ([@jastkand][])
|
263
|
+
|
264
|
+
See more [PR#18](https://github.com/palkan/anyway_config/pull/18).
|
265
|
+
|
266
|
+
- Use underscored config name as an env prefix. ([@palkan][])
|
267
|
+
|
268
|
+
For a config class:
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
class MyApp < Anyway::Config
|
272
|
+
end
|
273
|
+
```
|
274
|
+
|
275
|
+
Before this change we use `MYAPP_` prefix, now it's `MY_APP_`.
|
276
|
+
|
277
|
+
You can specify the prefix explicitly:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
class MyApp < Anyway::Config
|
281
|
+
env_prefix "MYAPP_"
|
282
|
+
end
|
283
|
+
```
|
284
|
+
|
285
|
+
## 1.3.0 (2018-06-15)
|
286
|
+
|
287
|
+
- Ruby 2.2 is no longer supported.
|
288
|
+
|
289
|
+
- `Anyway::Config.env_prefix` method is introduced. ([@charlie-wasp][])
|
290
|
+
|
291
|
+
## 1.2.0 (2018-02-19)
|
292
|
+
|
293
|
+
Now works on JRuby 9.1+.
|
294
|
+
|
295
|
+
## 1.1.3 (2017-12-20)
|
296
|
+
|
297
|
+
- Allow to pass raw hash with explicit values to `Config.new`. ([@dsalahutdinov][])
|
298
|
+
|
299
|
+
Example:
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
Sniffer::Config.new(
|
303
|
+
overrides: {
|
304
|
+
enabled: true,
|
305
|
+
storage: {capacity: 500}
|
306
|
+
}
|
307
|
+
)
|
308
|
+
```
|
309
|
+
|
310
|
+
See more [PR#10](https://github.com/palkan/anyway_config/pull/10).
|
311
|
+
|
312
|
+
## 1.1.2 (2017-11-19)
|
313
|
+
|
314
|
+
- Enable aliases for YAML. ([@onemanstartup][])
|
315
|
+
|
316
|
+
## 1.1.1 (2017-10-21)
|
317
|
+
|
318
|
+
- Return deep duplicate of a Hash in `Env#fetch`. ([@palkan][])
|
319
|
+
|
320
|
+
## 1.1.0 (2017-10-06)
|
321
|
+
|
322
|
+
- Add `#to_h` method. ([@palkan][])
|
323
|
+
|
324
|
+
See [#4](https://github.com/palkan/anyway_config/issues/4).
|
325
|
+
|
326
|
+
- Make it possible to extend configuration parameters. ([@palkan][])
|
327
|
+
|
328
|
+
## 1.0.0 (2017-06-20)
|
329
|
+
|
330
|
+
- Lazy load and parse ENV configuration. ([@palkan][])
|
331
|
+
|
332
|
+
- Add support for ERB in YML configuration. ([@palkan][])
|
333
|
+
|
334
|
+
## 0.5.0 (2017-01-20)
|
335
|
+
|
336
|
+
- Drop `active_support` dependency. ([@palkan][])
|
337
|
+
|
338
|
+
Use custom refinements instead of requiring `active_support`.
|
339
|
+
|
340
|
+
No we're dependency-free!
|
341
|
+
|
342
|
+
## 0.1.0 (2015-01-20)
|
343
|
+
|
344
|
+
Initial version.
|
345
|
+
|
346
|
+
[@palkan]: https://github.com/palkan
|
347
|
+
[@onemanstartup]: https://github.com/onemanstartup
|
348
|
+
[@dsalahutdinov]: https://github.com/dsalahutdinov
|
349
|
+
[@charlie-wasp]: https://github.com/charlie-wasp
|
350
|
+
[@jastkand]: https://github.com/jastkand
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -4,23 +4,70 @@
|
|
4
4
|
|
5
5
|
# Anyway Config
|
6
6
|
|
7
|
-
|
7
|
+
> One configuration to rule all data sources
|
8
|
+
|
9
|
+
Anyway Config is a configuration library for Ruby gems and applications.
|
10
|
+
|
11
|
+
As a library author, you can benefit from using Anyway Config by providing a better UX for your end-users:
|
12
|
+
|
13
|
+
- **Zero-code configuration** — no more boilerplate initializers.
|
14
|
+
- **Per-environment and local** settings support out-of-the-box.
|
15
|
+
|
16
|
+
For application developers, Anyway Config could be useful to:
|
17
|
+
|
18
|
+
- **Keep configuration organized** and use _named configs_ instead of bloated `.env`/`settings.yml`/whatever.
|
19
|
+
- **Free code of ENV/credentials/secrets dependency** and use configuration classes instead—your code should not rely on configuration data sources.
|
20
|
+
|
21
|
+
**NOTE:** this readme shows documentation for the upcoming 2.0 version (`2.0.0.rc1` is available on RubyGems).
|
8
22
|
For version 1.x see [1-4-stable branch](https://github.com/palkan/anyway_config/tree/1-4-stable).
|
9
23
|
|
10
|
-
|
24
|
+
## Table of contents
|
25
|
+
|
26
|
+
- [Main concepts](#main-concepts)
|
27
|
+
- [Installation](#installation)
|
28
|
+
- [Usage](#usage)
|
29
|
+
- [Configuration classes](#configuration-classes)
|
30
|
+
- [Dynamic configuration](#dynamic-configuration)
|
31
|
+
- [Validation & Callbacks](#validation-and-callbacks)
|
32
|
+
- [Using with Rails applications](#using-with-rails)
|
33
|
+
- [Data population](#data-population)
|
34
|
+
- [Organizing configs](#organizing-configs)
|
35
|
+
- [Generators](#generators)
|
36
|
+
- [Using with Ruby applications](#using-with-ruby)
|
37
|
+
- [Environment variables](#environment-variables)
|
38
|
+
- [Local configuration](#local-files)
|
39
|
+
- [Data loaders](#data-loaders)
|
40
|
+
- [Source tracing](#tracing)
|
41
|
+
- [Pattern matching](#pattern-matching)
|
42
|
+
- [Test helpers](#test-helpers)
|
43
|
+
- [OptionParser integration](#optionparser-integration)
|
44
|
+
|
45
|
+
## Main concepts
|
46
|
+
|
47
|
+
Anyway Config abstractize the configuration layer by introducing **configuration classes** which describe available parameters and their defaults. For [example](https://github.com/palkan/influxer/blob/master/lib/influxer/config.rb):
|
11
48
|
|
12
|
-
|
49
|
+
```ruby
|
50
|
+
module Influxer
|
51
|
+
class Config < Anyway::Config
|
52
|
+
attr_config(
|
53
|
+
host: "localhost",
|
54
|
+
username: "root",
|
55
|
+
password: "root"
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
13
60
|
|
14
|
-
|
61
|
+
Using Ruby classes to represent configuration allows you to add helper methods and computed parameters easily, makes the configuration **testable**.
|
15
62
|
|
16
|
-
- [
|
63
|
+
The `anyway_config` gem takes care of loading parameters from **different sources** (YAML, credentials/secrets, environment variables, etc.). Internally, we use a _pipeline pattern_ and provide the [Loaders API](#data-loaders) to manage and [extend](#custom-loaders) its functionality.
|
17
64
|
|
18
|
-
|
65
|
+
Check out the libraries using Anyway Config for more examples:
|
19
66
|
|
67
|
+
- [Influxer](https://github.com/palkan/influxer)
|
68
|
+
- [AnyCable](https://github.com/anycable/anycable)
|
20
69
|
- [Sniffer](https://github.com/aderyabin/sniffer)
|
21
|
-
|
22
70
|
- [Blood Contracts](https://github.com/sclinede/blood_contracts)
|
23
|
-
|
24
71
|
- [and others](https://github.com/palkan/anyway_config/network/dependents).
|
25
72
|
|
26
73
|
## Installation
|
@@ -31,7 +78,7 @@ Adding to a gem:
|
|
31
78
|
# my-cool-gem.gemspec
|
32
79
|
Gem::Specification.new do |spec|
|
33
80
|
# ...
|
34
|
-
spec.add_dependency "anyway_config", "2.0.0.
|
81
|
+
spec.add_dependency "anyway_config", "2.0.0.rc1"
|
35
82
|
# ...
|
36
83
|
end
|
37
84
|
```
|
@@ -40,23 +87,25 @@ Or adding to your project:
|
|
40
87
|
|
41
88
|
```ruby
|
42
89
|
# Gemfile
|
43
|
-
gem "anyway_config", "2.0.0.
|
90
|
+
gem "anyway_config", "2.0.0.rc1"
|
44
91
|
```
|
45
92
|
|
46
|
-
|
93
|
+
### Supported Ruby versions
|
47
94
|
|
48
95
|
- Ruby (MRI) >= 2.5.0
|
49
|
-
|
50
|
-
- JRuby >= 9.2.7
|
96
|
+
- JRuby >= 9.2.9
|
51
97
|
|
52
98
|
## Usage
|
53
99
|
|
54
|
-
###
|
100
|
+
### Configuration classes
|
101
|
+
|
102
|
+
Using configuration classes allows you to make configuration data a bit more than a bag of values:
|
103
|
+
you can define a schema for your configuration, provide defaults, add validations and additional helper methods.
|
55
104
|
|
56
|
-
|
105
|
+
Anyway Config provides a base class to inherit from with a few DSL methods:
|
57
106
|
|
58
107
|
```ruby
|
59
|
-
require "
|
108
|
+
require "anyway_config"
|
60
109
|
|
61
110
|
module MyCoolGem
|
62
111
|
class Config < Anyway::Config
|
@@ -65,22 +114,66 @@ module MyCoolGem
|
|
65
114
|
end
|
66
115
|
```
|
67
116
|
|
68
|
-
`attr_config` creates accessors and default values. If you don't need default values
|
117
|
+
Here `attr_config` creates accessors and populates the default values. If you don't need default values you can write:
|
69
118
|
|
70
119
|
```ruby
|
71
120
|
attr_config :user, :password, host: "localhost", options: {}
|
72
121
|
```
|
73
122
|
|
74
|
-
|
123
|
+
**NOTE**: it's safe to use non-primitive default values (like Hashes or Arrays) without worrying about their mutation: the values would be deeply duplicated for each config instance.
|
124
|
+
|
125
|
+
Then, create an instance of the config class and use it:
|
75
126
|
|
76
127
|
```ruby
|
77
|
-
|
78
|
-
|
79
|
-
|
128
|
+
MyCoolGem::Config.new.user #=> "root"
|
129
|
+
```
|
130
|
+
|
131
|
+
**Bonus:**: if you define attributes with boolean default values (`false` or `true`), Anyway Config would automatically add a corresponding predicate method. For example:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
attr_config :user, :password, debug: false
|
135
|
+
|
136
|
+
MyCoolGem::Config.new.debug? #=> false
|
137
|
+
MyCoolGem::Config.new(debug: true).debug? #=> true
|
138
|
+
```
|
139
|
+
|
140
|
+
**NOTE**: since v2.0 accessors created by `attr_config` are not `attr_accessor`, i.e. they do not populate instance variables. If you used instance variables before to override readers, you must switch to using `super` or `values` store:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
class MyConfig < Anyway::Config
|
144
|
+
attr_config :host, :port, :url, :meta
|
145
|
+
|
146
|
+
# override writer to handle type coercion
|
147
|
+
def meta=(val)
|
148
|
+
super JSON.parse(val)
|
149
|
+
end
|
150
|
+
|
151
|
+
# or override reader to handle missing values
|
152
|
+
def url
|
153
|
+
super || (self.url = "#{host}:#{port}")
|
154
|
+
end
|
155
|
+
|
156
|
+
# untill v2.1, it will still be possible to read instance variables,
|
157
|
+
# i.e. the following code would also work
|
158
|
+
def url
|
159
|
+
@url ||= "#{host}:#{port}"
|
80
160
|
end
|
81
161
|
end
|
162
|
+
```
|
163
|
+
|
164
|
+
We recommend to add a feature check and support both v1.x and v2.0 in gems for the time being:
|
82
165
|
|
83
|
-
|
166
|
+
```ruby
|
167
|
+
# Check for the class method added in 2.0, e.g., `.on_load`
|
168
|
+
if respond_to?(:on_load)
|
169
|
+
def url
|
170
|
+
super || (self.url = "#{host}:#{port}")
|
171
|
+
end
|
172
|
+
else
|
173
|
+
def url
|
174
|
+
@url ||= "#{host}:#{port}"
|
175
|
+
end
|
176
|
+
end
|
84
177
|
```
|
85
178
|
|
86
179
|
#### Config name
|
@@ -92,9 +185,9 @@ By default, Anyway Config uses the config class name to infer the config name us
|
|
92
185
|
- if the class name has a form of `<Module>::Config` then use the module name (`SomeModule::Config => "somemodule"`)
|
93
186
|
- if the class name has a form of `<Something>Config` then use the class name prefix (`SomeConfig => "some"`)
|
94
187
|
|
95
|
-
**NOTE:** in both cases the config name is a **downcased** module/class prefix, not underscored.
|
188
|
+
**NOTE:** in both cases, the config name is a **downcased** module/class prefix, not underscored.
|
96
189
|
|
97
|
-
You can also specify the config name explicitly (it's required in cases when
|
190
|
+
You can also specify the config name explicitly (it's required in cases when your class name doesn't match any of the patterns above):
|
98
191
|
|
99
192
|
```ruby
|
100
193
|
module MyCoolGem
|
@@ -122,7 +215,7 @@ module MyCoolGem
|
|
122
215
|
end
|
123
216
|
```
|
124
217
|
|
125
|
-
####
|
218
|
+
#### Explicit values
|
126
219
|
|
127
220
|
Sometimes it's useful to set some parameters explicitly during config initialization.
|
128
221
|
You can do that by passing a Hash into `.new` method:
|
@@ -133,17 +226,25 @@ config = MyCoolGem::Config.new(
|
|
133
226
|
password: "rubyisnotdead"
|
134
227
|
)
|
135
228
|
|
136
|
-
# The value would not be
|
229
|
+
# The value would not be overridden from other sources (such as YML file, env)
|
137
230
|
config.user == "john"
|
138
231
|
```
|
139
232
|
|
233
|
+
#### Reload configuration
|
234
|
+
|
235
|
+
There are `#clear` and `#reload` methods that do exactly what they state.
|
236
|
+
|
237
|
+
**NOTE**: `#reload` also accepts an optional Hash for [explicit values](#explicit-values).
|
238
|
+
|
140
239
|
### Dynamic configuration
|
141
240
|
|
142
|
-
You can also
|
241
|
+
You can also fetch configuration without pre-defined schema:
|
143
242
|
|
144
243
|
```ruby
|
145
|
-
# load data from config/my_app.yml,
|
146
|
-
#
|
244
|
+
# load data from config/my_app.yml,
|
245
|
+
# credentials.my_app, secrets.my_app (if using Rails), ENV["MY_APP_*"]
|
246
|
+
#
|
247
|
+
# Given MY_APP_VALUE=42
|
147
248
|
config = Anyway::Config.for(:my_app)
|
148
249
|
config["value"] #=> 42
|
149
250
|
|
@@ -151,11 +252,75 @@ config["value"] #=> 42
|
|
151
252
|
config = Anyway::Config.for(:my_app, config_path: "my_config.yml", env_prefix: "MYAPP")
|
152
253
|
```
|
153
254
|
|
154
|
-
|
255
|
+
This feature is similar to `Rails.application.config_for` but more powerful:
|
256
|
+
|
257
|
+
| Feature | Rails | Anyway Config |
|
258
|
+
| ------------- |-------------:| -----:|
|
259
|
+
| Load data from `config/app.yml` | ✅ | ✅ |
|
260
|
+
| Load data from `secrets` | ❌ | ✅ |
|
261
|
+
| Load data from `credentials` | ❌ | ✅ |
|
262
|
+
| Load data from environment | ❌ | ✅ |
|
263
|
+
| Load data from [custom sources](#data-loaders) | ❌ | ✅ |
|
264
|
+
| Local config files | ❌ | ✅ |
|
265
|
+
| [Source tracing](#tracing) | ❌ | ✅ |
|
266
|
+
| Return Hash with indifferent access | ❌ | ✅ |
|
267
|
+
| Support ERB\* within `config/app.yml` | ✅ | ✅ |
|
268
|
+
| Raise if file doesn't exist | ✅ | ❌ |
|
269
|
+
| Works without Rails | 😀 | ✅ |
|
270
|
+
|
271
|
+
\* Make sure that ERB is loaded
|
272
|
+
|
273
|
+
### Validation and callbacks
|
274
|
+
|
275
|
+
Anyway Config provides basic ways of ensuring that the configuration is valid.
|
276
|
+
|
277
|
+
There is a built-in `required` class method to define the list of parameters that must be present in the
|
278
|
+
configuration after loading (where present means non-`nil` and non-empty for strings):
|
279
|
+
|
280
|
+
```ruby
|
281
|
+
class MyConfig < Anyway::Config
|
282
|
+
attr_config :api_key, :api_secret, :debug
|
283
|
+
|
284
|
+
required :api_key, :api_secret
|
285
|
+
end
|
286
|
+
|
287
|
+
MyConfig.new(api_secret: "") #=> raises Anyway::Config::ValidationError
|
288
|
+
```
|
289
|
+
|
290
|
+
If you need more complex validation or need to manipulate with config state right after it has been loaded, you can use _on load callbacks_ and `#raise_validation_error` method:
|
291
|
+
|
292
|
+
```ruby
|
293
|
+
class MyConfig < Anyway::Config
|
294
|
+
attr_config :api_key, :api_secret, :mode
|
295
|
+
|
296
|
+
# on_load macro accepts symbol method names
|
297
|
+
on_load :ensure_mode_is_valid
|
298
|
+
|
299
|
+
# or block
|
300
|
+
on_load do
|
301
|
+
# the block is evaluated in the context of the config
|
302
|
+
raise_validation_error("API key and/or secret could be blank") if
|
303
|
+
api_key.blank? || api_secret.blank?
|
304
|
+
end
|
305
|
+
|
306
|
+
def ensure_mode_is_valid
|
307
|
+
unless %w[production test].include?(mode)
|
308
|
+
raise_validation_error "Unknown mode; #{mode}"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
```
|
313
|
+
|
314
|
+
## Using with Rails
|
155
315
|
|
156
316
|
**NOTE:** version 2.x supports Rails >= 5.0; for Rails 4.x use version 1.x of the gem.
|
157
317
|
|
158
|
-
|
318
|
+
We recommend going through [Data population](#data-population) and [Organizing configs](#organizing-configs) sections first,
|
319
|
+
and then use [Rails generators](#generators) to make your application Anyway Config-ready.
|
320
|
+
|
321
|
+
### Data population
|
322
|
+
|
323
|
+
Your config is filled up with values from the following sources (ordered by priority from low to high):
|
159
324
|
|
160
325
|
- `RAILS_ROOT/config/my_cool_gem.yml` (for the current `RAILS_ENV`, supports `ERB`):
|
161
326
|
|
@@ -180,7 +345,7 @@ development:
|
|
180
345
|
port: 4444
|
181
346
|
```
|
182
347
|
|
183
|
-
- `Rails.application.credentials` (if supported):
|
348
|
+
- `Rails.application.credentials.my_cool_gem` (if supported):
|
184
349
|
|
185
350
|
```yml
|
186
351
|
my_cool_gem:
|
@@ -191,14 +356,18 @@ my_cool_gem:
|
|
191
356
|
|
192
357
|
- `ENV['MYCOOLGEM_*']`.
|
193
358
|
|
194
|
-
|
359
|
+
See [environment variables](#environment-variables).
|
360
|
+
|
361
|
+
### Organizing configs
|
362
|
+
|
363
|
+
You can store application-level config classes in `app/configs` folder just like any other Rails entities.
|
195
364
|
|
196
|
-
|
365
|
+
However, in that case you won't be able to use them during the application initialization (i.e., in `config/**/*.rb` files).
|
197
366
|
|
198
|
-
|
199
|
-
|
367
|
+
Since that's a pretty common scenario, we provide a way to do that via a custom autoloader for `config/configs` folder.
|
368
|
+
That means, that you can put your configuration classes into `config/configs` folder, use them anywhere in your code without explicitly requiring them.
|
200
369
|
|
201
|
-
Consider an example: setting the Action Mailer
|
370
|
+
Consider an example: setting the Action Mailer hostname for Heroku review apps.
|
202
371
|
|
203
372
|
We have the following config to fetch the Heroku provided [metadata](https://devcenter.heroku.com/articles/dyno-metadata):
|
204
373
|
|
@@ -221,32 +390,108 @@ Then in `config/application.rb` you can do the following:
|
|
221
390
|
config.action_mailer.default_url_options = {host: HerokuConfig.new.hostname}
|
222
391
|
```
|
223
392
|
|
224
|
-
|
393
|
+
You can configure the configs folder path:
|
394
|
+
|
395
|
+
```ruby
|
396
|
+
# The path must be relative to Rails root
|
397
|
+
config.anyway_config.autoload_static_config_path = "path/to/configs"
|
398
|
+
```
|
399
|
+
|
400
|
+
**NOTE:** Configs loaded from the `autoload_static_config_path` are **not reloaded in development**. We call them _static_. So, it makes sense to keep only configs necessary for initialization in this folder. Other configs, _dynamic_, could be stored in `app/configs`.
|
401
|
+
Or you can store everything in `app/configs` by setting `config.anyway_config.autoload_static_config_path = "app/configs"`.
|
402
|
+
|
403
|
+
### Generators
|
404
|
+
|
405
|
+
Anyway Config provides Rails generators to create new config classes:
|
406
|
+
|
407
|
+
- `rails g anyway:install`—creates an `ApplicationConfig` class (the base class for all config classes) and updates `.gitignore`
|
408
|
+
|
409
|
+
You can specify the static configs path via the `--configs-path` option:
|
410
|
+
|
411
|
+
```sh
|
412
|
+
rails g anyway:install --configs-path=config/settings
|
413
|
+
|
414
|
+
# or to keep everything in app/configs
|
415
|
+
rails g anyway:install --configs-path=app/configs
|
416
|
+
```
|
417
|
+
|
418
|
+
- `rails g anyway:config <name> param1 param2 ...`—creates a named configuration class and optionally the corresponding YAML file; creates `application_config.rb` is missing.
|
419
|
+
|
420
|
+
The generator command for the Heroku example above would be:
|
421
|
+
|
422
|
+
```sh
|
423
|
+
$ rails g anyway:config heroku app_id app_name dyno_id release_version slug_commit
|
424
|
+
|
425
|
+
generate anyway:install
|
426
|
+
rails generate anyway:install
|
427
|
+
create config/configs/application_config.rb
|
428
|
+
append .gitignore
|
429
|
+
create config/configs/heroku_config.rb
|
430
|
+
Would you like to generate a heroku.yml file? (Y/n) n
|
431
|
+
```
|
432
|
+
|
433
|
+
You can also specify the `--app` option to put the newly created class into `app/configs` folder.
|
434
|
+
Alternatively, you can call `rails g anyway:app_config name param1 param2 ...`.
|
225
435
|
|
226
|
-
|
227
|
-
at `./config/<config-name>.yml`.
|
436
|
+
## Using with Ruby
|
228
437
|
|
229
|
-
|
438
|
+
The default data loading mechanism for non-Rails applications is the following (ordered by priority from low to high):
|
230
439
|
|
231
|
-
|
440
|
+
- `./config/<config-name>.yml` (`ERB` is supported if `erb` is loaded)
|
441
|
+
|
442
|
+
In pure Ruby apps, we do not know about _environments_ (`test`, `development`, `production`, etc.); thus, we assume that the YAML contains values for a single environment:
|
232
443
|
|
233
444
|
```yml
|
234
445
|
host: localhost
|
235
446
|
port: 3000
|
236
447
|
```
|
237
448
|
|
238
|
-
|
449
|
+
**NOTE:** you can override the default YML lookup path by setting `MYCOOLGEM_CONF` env variable.
|
450
|
+
|
451
|
+
- `ENV['MYCOOLGEM_*']`.
|
452
|
+
|
453
|
+
See [environment variables](#environment-variables).
|
454
|
+
|
455
|
+
## Environment variables
|
456
|
+
|
457
|
+
Environmental variables for your config should start with your config name, upper-cased.
|
458
|
+
|
459
|
+
For example, if your config name is "mycoolgem", then the env var "MYCOOLGEM_PASSWORD" is used as `config.password`.
|
460
|
+
|
461
|
+
Environment variables are automatically type cast:
|
462
|
+
|
463
|
+
- `"True"`, `"t"` and `"yes"` to `true`;
|
464
|
+
- `"False"`, `"f"` and `"no"` to `false`;
|
465
|
+
- `"nil"` and `"null"` to `nil` (do you really need it?);
|
466
|
+
- `"123"` to 123 and `"3.14"` to 3.14.
|
467
|
+
|
468
|
+
*Anyway Config* supports nested (_hashed_) env variables—just separate keys with double-underscore.
|
239
469
|
|
240
|
-
|
470
|
+
For example, "MYCOOLGEM_OPTIONS__VERBOSE" is parsed as `config.options["verbose"]`.
|
241
471
|
|
242
|
-
|
472
|
+
Array values are also supported:
|
473
|
+
|
474
|
+
```ruby
|
475
|
+
# Suppose ENV["MYCOOLGEM_IDS"] = '1,2,3'
|
476
|
+
config.ids #=> [1,2,3]
|
477
|
+
```
|
478
|
+
|
479
|
+
If you want to provide a text-like env variable which contains commas then wrap it into quotes:
|
480
|
+
|
481
|
+
```ruby
|
482
|
+
MYCOOLGEM = "Nif-Nif, Naf-Naf and Nouf-Nouf"
|
483
|
+
```
|
484
|
+
|
485
|
+
## Local files
|
486
|
+
|
487
|
+
It's useful to have a personal, user-specific configuration in development, which extends the project-wide one.
|
243
488
|
|
244
489
|
We support this by looking at _local_ files when loading the configuration data:
|
245
490
|
|
246
491
|
- `<config_name>.local.yml` files (next to\* the _global_ `<config_name>.yml`)
|
247
492
|
- `config/credentials/local.yml.enc` (for Rails >= 6, generate it via `rails credentials:edit --environment local`).
|
248
493
|
|
249
|
-
\* If the YAML config path is not default (i.e
|
494
|
+
\* If the YAML config path is not a default one (i.e., set via `<CONFIG_NAME>_CONF`), we look up the local
|
250
495
|
config at this location, too.
|
251
496
|
|
252
497
|
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"`).
|
@@ -255,110 +500,128 @@ Local configs are meant for using in development and only loaded if `Anyway::Set
|
|
255
500
|
|
256
501
|
Don't forget to add `*.local.yml` (and `config/credentials/local.*`) to your `.gitignore`.
|
257
502
|
|
258
|
-
**NOTE:** local YAML configs for Rails app must be environment-free (i.e
|
259
|
-
|
260
|
-
### Reload configuration
|
503
|
+
**NOTE:** local YAML configs for a Rails app must be environment-free (i.e., you shouldn't have top-level `development:` key).
|
261
504
|
|
262
|
-
|
505
|
+
## Data loaders
|
263
506
|
|
264
|
-
|
265
|
-
|
266
|
-
### OptionParser integration
|
267
|
-
|
268
|
-
It's possible to use config as option parser (e.g. for CLI apps/libraries). It uses
|
269
|
-
[`optparse`](https://ruby-doc.org/stdlib-2.5.1/libdoc/optparse/rdoc/OptionParser.html) under the hood.
|
270
|
-
|
271
|
-
Example usage:
|
507
|
+
You can provide your own data loaders or change the existing ones using the Loaders API (which is very similar to Rack middleware builder):
|
272
508
|
|
273
509
|
```ruby
|
274
|
-
|
275
|
-
|
510
|
+
# remove env loader => do not load params from ENV
|
511
|
+
Anyway.loaders.delete :env
|
276
512
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
# provide description for options
|
281
|
-
describe_options(
|
282
|
-
concurrency: "number of threads to use"
|
283
|
-
)
|
513
|
+
# add custom loader before :env (it's better to keep the ENV loader the last one)
|
514
|
+
Anyway.loaders.insert_before :env, :my_loader, MyLoader
|
515
|
+
```
|
284
516
|
|
285
|
-
|
286
|
-
|
517
|
+
Loader is a _callable_ Ruby object (module/class responding to `.call` or lambda/proc), which `call` method
|
518
|
+
accepts the following keyword arguments:
|
287
519
|
|
288
|
-
|
289
|
-
|
290
|
-
|
520
|
+
```ruby
|
521
|
+
def call(
|
522
|
+
name:, # config name
|
523
|
+
env_prefix:, # prefix for env vars if any
|
524
|
+
config_path:, # path to YML config
|
525
|
+
local: # true|false, whether to load local configuration
|
526
|
+
)
|
527
|
+
#=> must return Hash with configuration data
|
528
|
+
end
|
529
|
+
```
|
291
530
|
|
292
|
-
|
293
|
-
|
294
|
-
end
|
531
|
+
You can use `Anyway::Loaders::Base` as a base class for your loader and define a `#call` method.
|
532
|
+
For example, the [Chamber](https://github.com/thekompanee/chamber) loader could be written as follows:
|
295
533
|
|
296
|
-
|
297
|
-
|
298
|
-
|
534
|
+
```ruby
|
535
|
+
class ChamberConfigLoader < Anyway::Loaders::Base
|
536
|
+
def call(name:, **_opts)
|
537
|
+
Chamber.env.to_h[name] || {}
|
299
538
|
end
|
300
539
|
end
|
540
|
+
```
|
301
541
|
|
302
|
-
|
303
|
-
|
304
|
-
config.parse_options!(%w[--host localhost --port 3333 --log-level debug])
|
305
|
-
|
306
|
-
config.host # => "localhost"
|
307
|
-
config.port # => 3333
|
308
|
-
config.log_level # => "debug"
|
542
|
+
In order to support [source tracing](#tracing), you need to wrap the resulting Hash via the `#trace!` method with metadata:
|
309
543
|
|
310
|
-
|
311
|
-
|
544
|
+
```ruby
|
545
|
+
def call(name:, **_opts)
|
546
|
+
trace!(source: :chamber) do
|
547
|
+
Chamber.env.to_h[name] || {}
|
548
|
+
end
|
549
|
+
end
|
312
550
|
```
|
313
551
|
|
314
|
-
##
|
315
|
-
|
316
|
-
Rails 4.2 introduced new feature: `Rails.application.config_for`. It looks very similar to
|
317
|
-
`Anyway::Config.for`, but there are some differences:
|
552
|
+
## Tracing
|
318
553
|
|
319
|
-
|
320
|
-
| ------------- |-------------:| -----:|
|
321
|
-
| load data from `config/app.yml` | yes | yes |
|
322
|
-
| load data from `secrets` | no | yes |
|
323
|
-
| load data from `credentials` | no | yes |
|
324
|
-
| load data from environment | no | yes |
|
325
|
-
| local config files | no | yes |
|
326
|
-
| return Hash with indifferent access | no | yes |
|
327
|
-
| support ERB within `config/app.yml` | yes | yes* |
|
328
|
-
| raise errors if file doesn't exist | yes | no |
|
554
|
+
Since Anyway Config loads data from multiple source, it could be useful to know where a particular value came from.
|
329
555
|
|
330
|
-
|
556
|
+
Each `Anyway::Config` instance contains _tracing information_ which you can access via `#to_source_trace` method:
|
331
557
|
|
332
|
-
|
558
|
+
```ruby
|
559
|
+
conf = ExampleConfig.new
|
560
|
+
conf.to_source_trace
|
561
|
+
|
562
|
+
# returns the following hash
|
563
|
+
{
|
564
|
+
"host" => {value: "test.host", source: {type: :yml, path: "config/example.yml"}},
|
565
|
+
"user" => {
|
566
|
+
"name" => {value: "john", source: {type: :env, key: "EXAMPLE_USER__NAME"}},
|
567
|
+
"password" => {value: "root", source: {type: :credentials, store: "config/credentials/production.enc.yml"}}
|
568
|
+
},
|
569
|
+
"port" => {value: 9292, source: {type: :defaults}}
|
570
|
+
}
|
571
|
+
|
572
|
+
# if you change the value manually in your code,
|
573
|
+
# that would be reflected in the trace
|
574
|
+
|
575
|
+
conf.host = "anyway.host"
|
576
|
+
conf.to_source_trace["host"]
|
577
|
+
#=> {type: :user, called_from: "/path/to/caller.rb:15"}
|
578
|
+
```
|
333
579
|
|
334
|
-
|
580
|
+
You can disable tracing functionality by setting `Anyway::Settings.tracing_enabled = false` or `config.anyway_config.tracing_enabled = false` in Rails.
|
335
581
|
|
336
|
-
|
582
|
+
### Pretty print
|
337
583
|
|
338
|
-
|
584
|
+
You can use `pp` to print a formatted information about the config including the sources trace.
|
339
585
|
|
340
|
-
|
586
|
+
Example:
|
341
587
|
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
588
|
+
```ruby
|
589
|
+
pp CoolConfig.new
|
590
|
+
|
591
|
+
# #<CoolConfig
|
592
|
+
# config_name="cool"
|
593
|
+
# env_prefix="COOL"
|
594
|
+
# values:
|
595
|
+
# port => 3334 (type=load),
|
596
|
+
# host => "test.host" (type=yml path=./config/cool.yml),
|
597
|
+
# user =>
|
598
|
+
# name => "john" (type=env key=COOL_USER__NAME),
|
599
|
+
# password => "root" (type=yml path=./config/cool.yml)>
|
600
|
+
```
|
346
601
|
|
347
|
-
|
602
|
+
## Pattern matching
|
348
603
|
|
349
|
-
|
350
|
-
|
351
|
-
Array values are also supported:
|
604
|
+
You can use config instances in Ruby 2.7+ pattern matching:
|
352
605
|
|
353
606
|
```ruby
|
354
|
-
|
355
|
-
|
607
|
+
case AWSConfig.new
|
608
|
+
in bucket:, region: "eu-west-1"
|
609
|
+
setup_eu_storage(bucket)
|
610
|
+
in bucket:, region: "us-east-1"
|
611
|
+
setup_us_storage(bucket)
|
612
|
+
end
|
356
613
|
```
|
357
614
|
|
358
|
-
If
|
615
|
+
If the attribute wasn't populated, the key won't be returned for pattern matching, i.e. you can do something line:
|
359
616
|
|
360
617
|
```ruby
|
361
|
-
|
618
|
+
aws_configured =
|
619
|
+
case AWSConfig.new
|
620
|
+
in access_key_id:, secret_access_key:
|
621
|
+
true
|
622
|
+
else
|
623
|
+
false
|
624
|
+
end
|
362
625
|
```
|
363
626
|
|
364
627
|
## Test helpers
|
@@ -398,6 +661,68 @@ This helper is automatically included to RSpec if `RAILS_ENV` or `RACK_ENV` env
|
|
398
661
|
|
399
662
|
You can add it manually by requiring `"anyway/testing/helpers"` and including the `Anyway::Test::Helpers` module (into RSpec configuration or Minitest test class).
|
400
663
|
|
664
|
+
## OptionParser integration
|
665
|
+
|
666
|
+
It's possible to use config as option parser (e.g., for CLI apps/libraries). It uses
|
667
|
+
[`optparse`](https://ruby-doc.org/stdlib-2.5.1/libdoc/optparse/rdoc/OptionParser.html) under the hood.
|
668
|
+
|
669
|
+
Example usage:
|
670
|
+
|
671
|
+
```ruby
|
672
|
+
class MyConfig < Anyway::Config
|
673
|
+
attr_config :host, :log_level, :concurrency, :debug, server_args: {}
|
674
|
+
|
675
|
+
# specify which options shouldn't be handled by option parser
|
676
|
+
ignore_options :server_args
|
677
|
+
|
678
|
+
# provide description for options
|
679
|
+
describe_options(
|
680
|
+
concurrency: "number of threads to use"
|
681
|
+
)
|
682
|
+
|
683
|
+
# mark some options as flag
|
684
|
+
flag_options :debug
|
685
|
+
|
686
|
+
# extend an option parser object (i.e. add banner or version/help handlers)
|
687
|
+
extend_options do |parser, config|
|
688
|
+
parser.banner = "mycli [options]"
|
689
|
+
|
690
|
+
parser.on("--server-args VALUE") do |value|
|
691
|
+
config.server_args = JSON.parse(value)
|
692
|
+
end
|
693
|
+
|
694
|
+
parser.on_tail "-h", "--help" do
|
695
|
+
puts parser
|
696
|
+
end
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
config = MyConfig.new
|
701
|
+
|
702
|
+
config.parse_options!(%w[--host localhost --port 3333 --log-level debug])
|
703
|
+
|
704
|
+
config.host # => "localhost"
|
705
|
+
config.port # => 3333
|
706
|
+
config.log_level # => "debug"
|
707
|
+
|
708
|
+
# Get the instance of OptionParser
|
709
|
+
config.option_parser
|
710
|
+
```
|
711
|
+
|
712
|
+
**NOTE:** values are automatically type cast using the same rules as for [environment variables](#environment-variables).
|
713
|
+
If you want to specify the type explicitly, you can do that using `describe_options`:
|
714
|
+
|
715
|
+
```ruby
|
716
|
+
describe_options(
|
717
|
+
# In this case, you should specify a hash with `type`
|
718
|
+
# and (optionally) `desc` keys
|
719
|
+
concurrency: {
|
720
|
+
desc: "number of threads to use",
|
721
|
+
type: String
|
722
|
+
}
|
723
|
+
)
|
724
|
+
```
|
725
|
+
|
401
726
|
## Contributing
|
402
727
|
|
403
728
|
Bug reports and pull requests are welcome on GitHub at [https://github.com/palkan/anyway_config](https://github.com/palkan/anyway_config).
|