qonfig 0.0.0 → 0.12.0
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/.gitignore +6 -2
- data/.jrubyrc +1 -0
- data/.rspec +1 -1
- data/.rubocop.yml +15 -0
- data/.travis.yml +43 -4
- data/CHANGELOG.md +121 -0
- data/Gemfile +4 -2
- data/LICENSE.txt +1 -1
- data/README.md +1060 -19
- data/Rakefile +18 -4
- data/bin/console +5 -11
- data/bin/rspec +55 -0
- data/bin/setup +1 -0
- data/gemfiles/with_external_deps.gemfile +8 -0
- data/gemfiles/without_external_deps.gemfile +5 -0
- data/lib/qonfig.rb +22 -2
- data/lib/qonfig/command_set.rb +67 -0
- data/lib/qonfig/commands.rb +15 -0
- data/lib/qonfig/commands/add_nested_option.rb +45 -0
- data/lib/qonfig/commands/add_option.rb +41 -0
- data/lib/qonfig/commands/base.rb +12 -0
- data/lib/qonfig/commands/compose.rb +37 -0
- data/lib/qonfig/commands/expose_yaml.rb +159 -0
- data/lib/qonfig/commands/load_from_env.rb +95 -0
- data/lib/qonfig/commands/load_from_env/value_converter.rb +84 -0
- data/lib/qonfig/commands/load_from_json.rb +56 -0
- data/lib/qonfig/commands/load_from_self.rb +73 -0
- data/lib/qonfig/commands/load_from_yaml.rb +58 -0
- data/lib/qonfig/configurable.rb +116 -0
- data/lib/qonfig/data_set.rb +213 -0
- data/lib/qonfig/data_set/class_builder.rb +27 -0
- data/lib/qonfig/data_set/validator.rb +7 -0
- data/lib/qonfig/dsl.rb +122 -0
- data/lib/qonfig/errors.rb +111 -0
- data/lib/qonfig/loaders.rb +9 -0
- data/lib/qonfig/loaders/basic.rb +38 -0
- data/lib/qonfig/loaders/json.rb +24 -0
- data/lib/qonfig/loaders/yaml.rb +24 -0
- data/lib/qonfig/plugins.rb +65 -0
- data/lib/qonfig/plugins/abstract.rb +13 -0
- data/lib/qonfig/plugins/access_mixin.rb +38 -0
- data/lib/qonfig/plugins/registry.rb +125 -0
- data/lib/qonfig/plugins/toml.rb +26 -0
- data/lib/qonfig/plugins/toml/commands/expose_toml.rb +146 -0
- data/lib/qonfig/plugins/toml/commands/load_from_toml.rb +49 -0
- data/lib/qonfig/plugins/toml/data_set.rb +19 -0
- data/lib/qonfig/plugins/toml/dsl.rb +27 -0
- data/lib/qonfig/plugins/toml/loaders/toml.rb +24 -0
- data/lib/qonfig/plugins/toml/tomlrb_fixes.rb +92 -0
- data/lib/qonfig/plugins/toml/uploaders/toml.rb +25 -0
- data/lib/qonfig/settings.rb +457 -0
- data/lib/qonfig/settings/builder.rb +18 -0
- data/lib/qonfig/settings/key_guard.rb +71 -0
- data/lib/qonfig/settings/lock.rb +60 -0
- data/lib/qonfig/uploaders.rb +10 -0
- data/lib/qonfig/uploaders/base.rb +18 -0
- data/lib/qonfig/uploaders/file.rb +55 -0
- data/lib/qonfig/uploaders/json.rb +35 -0
- data/lib/qonfig/uploaders/yaml.rb +93 -0
- data/lib/qonfig/version.rb +7 -1
- data/qonfig.gemspec +29 -17
- metadata +122 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62b74a92c4c74b79f222e029726296a63b51ba3a57886a00911a34ffbcbced25
|
4
|
+
data.tar.gz: 33fa91631b6554dec3547c9c31faddf805bc4a56becbe7042e1942c19c493f16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 152acb89e834fccaaed1b4bfae379f8263d795b2e4e7b7913f6a2b98fd1bfebf984dec1c82a3568ddc08a3e16fdec2be7783f1f583ef09a3dc6b1386f9afb18f
|
7
|
+
data.tar.gz: c468d5a5c289dc8b4b7b337e62314dbbf9d388b5dd6df1248a14e957a97be9937d7f24c47aa8634ffe415dbd092ed4f3c5b447036770b171fb6d87454eceb4e8
|
data/.gitignore
CHANGED
data/.jrubyrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
debug.fullTrace=true
|
data/.rspec
CHANGED
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
@@ -1,5 +1,44 @@
|
|
1
|
-
sudo: false
|
2
1
|
language: ruby
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
matrix:
|
3
|
+
fast_finish: true
|
4
|
+
include:
|
5
|
+
- rvm: 2.3.8
|
6
|
+
gemfile: gemfiles/with_external_deps.gemfile
|
7
|
+
env: TEST_PLUGINS=true
|
8
|
+
- rvm: 2.4.6
|
9
|
+
gemfile: gemfiles/with_external_deps.gemfile
|
10
|
+
env: TEST_PLUGINS=true
|
11
|
+
- rvm: 2.5.5
|
12
|
+
gemfile: gemfiles/with_external_deps.gemfile
|
13
|
+
env: TEST_PLUGINS=true
|
14
|
+
- rvm: 2.6.3
|
15
|
+
gemfile: gemfiles/with_external_deps.gemfile
|
16
|
+
env: TEST_PLUGINS=true
|
17
|
+
- rvm: ruby-head
|
18
|
+
gemfile: gemfiles/with_external_deps.gemfile
|
19
|
+
env: TEST_PLUGINS=true
|
20
|
+
- rvm: jruby-head
|
21
|
+
gemfile: gemfiles/with_external_deps.gemfile
|
22
|
+
env: TEST_PLUGINS=true
|
23
|
+
- rvm: 2.3.8
|
24
|
+
gemfile: gemfiles/without_external_deps.gemfile
|
25
|
+
- rvm: 2.4.6
|
26
|
+
gemfile: gemfiles/without_external_deps.gemfile
|
27
|
+
- rvm: 2.5.5
|
28
|
+
gemfile: gemfiles/without_external_deps.gemfile
|
29
|
+
- rvm: 2.6.3
|
30
|
+
gemfile: gemfiles/without_external_deps.gemfile
|
31
|
+
- rvm: ruby-head
|
32
|
+
gemfile: gemfiles/without_external_deps.gemfile
|
33
|
+
- rvm: jruby-head
|
34
|
+
gemfile: gemfiles/without_external_deps.gemfile
|
35
|
+
allow_failures:
|
36
|
+
- rvm: ruby-head
|
37
|
+
- rvm: jruby-head
|
38
|
+
sudo: false
|
39
|
+
cache: bundler
|
40
|
+
before_install: gem install bundler
|
41
|
+
script: bundle exec rspec
|
42
|
+
notifications:
|
43
|
+
slack:
|
44
|
+
secure: I03SDv+IrKy3IkeGjjHUJ9VneFMiYpLzIgPOixGFO5zGVXgulwmun82KsrPSW5HkK1UEQCahfoXt1hNECPwxcdsY01q6LBYJQx1jD0q17bXHllN/q0C6lx3peRN0KqNAAOU3/mHZxLt3HFV+N3HsSnoxDMuSYJgKbjCL/QVG2L2UYT9vi+JRNM/thj8R6MWKWlOHemik40GbLr2anCOCqiALzxnJzh5nJyGj+9SGvjhHfQq/fAIrg1+Scu+UchG8d+1yS5JWsGTt1/JF08i+Ux4ceTQ7GNBNeA5cj/xuUzvRx6A85renxyTiZMKIL0+jeceUm8c+/46XFcq0F7/kJB36lwjFhX1JRphcu/VouRdEwW/BvH74wnyHtygqOpk0LH4shp7A1DIS1DlnBbeJxrR5hdMDnmV85kTU6w6H0BbncsYY/pH1fji1kgH6jCsdwqDlq4wLB8x8I+eZABBsfb/r55z/HnBmmxlvR7Rt3X5/yR3gJrsgRrDBBZ5LwYy1RSCDu76vMQqWGJKG03FdfqSNqmC5V4MC5Ez8yjGDW0Yle09mwvsL2c6fDXyDPCeB/gwNk+FvgLRXnv7C4BaBNEoG4JnCL/dwauoJNg0lB6uF34BEmYAhZIrdY1CI6BqPWnaVMJfcJSYekBVXDIELDnTFRWjaGU1y8dM6lNzDmYE=
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
## [0.12.0] - 2019-07-19
|
5
|
+
### Added
|
6
|
+
- Support for **TOML** (`.toml`) format
|
7
|
+
- realized as a plugin (`Qonfig.plugin(:toml)`);
|
8
|
+
- provides `#save_to_toml`, `#load_from_toml`, `#expose_toml` methods and works in `#*_yaml`-like manner);
|
9
|
+
- Custom `bin/rspec` command:
|
10
|
+
- `bin/rspec -n` - run tests without plugin tests;
|
11
|
+
- `bin/rspec -w` - run all tests;
|
12
|
+
- Added more convinient aliases for `Qonfig::DataSet` instances:
|
13
|
+
- `#save_to_yaml` => `#dump_to_yaml`;
|
14
|
+
- `#save_to_json` => `#dump_to_json`;
|
15
|
+
- `#save_to_toml` => `#dump_to_toml`;
|
16
|
+
### Changed
|
17
|
+
- Actualized development dependencies;
|
18
|
+
|
19
|
+
## [0.11.0] - 2019-05-15
|
20
|
+
### Added
|
21
|
+
- `#save_to_json` - save configurations to a json file (uses native `::JSON.generate` under the hood);
|
22
|
+
- `#save_to_yaml` - save configurations to a yaml file (uses native `::Psych.dump` under the hood);
|
23
|
+
|
24
|
+
### Changed
|
25
|
+
- new `#to_h` signature: `#to_h(key_transformer:, value_transformer:)`
|
26
|
+
- `:key_transformer` - proc object used for key pre-processing (`-> (key) { key }` by default);
|
27
|
+
- `:value_transformer` - proc object used for value pre-processing (`-> (value) { value }` by default);
|
28
|
+
|
29
|
+
## [0.10.0] - 2019-02-26
|
30
|
+
### Added
|
31
|
+
- `#slice_value` - get a slice of config options as a hash set and fetch the required value using the given key set;
|
32
|
+
|
33
|
+
## [0.9.0] - 2018-11-28
|
34
|
+
### Added
|
35
|
+
- `#slice` - get a slice of config options as a hash set (works in a `#dig` manner);
|
36
|
+
|
37
|
+
## [0.8.0] - 2018-11-21
|
38
|
+
### Changed
|
39
|
+
- `expose_yaml`, `load_from_yaml`, `load_from_json` and `load_from_self` treats empty hash (`{}`)
|
40
|
+
as an option with empty hash value (previously treated as a nested setting without options);
|
41
|
+
|
42
|
+
## [0.7.0] - 2018-10-20
|
43
|
+
### Added
|
44
|
+
- `expose_yaml` - a command that provides an ability to define config settings
|
45
|
+
by loading them from a yaml file where the concrete settings depends on the chosen environment;
|
46
|
+
|
47
|
+
## [0.6.0] - 2018-08-22
|
48
|
+
### Added
|
49
|
+
- `#shared_config` - instance method that provides an access to the class level config
|
50
|
+
object from `Qonfig::Configurable` instances;
|
51
|
+
|
52
|
+
## [0.5.0] - 2018-07-27
|
53
|
+
### Added
|
54
|
+
- `load_from_json`- a command that provides an ability to define config settings
|
55
|
+
by loading them from a json file (in `load_from_yaml` manner);
|
56
|
+
|
57
|
+
### Changed
|
58
|
+
- Support for Ruby 2.2 has ended;
|
59
|
+
|
60
|
+
## [0.4.0] - 2018-06-24
|
61
|
+
### Added
|
62
|
+
- Introduce Plugin Ecosystem (`Qonfig::Plugins`):
|
63
|
+
- load plugin: `Qonfig.plugin('plugin_name')` or `Qonfig.plugin(:plugin_name)`;
|
64
|
+
- get registered plugins: `Qonfig.plugins #=> array of strings`
|
65
|
+
|
66
|
+
## [0.3.0] - 2018-06-13
|
67
|
+
### Added
|
68
|
+
- Improved configuration process: `#configure` can take a hash as a configuration `[option key => option]`
|
69
|
+
map of values;
|
70
|
+
|
71
|
+
### Changed
|
72
|
+
- `#clear!` causes `Qonfig::FrozenSettingsError` if config object is frozen;
|
73
|
+
|
74
|
+
## [0.2.0] - 2018-06-07
|
75
|
+
### Added
|
76
|
+
- Instant configuration via block `config = Config.new { |conf| <<your configuration code>> }`;
|
77
|
+
- `.load_from_env` command - an ability to define config settings by loading them from ENV variable;
|
78
|
+
- `.load_from_yaml` command - an ability to define config settings by loading them from a yaml file;
|
79
|
+
- `.load_from_self` command - an ability to load config definitions form the YAML
|
80
|
+
instructions written in the file where the config class is defined (`__END__` section);
|
81
|
+
- `#reload!` - an ability to reload config isntance after any config class changes and updates;
|
82
|
+
- `#clear!` - an ability to set all options to `nil`;
|
83
|
+
- `#dig` - an ability to fetch setting values in `Hash#dig` manner
|
84
|
+
(fails with `Qonfig::UnknownSettingError` when the required key does not exist);
|
85
|
+
- Settings as Predicates - an ability to check the boolean nature of the config setting by appending
|
86
|
+
the question mark symbol (`?`) at the end of setting name:
|
87
|
+
- `nil` and `false` setting values indicates `false`;
|
88
|
+
- other setting values indicates `true`;
|
89
|
+
- setting roots always returns `true`;
|
90
|
+
- examples:
|
91
|
+
- `config.settings.database.user # => nil`;
|
92
|
+
- `config.settings.database.user? # => false`;
|
93
|
+
- `config.settings.database.host # => 'google.com'`;
|
94
|
+
- `config.settings.database.host? # => true`;
|
95
|
+
- `config.settings.database? # => true (setting with nested option (setting root))`
|
96
|
+
- Support for ERB instructions in YAML;
|
97
|
+
- Support for `HashWithIndifferentAccess`-like behaviour;
|
98
|
+
- `Qonfig::Settings` instance method redefinition protection: the setting key can not
|
99
|
+
have a name that matches an any instance method name of `Qonfig::Settings`;
|
100
|
+
- Added `Qonfig::Configurable` mixin - configuration behaviour for any classes and modules
|
101
|
+
and their instances:
|
102
|
+
- all `Qonfig`-related features;
|
103
|
+
- different class-level and instance-level config objects;
|
104
|
+
- working class-level inheritance :);
|
105
|
+
- Full thread-safe implementation;
|
106
|
+
|
107
|
+
### Changed
|
108
|
+
- Superclass of `Qonfig::FrozenSettingsError` (it was `Qonfig::Error` before):
|
109
|
+
- `ruby >= 2.5` - inherited from `::FrozenError`;
|
110
|
+
- `ruby < 2.5` - inherited from `::RuntimeError`;
|
111
|
+
- `.setting` will raise exceptions immediately:
|
112
|
+
- `.setting(key, ...) { ... }` - if setting key has incompatible type;
|
113
|
+
- `.compose(config_class)`- if composed config class is not a subtype of `Qonfig::DataSet`;
|
114
|
+
|
115
|
+
### Fixed
|
116
|
+
- Recoursive hash representation with deep nested `Qonfig::Settings` values (infinite loop);
|
117
|
+
- Fixed re-assignment of the options with nested options (losing the nested options
|
118
|
+
due to the instance configuration). Now it causes `Qonfig::AmbigousSettingValueError`.
|
119
|
+
|
120
|
+
## [0.1.0] - 2018-05-18
|
121
|
+
- Release :)
|
data/Gemfile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
6
|
|
5
7
|
# Specify your gem's dependencies in qonfig.gemspec
|
6
8
|
gemspec
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,43 +1,1084 @@
|
|
1
|
-
# Qonfig
|
1
|
+
# Qonfig · [](https://badge.fury.io/rb/qonfig) [](https://travis-ci.org/0exp/qonfig) [](https://coveralls.io/github/0exp/qonfig?branch=master)
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
Config. Defined as a class. Used as an instance. Support for inheritance and composition.
|
4
|
+
Lazy instantiation. Thread-safe. Command-style DSL. Extremely simple to define. Extremely simple to use. That's all.
|
6
5
|
|
7
6
|
## Installation
|
8
7
|
|
9
|
-
Add this line to your application's Gemfile:
|
10
|
-
|
11
8
|
```ruby
|
12
9
|
gem 'qonfig'
|
13
10
|
```
|
14
11
|
|
15
|
-
|
12
|
+
```shell
|
13
|
+
$ bundle install
|
14
|
+
# --- or ---
|
15
|
+
$ gem install 'qonfig'
|
16
|
+
```
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
require 'qonfig'
|
20
|
+
```
|
21
|
+
|
22
|
+
## Usage
|
16
23
|
|
17
|
-
|
24
|
+
- [Definition and Settings Access](#definition-and-access)
|
25
|
+
- [Configuration](#configuration)
|
26
|
+
- [Inheritance](#inheritance)
|
27
|
+
- [Composition](#composition)
|
28
|
+
- [Hash representation](#hash-representation)
|
29
|
+
- [Config reloading](#config-reloading) (reload config definitions and option values)
|
30
|
+
- [Clear options](#clear-options) (set to nil)
|
31
|
+
- [State freeze](#state-freeze)
|
32
|
+
- [Settings as Predicates](#settings-as-predicates)
|
33
|
+
- [Load from YAML file](#load-from-yaml-file)
|
34
|
+
- [Expose YAML](#expose-yaml) (`Rails`-like environment-based YAML configs)
|
35
|
+
- [Load from JSON file](#load-from-json-file)
|
36
|
+
- [Load from ENV](#load-from-env)
|
37
|
+
- [Load from \_\_END\_\_](#load-from-__end__) (aka `load_from_self`)
|
38
|
+
- [Save to JSON file](#save-to-json-file) (`save_to_json`)
|
39
|
+
- [Save to YAML file](#save-to-yaml-file) (`save_to_yaml`)
|
40
|
+
- [Smart Mixin](#smart-mixin) (`Qonfig::Configurable`)
|
41
|
+
- [Plugins](#plugins)
|
42
|
+
- [toml](#plugin-toml) (provides `load_from_toml`, `save_to_toml`, `expose_toml`)
|
43
|
+
---
|
18
44
|
|
19
|
-
|
45
|
+
### Definition and Access
|
20
46
|
|
21
|
-
|
47
|
+
```ruby
|
48
|
+
# --- definition ---
|
49
|
+
class Config < Qonfig::DataSet
|
50
|
+
# nil by default
|
51
|
+
setting :project_id
|
22
52
|
|
23
|
-
|
53
|
+
# nested setting
|
54
|
+
setting :vendor_api do
|
55
|
+
setting :host, 'app.service.com'
|
56
|
+
end
|
57
|
+
|
58
|
+
setting :enable_graphql, false
|
59
|
+
|
60
|
+
# nested setting reopening
|
61
|
+
setting :vendor_api do
|
62
|
+
setting :user, 'test_user'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
config = Config.new # your configuration object instance
|
67
|
+
|
68
|
+
# --- setting access ---
|
69
|
+
|
70
|
+
# get option value via method
|
71
|
+
config.settings.project_id # => nil
|
72
|
+
config.settings.vendor_api.host # => 'app.service.com'
|
73
|
+
config.settings.vendor_api.user # => 'test_user'
|
74
|
+
config.settings.enable_graphql # => false
|
75
|
+
|
76
|
+
# get option value via index (with indifferent (string / symbol / mixed) access)
|
77
|
+
config.settings[:project_id] # => nil
|
78
|
+
config.settings[:vendor_api][:host] # => 'app.service.com'
|
79
|
+
config.settings[:vendor_api][:user] # => 'test_user'
|
80
|
+
config.settings[:enable_graphql] # => false
|
81
|
+
|
82
|
+
# get option value via index (with indifferent (string / symbol / mixed) access)
|
83
|
+
config.settings['project_id'] # => nil
|
84
|
+
config.settings['vendor_api']['host'] # => 'app.service.com'
|
85
|
+
config.settings['vendor_api']['user'] # => 'test_user'
|
86
|
+
config.settings['enable_graphql'] # => false
|
87
|
+
|
88
|
+
# get option value directly via index (with indifferent access)
|
89
|
+
config['project_id'] # => nil
|
90
|
+
config['enable_graphql'] # => false
|
91
|
+
config[:project_id] # => nil
|
92
|
+
config[:enable_graphql] # => false
|
93
|
+
|
94
|
+
# get option value in Hash#dig manner (and fail when the required key does not exist)
|
95
|
+
config.dig(:vendor_api, :host) # => 'app.service.com' # (key exists)
|
96
|
+
config.dig(:vendor_api, :port) # => Qonfig::UnknownSettingError # (key does not exist)
|
97
|
+
|
98
|
+
# get a hash slice of setting options (and fail when the required key does not exist)
|
99
|
+
config.slice(:vendor_api) # => { 'vendor_api' => { 'host' => 'app_service', 'user' => 'test_user' } }
|
100
|
+
config.slice(:vendor_api, :user) # => { 'user' => 'test_user' }
|
101
|
+
config.slice(:project_api) # => Qonfig::UnknownSettingError # (key does not exist)
|
102
|
+
config.slice(:vendor_api, :port) # => Qonfig::UnknownSettingError # (key does not exist)
|
103
|
+
|
104
|
+
# get value from the slice of setting options using the given key set (and fail when the required key does not exist) (works in slice manner)
|
105
|
+
config.slice_value(:vendor_api) # => { 'host' => 'app_service', 'user' => 'test_user' }
|
106
|
+
config.slice_value(:vendor_api, :user) # => 'test_user'
|
107
|
+
config.slice_value(:project_api) # => Qonfig::UnknownSettingError # (key does not exist)
|
108
|
+
config.slice_value(:vendor_api, :port) # => Qonfig::UnknownSettingError # (key does not exist)
|
109
|
+
```
|
110
|
+
|
111
|
+
---
|
112
|
+
|
113
|
+
### Configuration
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
class Config < Qonfig::DataSet
|
117
|
+
setting :testing do
|
118
|
+
setting :engine, :rspec
|
119
|
+
setting :parallel, true
|
120
|
+
end
|
121
|
+
|
122
|
+
setting :geo_api do
|
123
|
+
setting :provider, :google_maps
|
124
|
+
end
|
125
|
+
|
126
|
+
setting :enable_middlewares, false
|
127
|
+
end
|
128
|
+
|
129
|
+
config = Config.new
|
130
|
+
|
131
|
+
# configure via proc
|
132
|
+
config.configure do |conf|
|
133
|
+
conf.enable_middlewares = true
|
134
|
+
conf.geo_api.provider = :yandex_maps
|
135
|
+
conf.testing.engine = :mini_test
|
136
|
+
end
|
137
|
+
|
138
|
+
# configure via settings object (by option name)
|
139
|
+
config.settings.enable_middlewares = false
|
140
|
+
config.settings.geo_api.provider = :apple_maps
|
141
|
+
config.settings.testing.engine = :ultra_test
|
142
|
+
|
143
|
+
# configure via settings object (by setting key)
|
144
|
+
config.settings[:enable_middlewares] = true
|
145
|
+
config.settings[:geo_api][:provider] = :rambler_maps
|
146
|
+
config.settings[:testing][:engine] = :mega_test
|
147
|
+
|
148
|
+
# instant configuration via proc
|
149
|
+
config = Config.new do |conf|
|
150
|
+
conf.enable_middlewares = false
|
151
|
+
conf.geo_api.provider = :amazon_maps
|
152
|
+
conf.testing.engine = :crypto_test
|
153
|
+
end
|
154
|
+
|
155
|
+
# using a hash
|
156
|
+
config = Config.new(
|
157
|
+
testing: { engine: :mini_test, parallel: false },
|
158
|
+
geo_api: { provider: :rambler_maps },
|
159
|
+
enable_middlewares: true
|
160
|
+
)
|
161
|
+
config.configure(enable_middlewares: false)
|
162
|
+
|
163
|
+
# using both hash and proc (proc has higher priority)
|
164
|
+
config = Config.new(enable_middlewares: true) do |conf|
|
165
|
+
conf.testing.parallel = true
|
166
|
+
end
|
167
|
+
|
168
|
+
config.configure(geo_api: { provider: nil }) do |conf|
|
169
|
+
conf.testing.engine = :rspec
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
---
|
174
|
+
|
175
|
+
### Inheritance
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
class CommonConfig < Qonfig::DataSet
|
179
|
+
setting :uploader, :fog
|
180
|
+
end
|
181
|
+
|
182
|
+
class ProjectConfig < CommonConfig
|
183
|
+
setting :auth_provider, :github
|
184
|
+
end
|
185
|
+
|
186
|
+
project_config = ProjectConfig.new
|
187
|
+
|
188
|
+
# inherited setting
|
189
|
+
project_config.settings.uploader # => :fog
|
190
|
+
|
191
|
+
# own setting
|
192
|
+
project_config.settings.auth_provider # => :github
|
193
|
+
```
|
194
|
+
|
195
|
+
---
|
196
|
+
|
197
|
+
### Composition
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
class SharedConfig < Qonfig::DataSet
|
201
|
+
setting :logger, Logger.new
|
202
|
+
end
|
203
|
+
|
204
|
+
class ServerConfig < Qonfig::DataSet
|
205
|
+
setting :port, 12345
|
206
|
+
setting :address, '0.0.0.0'
|
207
|
+
end
|
208
|
+
|
209
|
+
class DatabaseConfig < Qonfig::DataSet
|
210
|
+
setting :user, 'test'
|
211
|
+
setting :password, 'testpaswd'
|
212
|
+
end
|
213
|
+
|
214
|
+
class ProjectConfig < Qonfig::DataSet
|
215
|
+
compose SharedConfig
|
216
|
+
|
217
|
+
setting :server do
|
218
|
+
compose ServerConfig
|
219
|
+
end
|
220
|
+
|
221
|
+
setting :db do
|
222
|
+
compose DatabaseConfig
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
project_config = ProjectConfig.new
|
227
|
+
|
228
|
+
# fields from SharedConfig
|
229
|
+
project_config.settings.logger # => #<Logger:0x66f57048>
|
230
|
+
|
231
|
+
# fields from ServerConfig
|
232
|
+
project_config.settings.server.port # => 12345
|
233
|
+
project_config.settings.server.address # => '0.0.0.0'
|
234
|
+
|
235
|
+
# fields from DatabaseConfig
|
236
|
+
project_config.settings.db.user # => 'test'
|
237
|
+
project_config.settings.db.password # => 'testpaswd'
|
238
|
+
```
|
239
|
+
|
240
|
+
---
|
241
|
+
|
242
|
+
### Hash representation
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
class Config < Qonfig::DataSet
|
246
|
+
setting :serializers do
|
247
|
+
setting :json do
|
248
|
+
setting :engine, :ok
|
249
|
+
end
|
250
|
+
|
251
|
+
setting :hash do
|
252
|
+
setting :engine, :native
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
setting :adapter do
|
257
|
+
setting :default, :memory_sync
|
258
|
+
end
|
259
|
+
|
260
|
+
setting :logger, Logger.new(STDOUT)
|
261
|
+
end
|
262
|
+
|
263
|
+
Config.new.to_h
|
264
|
+
|
265
|
+
{
|
266
|
+
"serializers": {
|
267
|
+
"json" => { "engine" => :ok },
|
268
|
+
"hash" => { "engine" => :native },
|
269
|
+
},
|
270
|
+
"adapter" => { "default" => :memory_sync },
|
271
|
+
"logger" => #<Logger:0x4b0d79fc>
|
272
|
+
}
|
273
|
+
```
|
274
|
+
|
275
|
+
---
|
276
|
+
|
277
|
+
### Config reloading
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
class Config < Qonfig::DataSet
|
281
|
+
setting :db do
|
282
|
+
setting :adapter, 'postgresql'
|
283
|
+
end
|
284
|
+
|
285
|
+
setting :logger, Logger.new(STDOUT)
|
286
|
+
end
|
287
|
+
|
288
|
+
config = Config.new
|
289
|
+
|
290
|
+
config.settings.db.adapter # => 'postgresql'
|
291
|
+
config.settings.logger # => #<Logger:0x00007ff9>
|
292
|
+
|
293
|
+
config.configure { |conf| conf.logger = nil } # redefine some settings (will be reloaded)
|
294
|
+
|
295
|
+
# re-define and append settings
|
296
|
+
class Config
|
297
|
+
setting :db do
|
298
|
+
setting :adapter, 'mongoid' # re-define defaults
|
299
|
+
end
|
300
|
+
|
301
|
+
setting :enable_api, false # append new setting
|
302
|
+
end
|
303
|
+
|
304
|
+
# reload settings
|
305
|
+
config.reload!
|
306
|
+
|
307
|
+
config.settings.db.adapter # => 'mongoid'
|
308
|
+
config.settings.logger # => #<Logger:0x00007ff9> (reloaded from defaults)
|
309
|
+
config.settings.enable_api # => false (new setting)
|
310
|
+
|
311
|
+
# reload with instant configuration
|
312
|
+
config.reload!(db: { adapter: 'oracle' }) do |conf|
|
313
|
+
conf.enable_api = true # changed instantly
|
314
|
+
end
|
315
|
+
|
316
|
+
config.settings.db.adapter # => 'oracle'
|
317
|
+
config.settings.logger = # => #<Logger:0x00007ff9>
|
318
|
+
config.settings.enable_api # => true # value from instant change
|
319
|
+
```
|
320
|
+
|
321
|
+
---
|
322
|
+
|
323
|
+
### Clear options
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
class Config
|
327
|
+
setting :database do
|
328
|
+
setting :user
|
329
|
+
setting :password
|
330
|
+
end
|
331
|
+
|
332
|
+
setting :web_api do
|
333
|
+
setting :endpoint
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
config = Config.new do |conf|
|
338
|
+
conf.database.user = '0exp'
|
339
|
+
conf.database.password = 'test123'
|
340
|
+
|
341
|
+
conf.web_api.endpoint = '/api/'
|
342
|
+
end
|
343
|
+
|
344
|
+
config.settings.database.user # => '0exp'
|
345
|
+
config.settings.database.password # => 'test123'
|
346
|
+
config.settings.web_api.endpoint # => '/api'
|
347
|
+
|
348
|
+
# clear all options
|
349
|
+
config.clear!
|
350
|
+
|
351
|
+
config.settings.database.user # => nil
|
352
|
+
config.settings.database.password # => nil
|
353
|
+
config.settings.web_api.endpoint # => nil
|
354
|
+
```
|
355
|
+
|
356
|
+
---
|
357
|
+
|
358
|
+
### State freeze
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
class Config < Qonfig::DataSet
|
362
|
+
setting :logger, Logger.new(STDOUT)
|
363
|
+
setting :worker, :sidekiq
|
364
|
+
setting :db do
|
365
|
+
setting :adapter, 'postgresql'
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
config = Config.new
|
370
|
+
config.freeze!
|
371
|
+
|
372
|
+
config.settings.logger = Logger.new(StringIO.new) # => Qonfig::FrozenSettingsError
|
373
|
+
config.settings.worker = :que # => Qonfig::FrozenSettingsError
|
374
|
+
config.settings.db.adapter = 'mongoid' # => Qonfig::FrozenSettingsError
|
375
|
+
|
376
|
+
config.reload! # => Qonfig::FrozenSettingsError
|
377
|
+
config.clear! # => Qonfig::FrozenSettingsError
|
378
|
+
```
|
379
|
+
|
380
|
+
---
|
381
|
+
|
382
|
+
### Settings as Predicates
|
383
|
+
|
384
|
+
- predicate form: `?` at the end of setting name;
|
385
|
+
- `nil` and `false` setting values indicates `false`;
|
386
|
+
- other setting values indicates `true`;
|
387
|
+
- setting roots always returns `true`;
|
388
|
+
|
389
|
+
```ruby
|
390
|
+
class Config < Qonfig::DataSet
|
391
|
+
setting :database do
|
392
|
+
setting :user
|
393
|
+
setting :host, 'google.com'
|
394
|
+
|
395
|
+
setting :engine do
|
396
|
+
setting :driver, 'postgres'
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
config = Config.new
|
402
|
+
|
403
|
+
# predicates
|
404
|
+
config.settings.database.user? # => false (nil => false)
|
405
|
+
config.settings.database.host? # => true ('google.com' => true)
|
406
|
+
config.settings.database.engine.driver? # => true ('postgres' => true)
|
407
|
+
|
408
|
+
# setting roots always returns true
|
409
|
+
config.settings.database? # => true
|
410
|
+
config.settings.database.engine? # => ture
|
411
|
+
|
412
|
+
config.configure do |conf|
|
413
|
+
conf.database.user = '0exp'
|
414
|
+
conf.database.host = false
|
415
|
+
conf.database.engine.driver = true
|
416
|
+
end
|
417
|
+
|
418
|
+
# predicates
|
419
|
+
config.settings.database.user? # => true ('0exp' => true)
|
420
|
+
config.settings.database.host? # => false (false => false)
|
421
|
+
config.settings.database.engine.driver? # => true (true => true)
|
422
|
+
```
|
423
|
+
|
424
|
+
---
|
425
|
+
|
426
|
+
### Load from YAML file
|
427
|
+
|
428
|
+
- supports `ERB`;
|
429
|
+
- `:strict` mode (fail behaviour when the required yaml file doesnt exist):
|
430
|
+
- `true` (by default) - causes `Qonfig::FileNotFoundError`;
|
431
|
+
- `false` - do nothing, ignore current command;
|
432
|
+
|
433
|
+
```yaml
|
434
|
+
# travis.yml
|
435
|
+
|
436
|
+
sudo: false
|
437
|
+
language: ruby
|
438
|
+
rvm:
|
439
|
+
- ruby-head
|
440
|
+
- jruby-head
|
441
|
+
```
|
442
|
+
|
443
|
+
```yaml
|
444
|
+
# project.yml
|
445
|
+
|
446
|
+
enable_api: false
|
447
|
+
Sidekiq/Scheduler:
|
448
|
+
enable: true
|
449
|
+
```
|
450
|
+
|
451
|
+
```yaml
|
452
|
+
# ruby_data.yml
|
453
|
+
|
454
|
+
version: <%= RUBY_VERSION %>
|
455
|
+
platform: <%= RUBY_PLATFORM %>
|
456
|
+
```
|
457
|
+
|
458
|
+
```ruby
|
459
|
+
class Config < Qonfig::DataSet
|
460
|
+
setting :ruby do
|
461
|
+
load_from_yaml 'ruby_data.yml'
|
462
|
+
end
|
463
|
+
|
464
|
+
setting :travis do
|
465
|
+
load_from_yaml 'travis.yml'
|
466
|
+
end
|
467
|
+
|
468
|
+
load_from_yaml 'project.yml'
|
469
|
+
end
|
470
|
+
|
471
|
+
config = Config.new
|
472
|
+
|
473
|
+
config.settings.travis.sudo # => false
|
474
|
+
config.settings.travis.language # => 'ruby'
|
475
|
+
config.settings.travis.rvm # => ['ruby-head', 'jruby-head']
|
476
|
+
config.settings.enable_api # => false
|
477
|
+
config.settings['Sidekiq/Scheduler']['enable'] #=> true
|
478
|
+
config.settings.ruby.version # => '2.5.1'
|
479
|
+
config.settings.ruby.platform # => 'x86_64-darwin17'
|
480
|
+
```
|
481
|
+
|
482
|
+
```ruby
|
483
|
+
# --- strict mode ---
|
484
|
+
class Config < Qonfig::DataSet
|
485
|
+
setting :nonexistent_yaml do
|
486
|
+
load_from_yaml 'nonexistent_yaml.yml', strict: true # true by default
|
487
|
+
end
|
488
|
+
|
489
|
+
setting :another_key
|
490
|
+
end
|
491
|
+
|
492
|
+
Config.new # => Qonfig::FileNotFoundError
|
493
|
+
|
494
|
+
# --- non-strict mode ---
|
495
|
+
class Config < Qonfig::DataSet
|
496
|
+
settings :nonexistent_yaml do
|
497
|
+
load_from_yaml 'nonexistent_yaml.yml', strict: false
|
498
|
+
end
|
499
|
+
|
500
|
+
setting :another_key
|
501
|
+
end
|
502
|
+
|
503
|
+
Config.new.to_h # => { "nonexistent_yaml" => {}, "another_key" => nil }
|
504
|
+
```
|
505
|
+
|
506
|
+
---
|
507
|
+
|
508
|
+
### Expose YAML
|
509
|
+
|
510
|
+
- load configurations from YAML file in Rails-like manner (with environments);
|
511
|
+
- works in `load_from_yaml` manner;
|
512
|
+
- `via:` - how an environment will be determined:
|
513
|
+
- `:file_name`
|
514
|
+
- load configuration from YAML file that have an `:env` part in it's name;
|
515
|
+
- `:env_key`
|
516
|
+
- load configuration from YAML file;
|
517
|
+
- concrete configuration should be defined in the root key with `:env` name;
|
518
|
+
- `env:` - your environment name (must be a type of `String`, `Symbol` or `Numeric`);
|
519
|
+
- `strict:` - requires the existence of the file and/or key with the name of the used environment:
|
520
|
+
- `true`:
|
521
|
+
- file should exist;
|
522
|
+
- root key with `:env` name should exist (if `via: :env_key` is used);
|
523
|
+
- raises `Qonfig::ExposeError` if file does not contain the required env key (if `via: :env` key is used);
|
524
|
+
- raises `Qonfig::FileNotFoundError` if the required file does not exist;
|
525
|
+
- `false`:
|
526
|
+
- file is not required;
|
527
|
+
- root key with `:env` name is not required (if `via: :env_key` is used);
|
528
|
+
|
529
|
+
#### Environment is defined as a root key of YAML file
|
530
|
+
|
531
|
+
```yaml
|
532
|
+
# config/project.yml
|
533
|
+
|
534
|
+
default: &default
|
535
|
+
enable_api_mode: true
|
536
|
+
google_key: 12345
|
537
|
+
window:
|
538
|
+
width: 100
|
539
|
+
height: 100
|
24
540
|
|
25
|
-
|
541
|
+
development:
|
542
|
+
<<: *default
|
26
543
|
|
27
|
-
|
544
|
+
test:
|
545
|
+
<<: *default
|
546
|
+
sidekiq_instrumentation: false
|
547
|
+
|
548
|
+
staging:
|
549
|
+
<<: *default
|
550
|
+
google_key: 777
|
551
|
+
enable_api_mode: false
|
552
|
+
|
553
|
+
production:
|
554
|
+
google_key: asd1-39sd-55aI-O92x
|
555
|
+
enable_api_mode: true
|
556
|
+
window:
|
557
|
+
width: 50
|
558
|
+
height: 150
|
559
|
+
```
|
560
|
+
|
561
|
+
```ruby
|
562
|
+
class Config < Qonfig::DataSet
|
563
|
+
expose_yaml 'config/project.yml', via: :env_key, env: :production # load from production env
|
564
|
+
|
565
|
+
# NOTE: in rails-like application you can use this:
|
566
|
+
expose_yaml 'config/project.yml', via: :env_key, env: Rails.env
|
567
|
+
end
|
568
|
+
|
569
|
+
config = Config.new
|
570
|
+
|
571
|
+
config.settings.enable_api_mode # => true (from :production subset of keys)
|
572
|
+
config.settings.google_key # => asd1-39sd-55aI-O92x (from :production subset of keys)
|
573
|
+
config.settings.window.width # => 50 (from :production subset of keys)
|
574
|
+
config.settings.window.height # => 150 (from :production subset of keys)
|
575
|
+
```
|
576
|
+
|
577
|
+
#### Environment is defined as a part of YAML file name
|
578
|
+
|
579
|
+
```yaml
|
580
|
+
# config/sidekiq.staging.yml
|
581
|
+
|
582
|
+
web:
|
583
|
+
username: staging_admin
|
584
|
+
password: staging_password
|
585
|
+
```
|
586
|
+
|
587
|
+
```yaml
|
588
|
+
# config/sidekiq.production.yml
|
589
|
+
|
590
|
+
web:
|
591
|
+
username: urj1o2
|
592
|
+
password: u192jd0ixz0
|
593
|
+
```
|
594
|
+
|
595
|
+
```ruby
|
596
|
+
class SidekiqConfig < Qonfig::DataSet
|
597
|
+
# NOTE: file name should be described WITHOUT environment part (in file name attribute)
|
598
|
+
expose_yaml 'config/sidekiq.yml', via: :file_name, env: :staging # load from staging env
|
599
|
+
|
600
|
+
# NOTE: in rails-like application you can use this:
|
601
|
+
expose_yaml 'config/sidekiq.yml', via: :file_name, env: Rails.env
|
602
|
+
end
|
603
|
+
|
604
|
+
config = SidekiqConfig.new
|
605
|
+
|
606
|
+
config.settings.web.username # => staging_admin (from sidekiq.staging.yml)
|
607
|
+
config.settings.web.password # => staging_password (from sidekiq.staging.yml)
|
608
|
+
```
|
609
|
+
|
610
|
+
---
|
611
|
+
|
612
|
+
### Load from JSON file
|
613
|
+
|
614
|
+
- `:strict` mode (fail behaviour when the required yaml file doesnt exist):
|
615
|
+
- `true` (by default) - causes `Qonfig::FileNotFoundError`;
|
616
|
+
- `false` - do nothing, ignore current command;
|
617
|
+
|
618
|
+
```json
|
619
|
+
// options.json
|
620
|
+
|
621
|
+
{
|
622
|
+
"user": "0exp",
|
623
|
+
"password": 12345,
|
624
|
+
"rubySettings": {
|
625
|
+
"allowedVersions": ["2.3", "2.4.2", "1.9.8"],
|
626
|
+
"gitLink": null,
|
627
|
+
"withAdditionals": false
|
628
|
+
}
|
629
|
+
}
|
630
|
+
```
|
631
|
+
|
632
|
+
```ruby
|
633
|
+
class Config < Qonfig::DataSet
|
634
|
+
load_from_json 'options.json'
|
635
|
+
end
|
636
|
+
|
637
|
+
config = Config.new
|
638
|
+
|
639
|
+
config.settings.user # => '0exp'
|
640
|
+
config.settings.password # => 12345
|
641
|
+
config.settings.rubySettings.allowedVersions # => ['2.3', '2.4.2', '1.9.8']
|
642
|
+
config.settings.rubySettings.gitLink # => nil
|
643
|
+
config.settings.rubySettings.withAdditionals # => false
|
644
|
+
```
|
645
|
+
|
646
|
+
```ruby
|
647
|
+
# --- strict mode ---
|
648
|
+
class Config < Qonfig::DataSet
|
649
|
+
setting :nonexistent_json do
|
650
|
+
load_from_json 'nonexistent_json.json', strict: true # true by default
|
651
|
+
end
|
652
|
+
|
653
|
+
setting :another_key
|
654
|
+
end
|
655
|
+
|
656
|
+
Config.new # => Qonfig::FileNotFoundError
|
657
|
+
|
658
|
+
# --- non-strict mode ---
|
659
|
+
class Config < Qonfig::DataSet
|
660
|
+
settings :nonexistent_json do
|
661
|
+
load_from_json 'nonexistent_json.json', strict: false
|
662
|
+
end
|
663
|
+
|
664
|
+
setting :another_key
|
665
|
+
end
|
666
|
+
|
667
|
+
Config.new.to_h # => { "nonexistent_json" => {}, "another_key" => nil }
|
668
|
+
```
|
669
|
+
|
670
|
+
---
|
671
|
+
|
672
|
+
### Load from ENV
|
673
|
+
|
674
|
+
- `:convert_values` (`false` by default):
|
675
|
+
- `'t'`, `'T'`, `'true'`, `'TRUE'` - covnerts to `true`;
|
676
|
+
- `'f'`, `'F'`, `'false'`, `'FALSE'` - covnerts to `false`;
|
677
|
+
- `1`, `23` and etc - converts to `Integer`;
|
678
|
+
- `1.25`, `0.26` and etc - converts to `Float`;
|
679
|
+
- `1, 2, test`, `FALSE,Qonfig` (strings without quotes that contains at least one comma) -
|
680
|
+
converts to `Array` with recursively converted values;
|
681
|
+
- `'"please, test"'`, `"'test, please'"` (quoted strings) - converts to `String` without quotes;
|
682
|
+
- `:prefix` - load ENV variables which names starts with a prefix:
|
683
|
+
- `nil` (by default) - empty prefix;
|
684
|
+
- `Regexp` - names that match the regexp pattern;
|
685
|
+
- `String` - names which starts with a passed string;
|
686
|
+
- `:trim_prefix` (`false` by default);
|
687
|
+
|
688
|
+
```ruby
|
689
|
+
# some env variables
|
690
|
+
ENV['QONFIG_BOOLEAN'] = 'true'
|
691
|
+
ENV['QONFIG_INTEGER'] = '0'
|
692
|
+
ENV['QONFIG_STRING'] = 'none'
|
693
|
+
ENV['QONFIG_ARRAY'] = '1, 2.5, t, f, TEST'
|
694
|
+
ENV['QONFIG_MESSAGE'] = '"Hello, Qonfig!"'
|
695
|
+
ENV['RUN_CI'] = '1'
|
696
|
+
|
697
|
+
class Config < Qonfig::DataSet
|
698
|
+
# nested
|
699
|
+
setting :qonfig do
|
700
|
+
load_from_env convert_values: true, prefix: 'QONFIG' # or /\Aqonfig.*\z/i
|
701
|
+
end
|
702
|
+
|
703
|
+
setting :trimmed do
|
704
|
+
load_from_env convert_values: true, prefix: 'QONFIG_', trim_prefix: true # trim prefix
|
705
|
+
end
|
706
|
+
|
707
|
+
# on the root
|
708
|
+
load_from_env
|
709
|
+
end
|
710
|
+
|
711
|
+
config = Config.new
|
712
|
+
|
713
|
+
# customized
|
714
|
+
config.settings['qonfig']['QONFIG_BOOLEAN'] # => true ('true' => true)
|
715
|
+
config.settings['qonfig']['QONFIG_INTEGER'] # => 0 ('0' => 0)
|
716
|
+
config.settings['qonfig']['QONFIG_STRING'] # => 'none'
|
717
|
+
config.settings['qonfig']['QONFIG_ARRAY'] # => [1, 2.5, true, false, 'TEST']
|
718
|
+
config.settings['qonfig']['QONFIG_MESSAGE'] # => 'Hello, Qonfig!'
|
719
|
+
config.settings['qonfig']['RUN_CI'] # => Qonfig::UnknownSettingError
|
720
|
+
|
721
|
+
# trimmed (and customized)
|
722
|
+
config.settings['trimmed']['BOOLEAN'] # => true ('true' => true)
|
723
|
+
config.settings['trimmed']['INTEGER'] # => 0 ('0' => 0)
|
724
|
+
config.settings['trimmed']['STRING'] # => 'none'
|
725
|
+
config.settings['trimmed']['ARRAY'] # => [1, 2.5, true, false, 'TEST']
|
726
|
+
config.settings['trimmed']['MESSAGE'] # => 'Hello, Qonfig!'
|
727
|
+
config.settings['trimmed']['RUN_CI'] # => Qonfig::UnknownSettingError
|
728
|
+
|
729
|
+
# default
|
730
|
+
config.settings['QONFIG_BOOLEAN'] # => 'true'
|
731
|
+
config.settings['QONFIG_INTEGER'] # => '0'
|
732
|
+
config.settings['QONFIG_STRING'] # => 'none'
|
733
|
+
config.settings['QONFIG_ARRAY'] # => '1, 2.5, t, f, TEST'
|
734
|
+
config.settings['QONFIG_MESSAGE'] # => '"Hello, Qonfig!"'
|
735
|
+
config.settings['RUN_CI'] # => '1'
|
736
|
+
```
|
737
|
+
|
738
|
+
---
|
739
|
+
|
740
|
+
### Load from \_\_END\_\_
|
741
|
+
|
742
|
+
- aka `load_from_self`
|
743
|
+
|
744
|
+
```ruby
|
745
|
+
class Config < Qonfig::DataSet
|
746
|
+
load_from_self # on the root
|
747
|
+
|
748
|
+
setting :nested do
|
749
|
+
load_from_self # nested
|
750
|
+
end
|
751
|
+
end
|
752
|
+
|
753
|
+
config = Config.new
|
754
|
+
|
755
|
+
# on the root
|
756
|
+
config.settings.ruby_version # => '2.5.1'
|
757
|
+
config.settings.secret_key # => 'top-mega-secret'
|
758
|
+
config.settings.api_host # => 'super.puper-google.com'
|
759
|
+
config.settings.connection_timeout.seconds # => 10
|
760
|
+
config.settings.connection_timeout.enabled # => false
|
761
|
+
|
762
|
+
# nested
|
763
|
+
config.settings.nested.ruby_version # => '2.5.1'
|
764
|
+
config.settings.nested.secret_key # => 'top-mega-secret'
|
765
|
+
config.settings.nested.api_host # => 'super.puper-google.com'
|
766
|
+
config.settings.nested.connection_timeout.seconds # => 10
|
767
|
+
config.settings.nested.connection_timeout.enabled # => false
|
768
|
+
|
769
|
+
__END__
|
770
|
+
|
771
|
+
ruby_version: <%= RUBY_VERSION %>
|
772
|
+
secret_key: top-mega-secret
|
773
|
+
api_host: super.puper-google.com
|
774
|
+
connection_timeout:
|
775
|
+
seconds: 10
|
776
|
+
enabled: false
|
777
|
+
```
|
778
|
+
|
779
|
+
---
|
780
|
+
|
781
|
+
### Save to JSON file
|
782
|
+
|
783
|
+
- `#save_to_json` - represents config object as a json structure and saves it to a file:
|
784
|
+
- uses native `::JSON.generate` under the hood;
|
785
|
+
- writes new file (or rewrites existing file);
|
786
|
+
- attributes:
|
787
|
+
- `:path` - (required) - file path;
|
788
|
+
- `:options` - (optional) - native `::JSON.generate` options (from stdlib):
|
789
|
+
- `:indent` - `" "` by default;
|
790
|
+
- `:space` - `" "` by default/
|
791
|
+
- `:object_nl` - `"\n"` by default;
|
792
|
+
- `&value_preprocessor` - (optional) - value pre-processor;
|
793
|
+
|
794
|
+
#### Without value preprocessing (standard usage)
|
795
|
+
|
796
|
+
```ruby
|
797
|
+
class AppConfig < Qonfig::DataSet
|
798
|
+
setting :server do
|
799
|
+
setting :address, 'localhost'
|
800
|
+
setting :port, 12_345
|
801
|
+
end
|
802
|
+
|
803
|
+
setting :enabled, true
|
804
|
+
end
|
805
|
+
|
806
|
+
config = AppConfig.new
|
807
|
+
|
808
|
+
# NOTE: save to json file
|
809
|
+
config.save_to_json(path: 'config.json')
|
810
|
+
```
|
811
|
+
|
812
|
+
```json
|
813
|
+
{
|
814
|
+
"sentry": {
|
815
|
+
"address": "localhost",
|
816
|
+
"port": 12345
|
817
|
+
},
|
818
|
+
"enabled": true
|
819
|
+
}
|
820
|
+
```
|
821
|
+
|
822
|
+
#### With value preprocessing and custom options
|
823
|
+
|
824
|
+
```ruby
|
825
|
+
class AppConfig < Qonfig::DataSet
|
826
|
+
setting :server do
|
827
|
+
setting :address, 'localhost'
|
828
|
+
setting :port, 12_345
|
829
|
+
end
|
830
|
+
|
831
|
+
setting :enabled, true
|
832
|
+
setting :dynamic, -> { 1 + 2 }
|
833
|
+
end
|
834
|
+
|
835
|
+
config = AppConfig.new
|
836
|
+
|
837
|
+
# NOTE: save to json file with custom options (no spaces / no new line / no indent; call procs)
|
838
|
+
config.save_to_json(path: 'config.json', options: { indent: '', space: '', object_nl: '' }) do |value|
|
839
|
+
value.is_a?(Proc) ? value.call : value
|
840
|
+
end
|
841
|
+
```
|
842
|
+
|
843
|
+
```json
|
844
|
+
// no spaces / no new line / no indent / calculated "dynamic" setting key
|
845
|
+
{"sentry":{"address":"localhost","port":12345},"enabled":true,"dynamic":3}
|
846
|
+
```
|
847
|
+
|
848
|
+
---
|
849
|
+
|
850
|
+
### Save to YAML file
|
851
|
+
|
852
|
+
- `#save_to_yaml` - represents config object as a yaml structure and saves it to a file:
|
853
|
+
- uses native `::Psych.dump` under the hood;
|
854
|
+
- writes new file (or rewrites existing file);
|
855
|
+
- attributes:
|
856
|
+
- `:path` - (required) - file path;
|
857
|
+
- `:options` - (optional) - native `::Psych.dump` options (from stdlib):
|
858
|
+
- `:indentation` - `2` by default;
|
859
|
+
- `:line_width` - `-1` by default;
|
860
|
+
- `:canonical` - `false` by default;
|
861
|
+
- `:header` - `false` by default;
|
862
|
+
- `:symbolize_keys` - (non-native option) - `false` by default;
|
863
|
+
- `&value_preprocessor` - (optional) - value pre-processor;
|
864
|
+
|
865
|
+
#### Without value preprocessing (standard usage)
|
866
|
+
|
867
|
+
```ruby
|
868
|
+
class AppConfig < Qonfig::DataSet
|
869
|
+
setting :server do
|
870
|
+
setting :address, 'localhost'
|
871
|
+
setting :port, 12_345
|
872
|
+
end
|
873
|
+
|
874
|
+
setting :enabled, true
|
875
|
+
end
|
876
|
+
|
877
|
+
config = AppConfig.new
|
878
|
+
|
879
|
+
# NOTE: save to yaml file
|
880
|
+
config.save_to_yaml(path: 'config.yml')
|
881
|
+
```
|
882
|
+
|
883
|
+
```yaml
|
884
|
+
---
|
885
|
+
server:
|
886
|
+
address: localhost
|
887
|
+
port: 12345
|
888
|
+
enabled: true
|
889
|
+
```
|
890
|
+
|
891
|
+
#### With value preprocessing and custom options
|
892
|
+
|
893
|
+
```ruby
|
894
|
+
class AppConfig < Qonfig::DataSet
|
895
|
+
setting :server do
|
896
|
+
setting :address, 'localhost'
|
897
|
+
setting :port, 12_345
|
898
|
+
end
|
899
|
+
|
900
|
+
setting :enabled, true
|
901
|
+
setting :dynamic, -> { 5 + 5 }
|
902
|
+
end
|
903
|
+
|
904
|
+
config = AppConfig.new
|
905
|
+
|
906
|
+
# NOTE: save to yaml file with custom options (add yaml version header; call procs)
|
907
|
+
config.save_to_yaml(path: 'config.yml', options: { header: true }) do |value|
|
908
|
+
value.is_a?(Proc) ? value.call : value
|
909
|
+
end
|
910
|
+
```
|
911
|
+
|
912
|
+
```yaml
|
913
|
+
# yaml version header / calculated "dynamic" setting key
|
914
|
+
%YAML 1.1
|
915
|
+
---
|
916
|
+
server:
|
917
|
+
address: localhost
|
918
|
+
port: 12345
|
919
|
+
enabled: true
|
920
|
+
dynamic: 10
|
921
|
+
```
|
922
|
+
|
923
|
+
---
|
924
|
+
|
925
|
+
### Smart Mixin
|
926
|
+
|
927
|
+
- class-level:
|
928
|
+
- `.configuration` - settings definitions;
|
929
|
+
- `.configure` - configuration;
|
930
|
+
- `.config` - config object;
|
931
|
+
- settings definitions are inheritable;
|
932
|
+
- instance-level:
|
933
|
+
- `#configure` - configuration;
|
934
|
+
- `#config` - config object;
|
935
|
+
- `#shared_config` - class-level config object;
|
936
|
+
|
937
|
+
```ruby
|
938
|
+
# --- usage ---
|
939
|
+
|
940
|
+
class Application
|
941
|
+
# make configurable
|
942
|
+
include Qonfig::Configurable
|
943
|
+
|
944
|
+
configuration do
|
945
|
+
setting :user
|
946
|
+
setting :password
|
947
|
+
end
|
948
|
+
end
|
949
|
+
|
950
|
+
app = Application.new
|
951
|
+
|
952
|
+
# class-level config
|
953
|
+
Application.config.settings.user # => nil
|
954
|
+
Application.config.settings.password # => nil
|
955
|
+
|
956
|
+
# instance-level config
|
957
|
+
app.config.settings.user # => nil
|
958
|
+
app.config.settings.password # => nil
|
959
|
+
|
960
|
+
# access to the class level config from an instance
|
961
|
+
app.shared_config.settings.user # => nil
|
962
|
+
app.shared_config.settings.password # => nil
|
963
|
+
|
964
|
+
# class-level configuration
|
965
|
+
Application.configure do |conf|
|
966
|
+
conf.user = '0exp'
|
967
|
+
conf.password = 'test123'
|
968
|
+
end
|
969
|
+
|
970
|
+
# instance-level configuration
|
971
|
+
app.configure do |conf|
|
972
|
+
conf.user = 'admin'
|
973
|
+
conf.password = '123test'
|
974
|
+
end
|
975
|
+
|
976
|
+
# class has own config object
|
977
|
+
Application.config.settings.user # => '0exp'
|
978
|
+
Application.config.settings.password # => 'test123'
|
979
|
+
|
980
|
+
# instance has own config object
|
981
|
+
app.config.settings.user # => 'admin'
|
982
|
+
app.config.settings.password # => '123test'
|
983
|
+
|
984
|
+
# access to the class level config from an instance
|
985
|
+
app.shared_config.settings.user # => '0exp'
|
986
|
+
app.shared_config.settings.password # => 'test123'
|
987
|
+
|
988
|
+
# and etc... (all Qonfig-related features)
|
989
|
+
```
|
990
|
+
|
991
|
+
```ruby
|
992
|
+
# --- inheritance ---
|
993
|
+
|
994
|
+
class BasicApplication
|
995
|
+
# make configurable
|
996
|
+
include Qonfig::Configurable
|
997
|
+
|
998
|
+
configuration do
|
999
|
+
setting :user
|
1000
|
+
setting :pswd
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
configure do |conf|
|
1004
|
+
conf.user = 'admin'
|
1005
|
+
conf.pswd = 'admin'
|
1006
|
+
end
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
class GeneralApplication < BasicApplication
|
1010
|
+
# extend inherited definitions
|
1011
|
+
configuration do
|
1012
|
+
setting :db do
|
1013
|
+
setting :adapter
|
1014
|
+
end
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
configure do |conf|
|
1018
|
+
conf.user = '0exp' # .user inherited from BasicApplication
|
1019
|
+
conf.pswd = '123test' # .pswd inherited from BasicApplication
|
1020
|
+
conf.db.adapter = 'pg'
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
BasicApplication.config.to_h
|
1025
|
+
{ 'user' => 'admin', 'pswd' => 'admin' }
|
1026
|
+
|
1027
|
+
GeneralApplication.config.to_h
|
1028
|
+
{ 'user' => '0exp', 'pswd' => '123test', 'db' => { 'adapter' => 'pg' } }
|
1029
|
+
|
1030
|
+
# and etc... (all Qonfig-related features)
|
1031
|
+
```
|
1032
|
+
|
1033
|
+
---
|
1034
|
+
|
1035
|
+
### Plugins
|
1036
|
+
|
1037
|
+
```ruby
|
1038
|
+
# --- show names of registered plugins ---
|
1039
|
+
Qonfig.plugins # => array of strings
|
1040
|
+
|
1041
|
+
# --- load specific plugin ---
|
1042
|
+
Qonfig.plugin(:plugin_name) # or Qonfig.plugin('plugin_name')
|
1043
|
+
```
|
1044
|
+
|
1045
|
+
---
|
1046
|
+
|
1047
|
+
### Plugins: toml
|
1048
|
+
|
1049
|
+
- adds support for `toml` format ([specification](https://github.com/toml-lang/toml));
|
1050
|
+
- depends on `toml-rb` gem;
|
1051
|
+
- provides `load_from_toml` (works in `load_from_yaml` manner [doc](#load-from-yaml-file));
|
1052
|
+
- provides `save_to_toml` (works in `save_to_yaml` manner [doc](#save-to-yaml-file)) (`toml-rb` has no native options);
|
1053
|
+
- provides `expose_toml` (works in `expose_yaml` manner [doc](#expose-yaml));
|
1054
|
+
|
1055
|
+
```ruby
|
1056
|
+
require 'toml-rb'
|
1057
|
+
Qonfig.plugin(:toml)
|
1058
|
+
# and use :)
|
1059
|
+
```
|
1060
|
+
---
|
28
1061
|
|
29
|
-
|
1062
|
+
## Roadmap
|
30
1063
|
|
31
|
-
|
1064
|
+
- support for TOML format;
|
1065
|
+
- explicit "settings" object;
|
1066
|
+
- validation layer;
|
1067
|
+
- distributed configuration server;
|
1068
|
+
- support for Rails-like secrets;
|
32
1069
|
|
33
1070
|
## Contributing
|
34
1071
|
|
35
|
-
|
1072
|
+
- Fork it ( https://github.com/0exp/qonfig/fork )
|
1073
|
+
- Create your feature branch (`git checkout -b feature/my-new-feature`)
|
1074
|
+
- Commit your changes (`git commit -am 'Add some feature'`)
|
1075
|
+
- Push to the branch (`git push origin feature/my-new-feature`)
|
1076
|
+
- Create new Pull Request
|
36
1077
|
|
37
1078
|
## License
|
38
1079
|
|
39
|
-
|
1080
|
+
Released under MIT License.
|
40
1081
|
|
41
|
-
##
|
1082
|
+
## Authors
|
42
1083
|
|
43
|
-
|
1084
|
+
[Rustam Ibragimov](https://github.com/0exp)
|