qonfig 0.16.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -1
- data/.travis.yml +6 -6
- data/CHANGELOG.md +17 -0
- data/README.md +630 -49
- data/gemfiles/with_external_deps.gemfile +2 -2
- data/lib/qonfig/commands/{add_nested_option.rb → definition/add_nested_option.rb} +1 -1
- data/lib/qonfig/commands/{add_option.rb → definition/add_option.rb} +1 -1
- data/lib/qonfig/commands/{compose.rb → definition/compose.rb} +1 -1
- data/lib/qonfig/commands/{expose_json.rb → definition/expose_json.rb} +1 -1
- data/lib/qonfig/commands/{expose_self.rb → definition/expose_self.rb} +1 -1
- data/lib/qonfig/commands/{expose_yaml.rb → definition/expose_yaml.rb} +1 -1
- data/lib/qonfig/commands/definition/load_from_env/value_converter.rb +82 -0
- data/lib/qonfig/commands/{load_from_env.rb → definition/load_from_env.rb} +1 -1
- data/lib/qonfig/commands/{load_from_json.rb → definition/load_from_json.rb} +1 -1
- data/lib/qonfig/commands/{load_from_self.rb → definition/load_from_self.rb} +1 -1
- data/lib/qonfig/commands/{load_from_yaml.rb → definition/load_from_yaml.rb} +1 -1
- data/lib/qonfig/commands/definition.rb +16 -0
- data/lib/qonfig/commands/instantiation/values_file.rb +171 -0
- data/lib/qonfig/commands/instantiation.rb +7 -0
- data/lib/qonfig/commands.rb +2 -10
- data/lib/qonfig/data_set/lock.rb +61 -4
- data/lib/qonfig/data_set.rb +151 -3
- data/lib/qonfig/dsl.rb +56 -16
- data/lib/qonfig/errors.rb +38 -11
- data/lib/qonfig/loaders/dynamic.rb +52 -0
- data/lib/qonfig/loaders/json.rb +6 -0
- data/lib/qonfig/loaders/yaml.rb +13 -0
- data/lib/qonfig/loaders.rb +3 -0
- data/lib/qonfig/plugins/toml/data_set.rb +13 -0
- data/lib/qonfig/plugins/toml/dsl.rb +6 -2
- data/lib/qonfig/plugins/toml/errors.rb +12 -0
- data/lib/qonfig/plugins/toml/loaders/dynamic.rb +31 -0
- data/lib/qonfig/plugins/toml/loaders/toml.rb +6 -0
- data/lib/qonfig/plugins/toml.rb +2 -0
- data/lib/qonfig/settings/builder.rb +1 -1
- data/lib/qonfig/settings.rb +21 -0
- data/lib/qonfig/validator/basic.rb +9 -1
- data/lib/qonfig/validator/builder/attribute_consistency.rb +29 -0
- data/lib/qonfig/validator/builder.rb +39 -14
- data/lib/qonfig/validator/dsl.rb +9 -1
- data/lib/qonfig/validator/method_based.rb +4 -2
- data/lib/qonfig/validator/predefined/common.rb +4 -2
- data/lib/qonfig/validator/predefined/registry.rb +0 -2
- data/lib/qonfig/validator/predefined/registry_control_mixin.rb +3 -2
- data/lib/qonfig/validator/proc_based.rb +4 -2
- data/lib/qonfig/version.rb +1 -1
- data/qonfig.gemspec +1 -1
- metadata +21 -15
- data/lib/qonfig/commands/load_from_env/value_converter.rb +0 -84
data/README.md
CHANGED
@@ -25,12 +25,18 @@ require 'qonfig'
|
|
25
25
|
- [Definition](#definition)
|
26
26
|
- [Definition and Settings Access](#definition-and-access)
|
27
27
|
- [access via method](#access-via-method)
|
28
|
-
- [index-method](#index-method)
|
28
|
+
- [access via index-method \[\]](#access-via-index-method-)
|
29
29
|
- [.dig](#dig)
|
30
30
|
- [.slice](#slice)
|
31
31
|
- [.slice_value](#slice_value)
|
32
32
|
- [.subset](#subset)
|
33
33
|
- [Configuration](#configuration)
|
34
|
+
- [configure via proc](#configure-via-proc)
|
35
|
+
- [configure via settings object (by option name)](#configure-via-settings-object-by-option-name)
|
36
|
+
- [configure via settings object (by setting key)](#configure-via-settings-object-by-setting-key)
|
37
|
+
- [instant configuration via proc](#instant-configuration-via-proc)
|
38
|
+
- [using a hash](#using-a-hash)
|
39
|
+
- [using both hash and proc](#using-both-hash-and-proc-proc-has-higher-priority)
|
34
40
|
- [Inheritance](#inheritance)
|
35
41
|
- [Composition](#composition)
|
36
42
|
- [Hash representation](#hash-representation)
|
@@ -39,25 +45,35 @@ require 'qonfig'
|
|
39
45
|
- [Interaction](#interaction)
|
40
46
|
- [Iteration over setting keys](#iteration-over-setting-keys) (`#each_setting`, `#deep_each_setting`)
|
41
47
|
- [Config reloading](#config-reloading) (reload config definitions and option values)
|
42
|
-
- [Clear options](#clear-options) (set to nil)
|
48
|
+
- [Clear options](#clear-options) (set to `nil`)
|
43
49
|
- [State freeze](#state-freeze)
|
44
50
|
- [Settings as Predicates](#settings-as-predicates)
|
51
|
+
- [Setting key existence](#setting-key-existence) (`#key?`/`#option?`/`#setting?`)
|
52
|
+
- [Run arbitary code with temporary settings](#run-arbitary-code-with-temporary-settings) (`#with(configs = {}, &arbitary_code)`)
|
45
53
|
- [Validation](#validation)
|
46
|
-
- [Introduction](#
|
54
|
+
- [Introduction](#introduction)
|
47
55
|
- [Key search pattern](#key-search-pattern)
|
48
56
|
- [Proc-based validation](#proc-based-validation)
|
49
57
|
- [Method-based validation](#method-based-validation)
|
50
58
|
- [Predefined validations](#predefined-validations)
|
51
59
|
- [Work with files](#work-with-files)
|
52
|
-
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
-
|
60
|
+
- **Setting keys definition**
|
61
|
+
- [Load from YAML file](#load-from-yaml-file)
|
62
|
+
- [Expose YAML](#expose-yaml) (`Rails`-like environment-based YAML configs)
|
63
|
+
- [Load from JSON file](#load-from-json-file)
|
64
|
+
- [Expose JSON](#expose-json) (`Rails`-like environment-based JSON configs)
|
65
|
+
- [Load from ENV](#load-from-env)
|
66
|
+
- [Load from \_\_END\_\_](#load-from-__end__) (aka `.load_from_self`)
|
67
|
+
- [Expose \_\_END\_\_](#expose-__end__) (aka `.expose_self`)
|
68
|
+
- **Setting values**
|
69
|
+
- [Default setting values file](#default-setting-values-file)
|
70
|
+
- [Load setting values from YAML file](#load-setting-values-from-yaml-file-by-instance)
|
71
|
+
- [Load setting values from JSON file](#load-setting-values-from-json-file-by-instance)
|
72
|
+
- [Load setting values from \_\_END\_\_](#load-setting-values-from-__end__-by-instance)
|
73
|
+
- [Load setting values from file manually](#load-setting-values-from-file-manually-by-instance)
|
74
|
+
- **Daily work**
|
75
|
+
- [Save to JSON file](#save-to-json-file) (`#save_to_json`)
|
76
|
+
- [Save to YAML file](#save-to-yaml-file) (`#save_to_yaml`)
|
61
77
|
- [Plugins](#plugins)
|
62
78
|
- [toml](#plugins-toml) (provides `load_from_toml`, `save_to_toml`, `expose_toml`)
|
63
79
|
- [Roadmap](#roadmap)
|
@@ -116,7 +132,7 @@ config.settings.vendor_api.user # => 'test_user'
|
|
116
132
|
config.settings.enable_graphql # => false
|
117
133
|
```
|
118
134
|
|
119
|
-
#### index-method []
|
135
|
+
#### access via index-method []
|
120
136
|
|
121
137
|
```ruby
|
122
138
|
# get option value via index (with indifferent (string / symbol / mixed) access)
|
@@ -200,40 +216,58 @@ class Config < Qonfig::DataSet
|
|
200
216
|
end
|
201
217
|
|
202
218
|
config = Config.new
|
219
|
+
```
|
203
220
|
|
204
|
-
|
221
|
+
#### configure via proc
|
222
|
+
|
223
|
+
```ruby
|
205
224
|
config.configure do |conf|
|
206
225
|
conf.enable_middlewares = true
|
207
226
|
conf.geo_api.provider = :yandex_maps
|
208
227
|
conf.testing.engine = :mini_test
|
209
228
|
end
|
229
|
+
```
|
210
230
|
|
211
|
-
|
231
|
+
#### configure via settings object (by option name)
|
232
|
+
|
233
|
+
```ruby
|
212
234
|
config.settings.enable_middlewares = false
|
213
235
|
config.settings.geo_api.provider = :apple_maps
|
214
236
|
config.settings.testing.engine = :ultra_test
|
237
|
+
```
|
238
|
+
|
239
|
+
#### configure via settings object (by setting key)
|
215
240
|
|
216
|
-
|
241
|
+
```ruby
|
217
242
|
config.settings[:enable_middlewares] = true
|
218
243
|
config.settings[:geo_api][:provider] = :rambler_maps
|
219
244
|
config.settings[:testing][:engine] = :mega_test
|
245
|
+
```
|
220
246
|
|
221
|
-
|
247
|
+
#### instant configuration via proc
|
248
|
+
|
249
|
+
```ruby
|
222
250
|
config = Config.new do |conf|
|
223
251
|
conf.enable_middlewares = false
|
224
252
|
conf.geo_api.provider = :amazon_maps
|
225
253
|
conf.testing.engine = :crypto_test
|
226
254
|
end
|
255
|
+
```
|
227
256
|
|
228
|
-
|
257
|
+
#### using a hash
|
258
|
+
|
259
|
+
```ruby
|
229
260
|
config = Config.new(
|
230
261
|
testing: { engine: :mini_test, parallel: false },
|
231
262
|
geo_api: { provider: :rambler_maps },
|
232
263
|
enable_middlewares: true
|
233
264
|
)
|
234
265
|
config.configure(enable_middlewares: false)
|
266
|
+
```
|
267
|
+
|
268
|
+
#### using both hash and proc (proc has higher priority)
|
235
269
|
|
236
|
-
|
270
|
+
```ruby
|
237
271
|
config = Config.new(enable_middlewares: true) do |conf|
|
238
272
|
conf.testing.parallel = true
|
239
273
|
end
|
@@ -455,18 +489,25 @@ GeneralApplication.config.to_h
|
|
455
489
|
# and etc... (all Qonfig-related features)
|
456
490
|
```
|
457
491
|
|
492
|
+
---
|
493
|
+
|
458
494
|
### Instantiation without class definition
|
459
495
|
|
460
496
|
```ruby
|
461
497
|
config = Qonfig::DataSet.build do
|
462
498
|
setting :user, 'D@iVeR'
|
463
499
|
setting :password, 'test123'
|
500
|
+
|
501
|
+
def custom_method
|
502
|
+
'custom_result'
|
503
|
+
end
|
464
504
|
end
|
465
505
|
|
466
506
|
config.is_a?(Qonfig::DataSet) # => true
|
467
507
|
|
468
508
|
config.settings.user # => 'D@iVeR'
|
469
509
|
config.settings.password # => 'test123'
|
510
|
+
config.custom_method # => 'custom_result'
|
470
511
|
```
|
471
512
|
|
472
513
|
---
|
@@ -478,6 +519,8 @@ config.settings.password # => 'test123'
|
|
478
519
|
- [Clear options](#clear-options) (set to nil)
|
479
520
|
- [State freeze](#state-freeze)
|
480
521
|
- [Settings as Predicates](#settings-as-predicates)
|
522
|
+
- [Setting key existence](#setting-key-existence) (`#key?`/`#option?`/`#setting?`)
|
523
|
+
- [Run arbitary code with temporary settings](#run-arbitary-code-with-temporary-settings)
|
481
524
|
|
482
525
|
---
|
483
526
|
|
@@ -682,6 +725,72 @@ config.settings.database.engine.driver? # => true (true => true)
|
|
682
725
|
|
683
726
|
---
|
684
727
|
|
728
|
+
### Setting key existence
|
729
|
+
|
730
|
+
- `#key?(*key_path)` / `#option?(*key_path)` / `#setting?(*key_path)`
|
731
|
+
- `*key_path` - an array of symbols and strings that represents a path to the concrete setting key;
|
732
|
+
- (for example, `config.key?(:credentials, :user)` tries to check that `config.settings.credentials.user` is exist);
|
733
|
+
- returns `true` if the concrete key is exist;
|
734
|
+
- returns `false` if the concrete key does not exist;
|
735
|
+
|
736
|
+
```ruby
|
737
|
+
class Config < Qonfig::DataSet
|
738
|
+
setting :credentials do
|
739
|
+
setting :user, 'D@iVeR'
|
740
|
+
setting :password, 'test123'
|
741
|
+
end
|
742
|
+
end
|
743
|
+
|
744
|
+
config = Config.new
|
745
|
+
|
746
|
+
config.key?('credentials', 'user') # => true
|
747
|
+
config.key?('credentials', 'token') # => false (key does not exist)
|
748
|
+
|
749
|
+
config.key?('credentials') # => true
|
750
|
+
config.key?('que_adapter') # => false (key does not exist)
|
751
|
+
|
752
|
+
# aliases
|
753
|
+
config.setting?('credentials') # => true
|
754
|
+
config.option?(:credentials, :password) # => true
|
755
|
+
```
|
756
|
+
|
757
|
+
---
|
758
|
+
|
759
|
+
### Run arbitary code with temporary settings
|
760
|
+
|
761
|
+
- provides a way to run an arbitary code with temporarily specified settings;
|
762
|
+
- your arbitary code can temporary change any setting too - all settings will be returned to the original state;
|
763
|
+
- (it is convenient to run code samples by this way in tests (with substitued configs));
|
764
|
+
- it is fully thread-safe `:)`;
|
765
|
+
|
766
|
+
```ruby
|
767
|
+
class Config < Qonfig::DataSet
|
768
|
+
setting :queue do
|
769
|
+
setting :adapter, :sidekiq
|
770
|
+
setting :options, {}
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
config = Config.new
|
775
|
+
|
776
|
+
# run a block of code with temporary queue.adapter setting
|
777
|
+
config.with(queue: { adapter: 'que' }) do
|
778
|
+
# your changed settings
|
779
|
+
config.settings.queue.adapter # => 'que'
|
780
|
+
|
781
|
+
# you can temporary change settings by your code too
|
782
|
+
config.settings.queue.options = { concurrency: 10 }
|
783
|
+
|
784
|
+
# ...your another code...
|
785
|
+
end
|
786
|
+
|
787
|
+
# original settings has not changed :)
|
788
|
+
config.settings.queue.adapter # => :sidekiq
|
789
|
+
config.settings.queue.options # => {}
|
790
|
+
```
|
791
|
+
|
792
|
+
---
|
793
|
+
|
685
794
|
## Validation
|
686
795
|
|
687
796
|
- [Introduction](#introduction)
|
@@ -705,34 +814,38 @@ If you want to check the config object completely you can define a custom valida
|
|
705
814
|
- when assigning new values;
|
706
815
|
- when calling `#reload!`;
|
707
816
|
- when calling `#clear!`;
|
817
|
+
- provides `strict` and `non-strict` behavior (`strict: true` and `strict: false` respectively):
|
818
|
+
- `strict: false` ignores validations for settings with `nil` (allows `nil` value);
|
819
|
+
- `strict: true` does not ignores validations for settings with `nil`;
|
820
|
+
- `strict: false` is used by default;
|
708
821
|
- provides special [key search pattern](#key-search-pattern) for matching setting key names;
|
709
822
|
- uses the [key search pattern](#key-search-pattern) for definging what the setting key should be validated;
|
710
823
|
- you can define your own custom validation logic and validate dataset instance completely;
|
711
824
|
- validation logic should return **truthy** or **falsy** value;
|
712
825
|
- supprots two validation techniques (**proc-based** ([doc](#proc-based-validation)) and **dataset-method-based** ([doc](#method-based-validation))):
|
713
|
-
- **proc-based** (`setting validation`)
|
826
|
+
- **proc-based** (`setting validation`) ([doc](#proc-based-validation))
|
714
827
|
```ruby
|
715
|
-
validate
|
828
|
+
validate('db.user', strict: true) do |value|
|
716
829
|
value.is_a?(String)
|
717
830
|
end
|
718
831
|
```
|
719
|
-
- **proc-based** (`dataset validation`)
|
832
|
+
- **proc-based** (`dataset validation`) ([doc](#proc-based-validation))
|
720
833
|
```ruby
|
721
|
-
validate do
|
834
|
+
validate(strict: false) do
|
722
835
|
settings.user == User[1]
|
723
836
|
end
|
724
837
|
```
|
725
|
-
- **dataset-method-based** (`setting validation`)
|
838
|
+
- **dataset-method-based** (`setting validation`) ([doc](#method-based-validation))
|
726
839
|
```ruby
|
727
|
-
validate 'db.user', by: :check_user
|
840
|
+
validate 'db.user', by: :check_user, strict: true
|
728
841
|
|
729
842
|
def check_user(value)
|
730
843
|
value.is_a?(String)
|
731
844
|
end
|
732
845
|
```
|
733
|
-
- **dataset-method-based** (`dataset validation`)
|
846
|
+
- **dataset-method-based** (`dataset validation`) ([doc](#method-based-validation))
|
734
847
|
```ruby
|
735
|
-
validate by: :check_config
|
848
|
+
validate by: :check_config, strict: false
|
736
849
|
|
737
850
|
def check_config
|
738
851
|
settings.user == User[1]
|
@@ -740,7 +853,8 @@ If you want to check the config object completely you can define a custom valida
|
|
740
853
|
```
|
741
854
|
- provides a **set of standard validations** ([doc](#predefined-validations)):
|
742
855
|
- DSL: `validate 'key.pattern', :predefned_validator`;
|
743
|
-
-
|
856
|
+
- supports `strict` behavior;
|
857
|
+
- realized validators:
|
744
858
|
- `integer`
|
745
859
|
- `float`
|
746
860
|
- `numeric`
|
@@ -782,11 +896,13 @@ If you want to check the config object completely you can define a custom valida
|
|
782
896
|
### Proc-based validation
|
783
897
|
|
784
898
|
- your proc should return truthy value or falsy value;
|
899
|
+
- `nil` values are ignored by default;
|
900
|
+
- set `strict: true` to disable `nil` ignorance (`strict: false` is used by default);
|
785
901
|
- how to validate setting keys:
|
786
902
|
- define proc with attribute: `validate 'your.setting.path' do |value|; end`
|
787
903
|
- proc will receive setting value;
|
788
904
|
- how to validate dataset instance:
|
789
|
-
- define proc without setting key pattern: `validate do; end
|
905
|
+
- define proc without setting key pattern: `validate do; end`;
|
790
906
|
|
791
907
|
```ruby
|
792
908
|
class Config < Qonfig::DataSet
|
@@ -805,6 +921,7 @@ class Config < Qonfig::DataSet
|
|
805
921
|
end
|
806
922
|
|
807
923
|
setting :enabled, false
|
924
|
+
setting :token, '1a2a3a', strict: true
|
808
925
|
|
809
926
|
# validates:
|
810
927
|
# - db.password
|
@@ -825,6 +942,11 @@ class Config < Qonfig::DataSet
|
|
825
942
|
validate do # NOTE: no setting key pattern
|
826
943
|
settings.enabled == false
|
827
944
|
end
|
945
|
+
|
946
|
+
# do not ignore `nil` (strict: true)
|
947
|
+
validate(:token, strict: true) do
|
948
|
+
value.is_a?(String)
|
949
|
+
end
|
828
950
|
end
|
829
951
|
|
830
952
|
config = Config.new
|
@@ -833,6 +955,9 @@ config.settings.service.address = 123 # => Qonfig::ValidationError (should be a
|
|
833
955
|
config.settings.service.protocol = :http # => Qonfig::ValidationError (should be a string)
|
834
956
|
config.settings.service.creds.admin = :billikota # => Qonfig::ValidationError (should be a string)
|
835
957
|
config.settings.enabled = true # => Qonfig::ValidationError (isnt `true`)
|
958
|
+
|
959
|
+
config.settings.db.password = nil # ok, nil is ignored (non-strict behavior)
|
960
|
+
config.settings.token = nil # => Qonfig::ValidationError (nil is not ignored, strict behavior) (should be a type of string)
|
836
961
|
```
|
837
962
|
|
838
963
|
---
|
@@ -840,6 +965,8 @@ config.settings.enabled = true # => Qonfig::ValidationError (isnt `true`)
|
|
840
965
|
### Method-based validation
|
841
966
|
|
842
967
|
- method should return truthy value or falsy value;
|
968
|
+
- `nil` values are ignored by default;
|
969
|
+
- set `strict: true` to disable `nil` ignorance (`strict: false` is used by default);
|
843
970
|
- how to validate setting keys:
|
844
971
|
- define validation: `validate 'db.*.user', by: :your_custom_method`;
|
845
972
|
- define your method with attribute: `def your_custom_method(setting_value); end`
|
@@ -862,6 +989,7 @@ class Config < Qonfig::DataSet
|
|
862
989
|
end
|
863
990
|
|
864
991
|
setting :enabled, true
|
992
|
+
setting :timeout, 12345, strict: true
|
865
993
|
|
866
994
|
# validates:
|
867
995
|
# - services.counts.google
|
@@ -874,6 +1002,9 @@ class Config < Qonfig::DataSet
|
|
874
1002
|
# - dataset instance
|
875
1003
|
validate by: :check_state # NOTE: no setting key pattern
|
876
1004
|
|
1005
|
+
# do not ignore `nil` (strict: true)
|
1006
|
+
validate :timeout, strict: true, by: :check_timeout
|
1007
|
+
|
877
1008
|
def check_presence(value)
|
878
1009
|
value.is_a?(Numeric) && value > 0
|
879
1010
|
end
|
@@ -881,15 +1012,21 @@ class Config < Qonfig::DataSet
|
|
881
1012
|
def check_state
|
882
1013
|
settings.enabled.is_a?(TrueClass) || settings.enabled.is_a?(FalseClass)
|
883
1014
|
end
|
1015
|
+
|
1016
|
+
def check_timeout(value)
|
1017
|
+
value.is_a?(Numeric)
|
1018
|
+
end
|
884
1019
|
end
|
885
1020
|
|
886
1021
|
config = Config.new
|
887
1022
|
|
888
1023
|
config.settings.counts.google = 0 # => Qonfig::ValidationError (< 0)
|
889
|
-
config.settings.counts.rambler = nil # => Qonfig::ValidationError (should be a numeric)
|
890
1024
|
config.settings.minimals.google = -1 # => Qonfig::ValidationError (< 0)
|
891
1025
|
config.settings.minimals.rambler = 'no' # => Qonfig::ValidationError (should be a numeric)
|
892
|
-
|
1026
|
+
|
1027
|
+
config.settings.counts.rambler = nil # ok, nil is ignored (default non-strict behavior)
|
1028
|
+
config.settings.enabled = nil # ok, nil is ignored (default non-strict behavior)
|
1029
|
+
config.settings.timeout = nil # => Qonfig::ValidationError (nil is not ignored, strict behavior) (should be a type of numeric)
|
893
1030
|
```
|
894
1031
|
|
895
1032
|
---
|
@@ -897,6 +1034,8 @@ config.settings.enabled = nil # => Qonfig::ValidationError (should be a boolean)
|
|
897
1034
|
### Predefined validations
|
898
1035
|
|
899
1036
|
- DSL: `validate 'key.pattern', :predefned_validator`
|
1037
|
+
- `nil` values are ignored by default;
|
1038
|
+
- set `strict: true` to disable `nil` ignorance (`strict: false` is used by default);
|
900
1039
|
- predefined validators:
|
901
1040
|
- `:not_nil`
|
902
1041
|
- `:integer`
|
@@ -948,15 +1087,23 @@ config.settings.ignorance = nil # => Qonfig::ValidationError (cant be nil)
|
|
948
1087
|
|
949
1088
|
## Work with files
|
950
1089
|
|
951
|
-
-
|
952
|
-
- [
|
953
|
-
- [
|
954
|
-
- [
|
955
|
-
- [
|
956
|
-
- [Load from
|
957
|
-
- [
|
958
|
-
- [
|
959
|
-
-
|
1090
|
+
- **Setting keys definition**
|
1091
|
+
- [Load from YAML file](#load-from-yaml-file)
|
1092
|
+
- [Expose YAML](#expose-yaml) (`Rails`-like environment-based YAML configs)
|
1093
|
+
- [Load from JSON file](#load-from-json-file)
|
1094
|
+
- [Expose JSON](#expose-json) (`Rails`-like environment-based JSON configs)
|
1095
|
+
- [Load from ENV](#load-from-env)
|
1096
|
+
- [Load from \_\_END\_\_](#load-from-__end__) (aka `load_from_self`)
|
1097
|
+
- [Expose \_\_END\_\_](#expose-__end__) (aka `expose_self`)
|
1098
|
+
- **Setting values**
|
1099
|
+
- [Default setting values file](#default-setting-values-file)
|
1100
|
+
- [Load setting values from YAML file](#load-setting-values-from-yaml-file-by-instance)
|
1101
|
+
- [Load setting values from JSON file](#load-setting-values-from-json-file-by-instance)
|
1102
|
+
- [Load setting values from \_\_END\_\_](#load-setting-values-from-__end__-by-instance)
|
1103
|
+
- [Load setting values from file manually](#load-setting-values-from-file-manually-by-instance)
|
1104
|
+
- **Daily work**
|
1105
|
+
- [Save to JSON file](#save-to-json-file) (`save_to_json`)
|
1106
|
+
- [Save to YAML file](#save-to-yaml-file) (`save_to_yaml`)
|
960
1107
|
|
961
1108
|
---
|
962
1109
|
|
@@ -1488,6 +1635,430 @@ production:
|
|
1488
1635
|
|
1489
1636
|
---
|
1490
1637
|
|
1638
|
+
### Default setting values file
|
1639
|
+
|
1640
|
+
- defines a file that should be used for setting values initialization for your config object;
|
1641
|
+
- `.values_file(file_path, format: :dynamic, strict: false, expose: nil)`
|
1642
|
+
- `file_path` - full file path or `:self` (`:self` menas "load setting values from __END__ data");
|
1643
|
+
- `:format` - defines the format of file (`:dynamic` means "try to automatically infer the file format") (`:dynamic` by default);
|
1644
|
+
- supports `:yaml`, `:json`, `:toml` (via `Qonfig.plugin(:toml)`), `:dynamic` (automatic format detection);
|
1645
|
+
- `:strict` - rerquires that file (or __END__-data) should exist (`false` by default);
|
1646
|
+
- `:expose` - what the environment-based subset of keys should be used (`nil` means "do not use any subset of keys") (`nil` by default);
|
1647
|
+
- extra keys that does not exist in your config will cause an exception `Qonfig::SettingNotFound` respectively;
|
1648
|
+
- initial values will be rewritten by values defined in your file;
|
1649
|
+
|
1650
|
+
#### Default behavior
|
1651
|
+
|
1652
|
+
```yaml
|
1653
|
+
# sidekiq.yml
|
1654
|
+
|
1655
|
+
adapter: sidekiq
|
1656
|
+
options:
|
1657
|
+
processes: 10
|
1658
|
+
```
|
1659
|
+
|
1660
|
+
```ruby
|
1661
|
+
class Config < Qonfig::DataSet
|
1662
|
+
values_file 'sidekiq.yml', format: :yaml
|
1663
|
+
|
1664
|
+
setting :adapter, 'que'
|
1665
|
+
setting :options do
|
1666
|
+
setting :processes, 2
|
1667
|
+
setting :threads, 5
|
1668
|
+
setting :protected, false
|
1669
|
+
end
|
1670
|
+
end
|
1671
|
+
|
1672
|
+
config = Config.new
|
1673
|
+
|
1674
|
+
config.settings.adapter # => "sidekiq" (from sidekiq.yml)
|
1675
|
+
config.settings.options.processes # => 10 (from sidekiq.yml)
|
1676
|
+
config.settings.options.threads # => 5 (original value)
|
1677
|
+
config.settings.options.protected # => false (original value)
|
1678
|
+
```
|
1679
|
+
|
1680
|
+
#### Load values from \_\_END\_\_-data
|
1681
|
+
|
1682
|
+
```ruby
|
1683
|
+
class Config < Qonfig::DataSet
|
1684
|
+
values_file :self, format: :yaml
|
1685
|
+
|
1686
|
+
setting :user
|
1687
|
+
setting :password
|
1688
|
+
setting :enabled, true
|
1689
|
+
end
|
1690
|
+
|
1691
|
+
config = Config.new
|
1692
|
+
|
1693
|
+
config.settings.user # => "D@iVeR" (from __END__ data)
|
1694
|
+
config.settings.password # => "test123" (from __END__ data)
|
1695
|
+
config.settings.enabled # => true (original value)
|
1696
|
+
|
1697
|
+
__END__
|
1698
|
+
|
1699
|
+
user: 'D@iVeR'
|
1700
|
+
password: 'test123'
|
1701
|
+
```
|
1702
|
+
|
1703
|
+
#### Setting values with environment separation
|
1704
|
+
|
1705
|
+
```yaml
|
1706
|
+
# sidekiq.yml
|
1707
|
+
|
1708
|
+
development:
|
1709
|
+
adapter: :in_memory
|
1710
|
+
options:
|
1711
|
+
threads: 10
|
1712
|
+
|
1713
|
+
production:
|
1714
|
+
adapter: :sidekiq
|
1715
|
+
options:
|
1716
|
+
threads: 150
|
1717
|
+
```
|
1718
|
+
|
1719
|
+
```ruby
|
1720
|
+
class Config < Qonfig::DataSet
|
1721
|
+
values_file 'sidekiq.yml', format: :yaml, expose: :development
|
1722
|
+
|
1723
|
+
setting :adapter
|
1724
|
+
setting :options do
|
1725
|
+
setting :threads
|
1726
|
+
end
|
1727
|
+
end
|
1728
|
+
|
1729
|
+
config = Config.new
|
1730
|
+
|
1731
|
+
config.settings.adapter # => 'in_memory' (development keys subset)
|
1732
|
+
config.settings.options.threads # => 10 (development keys subset)
|
1733
|
+
```
|
1734
|
+
|
1735
|
+
#### File does not exist
|
1736
|
+
|
1737
|
+
```ruby
|
1738
|
+
# strict behavior (default)
|
1739
|
+
class Config < Qonfig::DataSet
|
1740
|
+
values_file 'sidekiq.yml'
|
1741
|
+
end
|
1742
|
+
|
1743
|
+
config = Config.new # => Qonfig::FileNotFoundError
|
1744
|
+
|
1745
|
+
# non-strict behavior (strict: false)
|
1746
|
+
class Config < Qonfig::DataSet
|
1747
|
+
values_file 'sidekiq.yml', strict: false
|
1748
|
+
end
|
1749
|
+
|
1750
|
+
config = Config.new # no error
|
1751
|
+
```
|
1752
|
+
|
1753
|
+
---
|
1754
|
+
|
1755
|
+
### Load setting values from YAML file (by instance)
|
1756
|
+
|
1757
|
+
- prvoides an ability to load predefined setting values from a yaml file;
|
1758
|
+
- `#load_from_yaml(file_path, strict: true, expose: nil)`
|
1759
|
+
- `file_path` - full file path or `:self` (`:self` means "load setting values from __END__ data");
|
1760
|
+
- `:strict` - rerquires that file (or __END__-data) should exist (`true` by default);
|
1761
|
+
- `:expose` - what the environment-based subset of keys should be used (`nil` means "do not use any subset of keys") (`nil` by default);
|
1762
|
+
|
1763
|
+
#### Default behavior
|
1764
|
+
|
1765
|
+
```yaml
|
1766
|
+
# config.yml
|
1767
|
+
|
1768
|
+
domain: google.ru
|
1769
|
+
creds:
|
1770
|
+
auth_token: test123
|
1771
|
+
```
|
1772
|
+
|
1773
|
+
```ruby
|
1774
|
+
class Config < Qonfig::DataSet
|
1775
|
+
seting :domain, 'test.com'
|
1776
|
+
setting :creds do
|
1777
|
+
setting :auth_token, 'test'
|
1778
|
+
end
|
1779
|
+
end
|
1780
|
+
|
1781
|
+
config = Config.new
|
1782
|
+
config.settings.domain # => "test.com"
|
1783
|
+
config.settings.creds.auth_token # => "test"
|
1784
|
+
|
1785
|
+
# load new values
|
1786
|
+
config.load_from_yaml('config.yml')
|
1787
|
+
|
1788
|
+
config.settings.domain # => "google.ru" (from config.yml)
|
1789
|
+
config.settings.creds.auth_token # => "test123" (from config.yml)
|
1790
|
+
```
|
1791
|
+
|
1792
|
+
#### Load from \_\_END\_\_
|
1793
|
+
|
1794
|
+
```ruby
|
1795
|
+
class Config < Qonfig::DataSet
|
1796
|
+
seting :domain, 'test.com'
|
1797
|
+
setting :creds do
|
1798
|
+
setting :auth_token, 'test'
|
1799
|
+
end
|
1800
|
+
end
|
1801
|
+
|
1802
|
+
config = Config.new
|
1803
|
+
config.settings.domain # => "test.com"
|
1804
|
+
config.settings.creds.auth_token # => "test"
|
1805
|
+
|
1806
|
+
# load new values
|
1807
|
+
config.load_from_yaml(:self)
|
1808
|
+
config.settings.domain # => "yandex.ru" (from __END__-data)
|
1809
|
+
config.settings.creds.auth_token # => "CK0sIdA" (from __END__-data)
|
1810
|
+
|
1811
|
+
__END__
|
1812
|
+
|
1813
|
+
domain: yandex.ru
|
1814
|
+
creds:
|
1815
|
+
auth_token: CK0sIdA
|
1816
|
+
```
|
1817
|
+
|
1818
|
+
#### Setting values with environment separation
|
1819
|
+
|
1820
|
+
```yaml
|
1821
|
+
# config.yml
|
1822
|
+
|
1823
|
+
development:
|
1824
|
+
domain: dev.google.ru
|
1825
|
+
creds:
|
1826
|
+
auth_token: kekpek
|
1827
|
+
|
1828
|
+
production:
|
1829
|
+
domain: google.ru
|
1830
|
+
creds:
|
1831
|
+
auth_token: Asod1
|
1832
|
+
```
|
1833
|
+
|
1834
|
+
```ruby
|
1835
|
+
class Config < Qonfig::DataSet
|
1836
|
+
setting :domain, 'test.com'
|
1837
|
+
setting :creds do
|
1838
|
+
setting :auth_token
|
1839
|
+
end
|
1840
|
+
end
|
1841
|
+
|
1842
|
+
config = Config.new
|
1843
|
+
|
1844
|
+
# load new values (expose development settings)
|
1845
|
+
config.load_from_yaml('config.yml', expose: :development)
|
1846
|
+
|
1847
|
+
config.settings.domain # => "dev.google.ru" (from config.yml)
|
1848
|
+
config.settings.creds.auth_token # => "kek.pek" (from config.yml)
|
1849
|
+
```
|
1850
|
+
|
1851
|
+
---
|
1852
|
+
|
1853
|
+
### Load setting values from JSON file (by instance)
|
1854
|
+
|
1855
|
+
- prvoides an ability to load predefined setting values from a json file;
|
1856
|
+
- `#load_from_yaml(file_path, strict: true, expose: nil)`
|
1857
|
+
- `file_path` - full file path or `:self` (`:self` means "load setting values from __END__ data");
|
1858
|
+
- `:strict` - rerquires that file (or __END__-data) should exist (`true` by default);
|
1859
|
+
- `:expose` - what the environment-based subset of keys should be used (`nil` means "do not use any subset of keys") (`nil` by default);
|
1860
|
+
|
1861
|
+
#### Default behavior
|
1862
|
+
|
1863
|
+
```json
|
1864
|
+
// config.json
|
1865
|
+
|
1866
|
+
{
|
1867
|
+
"domain": "google.ru",
|
1868
|
+
"creds": {
|
1869
|
+
"auth_token": "test123"
|
1870
|
+
}
|
1871
|
+
}
|
1872
|
+
```
|
1873
|
+
|
1874
|
+
```ruby
|
1875
|
+
class Config < Qonfig::DataSet
|
1876
|
+
seting :domain, 'test.com'
|
1877
|
+
setting :creds do
|
1878
|
+
setting :auth_token, 'test'
|
1879
|
+
end
|
1880
|
+
end
|
1881
|
+
|
1882
|
+
config = Config.new
|
1883
|
+
config.settings.domain # => "test.com"
|
1884
|
+
config.settings.creds.auth_token # => "test"
|
1885
|
+
|
1886
|
+
# load new values
|
1887
|
+
config.load_from_json('config.json')
|
1888
|
+
|
1889
|
+
config.settings.domain # => "google.ru" (from config.json)
|
1890
|
+
config.settings.creds.auth_token # => "test123" (from config.json)
|
1891
|
+
```
|
1892
|
+
|
1893
|
+
#### Load from \_\_END\_\_
|
1894
|
+
|
1895
|
+
```ruby
|
1896
|
+
class Config < Qonfig::DataSet
|
1897
|
+
seting :domain, 'test.com'
|
1898
|
+
setting :creds do
|
1899
|
+
setting :auth_token, 'test'
|
1900
|
+
end
|
1901
|
+
end
|
1902
|
+
|
1903
|
+
config = Config.new
|
1904
|
+
config.settings.domain # => "test.com"
|
1905
|
+
config.settings.creds.auth_token # => "test"
|
1906
|
+
|
1907
|
+
# load new values
|
1908
|
+
config.load_from_json(:self)
|
1909
|
+
config.settings.domain # => "yandex.ru" (from __END__-data)
|
1910
|
+
config.settings.creds.auth_token # => "CK0sIdA" (from __END__-data)
|
1911
|
+
|
1912
|
+
__END__
|
1913
|
+
|
1914
|
+
{
|
1915
|
+
"domain": "yandex.ru",
|
1916
|
+
"creds": {
|
1917
|
+
"auth_token": "CK0sIdA"
|
1918
|
+
}
|
1919
|
+
}
|
1920
|
+
```
|
1921
|
+
|
1922
|
+
#### Setting values with environment separation
|
1923
|
+
|
1924
|
+
```json
|
1925
|
+
// config.json
|
1926
|
+
|
1927
|
+
{
|
1928
|
+
"development": {
|
1929
|
+
"domain": "dev.google.ru",
|
1930
|
+
"creds": {
|
1931
|
+
"auth_token": "kekpek"
|
1932
|
+
}
|
1933
|
+
},
|
1934
|
+
"production": {
|
1935
|
+
"domain": "google.ru",
|
1936
|
+
"creds": {
|
1937
|
+
"auth_token": "Asod1"
|
1938
|
+
}
|
1939
|
+
}
|
1940
|
+
}
|
1941
|
+
```
|
1942
|
+
|
1943
|
+
```ruby
|
1944
|
+
class Config < Qonfig::DataSet
|
1945
|
+
setting :domain, 'test.com'
|
1946
|
+
setting :creds do
|
1947
|
+
setting :auth_token
|
1948
|
+
end
|
1949
|
+
end
|
1950
|
+
|
1951
|
+
config = Config.new
|
1952
|
+
|
1953
|
+
# load new values (from development subset)
|
1954
|
+
config.load_from_json('config.json', expose: :development)
|
1955
|
+
|
1956
|
+
config.settings.domain # => "dev.google.ru" (from config.json)
|
1957
|
+
config.settings.creds.auth_token # => "kek.pek" (from config.json)
|
1958
|
+
```
|
1959
|
+
---
|
1960
|
+
|
1961
|
+
### Load setting values from \_\_END\_\_ (by instance)
|
1962
|
+
|
1963
|
+
- prvoides an ability to load predefined setting values from `__END__` file section;
|
1964
|
+
- `#load_from_self(strict: true, expose: nil)`
|
1965
|
+
- `:format` - defines the format of file (`:dynamic` means "try to automatically infer the file format") (`:dynamic` by default);
|
1966
|
+
- supports `:yaml`, `:json`, `:toml` (via `Qonfig.plugin(:toml)`), `:dynamic` (automatic format detection);
|
1967
|
+
- `:strict` - requires that __END__-data should exist (`true` by default);
|
1968
|
+
- `:expose` - what the environment-based subset of keys should be used (`nil` means "do not use any subset of keys") (`nil` by default);
|
1969
|
+
|
1970
|
+
#### Default behavior
|
1971
|
+
|
1972
|
+
```ruby
|
1973
|
+
class Config < Qonfig::DataSet
|
1974
|
+
setting :account, 'test'
|
1975
|
+
setting :options do
|
1976
|
+
setting :login, '0exp'
|
1977
|
+
setting :password, 'test123'
|
1978
|
+
end
|
1979
|
+
end
|
1980
|
+
|
1981
|
+
config = Config.new
|
1982
|
+
config.settings.account # => "test" (original value)
|
1983
|
+
config.settings.options.login # => "0exp" (original value)
|
1984
|
+
config.settings.options.password # => "test123" (original value)
|
1985
|
+
|
1986
|
+
# load new values
|
1987
|
+
config.load_from_self(format: :yaml)
|
1988
|
+
# or config.load_from_self
|
1989
|
+
|
1990
|
+
config.settings.account # => "real" (from __END__-data)
|
1991
|
+
config.settings.options.login # => "D@iVeR" (from __END__-data)
|
1992
|
+
config.settings.options.password # => "azaza123" (from __END__-data)
|
1993
|
+
|
1994
|
+
__END__
|
1995
|
+
|
1996
|
+
account: real
|
1997
|
+
options:
|
1998
|
+
login: D@iVeR
|
1999
|
+
password: azaza123
|
2000
|
+
```
|
2001
|
+
|
2002
|
+
#### Setting values with envvironment separation
|
2003
|
+
|
2004
|
+
```ruby
|
2005
|
+
class Config < Qonfig::DataSet
|
2006
|
+
setting :domain, 'test.google.ru'
|
2007
|
+
setting :options do
|
2008
|
+
setting :login, 'test'
|
2009
|
+
setting :password, 'test123'
|
2010
|
+
end
|
2011
|
+
end
|
2012
|
+
|
2013
|
+
config = Config.new
|
2014
|
+
config.settings.domain # => "test.google.ru" (original value)
|
2015
|
+
config.settings.options.login # => "test" (original value)
|
2016
|
+
config.settings.options.password # => "test123" (original value)
|
2017
|
+
|
2018
|
+
# load new values
|
2019
|
+
config.load_from_self(format: :json, expose: :production)
|
2020
|
+
# or config.load_from_self(expose: production)
|
2021
|
+
|
2022
|
+
config.settings.domain # => "prod.google.ru" (from __END__-data)
|
2023
|
+
config.settings.options.login # => "prod" (from __END__-data)
|
2024
|
+
config.settings.options.password # => "prod123" (from __END__-data)
|
2025
|
+
|
2026
|
+
__END__
|
2027
|
+
|
2028
|
+
{
|
2029
|
+
"development": {
|
2030
|
+
"domain": "dev.google.ru",
|
2031
|
+
"options": {
|
2032
|
+
"login": "dev",
|
2033
|
+
"password": "dev123"
|
2034
|
+
}
|
2035
|
+
},
|
2036
|
+
"production": {
|
2037
|
+
"domain": "prod.google.ru",
|
2038
|
+
"options": {
|
2039
|
+
"login": "prod",
|
2040
|
+
"password": "prod123"
|
2041
|
+
}
|
2042
|
+
}
|
2043
|
+
}
|
2044
|
+
```
|
2045
|
+
|
2046
|
+
---
|
2047
|
+
|
2048
|
+
### Load setting values from file manually (by instance)
|
2049
|
+
|
2050
|
+
- prvoides an ability to load predefined setting values from a file;
|
2051
|
+
- works in instance-based `#load_from_yaml` / `#load_from_json` / `#load_from_self` manner;
|
2052
|
+
- signature: `#load_from_file(file_path, format: :dynamic, strict: true, expose: nil)`:
|
2053
|
+
- `file_path` - full file path or `:self` (`:self` means "load setting values from __END__ data");
|
2054
|
+
- `:format` - defines the format of file (`:dynamic` means "try to automatically infer the file format") (`:dynamic` by default);
|
2055
|
+
- supports `:yaml`, `:json`, `:toml` (via `Qonfig.plugin(:toml)`), `:dynamic` (automatic format detection);
|
2056
|
+
- `:strict` - rerquires that file (or __END__-data) should exist (`true` by default);
|
2057
|
+
- `:expose` - what the environment-based subset of keys should be used (`nil` means "do not use any subset of keys") (`nil` by default);
|
2058
|
+
- see examples for instance-based `#load_from_yaml` ([doc](#load-setting-values-from-yaml-by-instance)) / `#load_from_json` ([doc](#load-setting-values-from-json-by-instance)) / `#load_from_self` ([doc](#load-setting-values-from-__end__-by-instance));
|
2059
|
+
|
2060
|
+
---
|
2061
|
+
|
1491
2062
|
### Save to JSON file
|
1492
2063
|
|
1493
2064
|
- `#save_to_json` - represents config object as a json structure and saves it to a file:
|
@@ -1630,8 +2201,6 @@ enabled: true
|
|
1630
2201
|
dynamic: 10
|
1631
2202
|
```
|
1632
2203
|
|
1633
|
-
---
|
1634
|
-
|
1635
2204
|
### Plugins
|
1636
2205
|
|
1637
2206
|
```ruby
|
@@ -1652,10 +2221,12 @@ Provided plugins:
|
|
1652
2221
|
|
1653
2222
|
- adds support for `toml` format ([specification](https://github.com/toml-lang/toml));
|
1654
2223
|
- depends on `toml-rb` gem ([link](https://github.com/emancu/toml-rb));
|
1655
|
-
- supports TOML `0.
|
1656
|
-
- provides
|
1657
|
-
- provides `
|
1658
|
-
- provides `
|
2224
|
+
- supports TOML `0.5.0` format (dependency lock);
|
2225
|
+
- provides `.load_from_toml` (works in `.load_from_yaml` manner ([doc](#load-from-yaml-file)));
|
2226
|
+
- provides `.expose_toml` (works in `.expose_yaml` manner ([doc](#expose-yaml)));
|
2227
|
+
- provides `#save_to_toml` (works in `#save_to_yaml` manner ([doc](#save-to-yaml-file))) (`toml-rb` has no native options);
|
2228
|
+
- provides `format: :toml` for `.values_file` ([doc]());
|
2229
|
+
- provides `#load_from_toml` (work in `#load_from_yaml` manner ([doc](#load-setting-values-from-yaml)));
|
1659
2230
|
|
1660
2231
|
```ruby
|
1661
2232
|
# 1) require external dependency
|
@@ -1670,14 +2241,24 @@ Qonfig.plugin(:toml)
|
|
1670
2241
|
|
1671
2242
|
## Roadmap
|
1672
2243
|
|
1673
|
-
-
|
1674
|
-
-
|
2244
|
+
- **Major**:
|
2245
|
+
- distributed configuration server;
|
2246
|
+
- cli toolchain;
|
2247
|
+
- support for Rails-like secrets;
|
2248
|
+
- support for persistent data storages (we want to store configs in multiple databases and files);
|
2249
|
+
- Rails reload plugin;
|
2250
|
+
- **Minor**:
|
2251
|
+
- custom global (and class-level) validators (with a special Validator Definition DSL);
|
2252
|
+
- support for "dot notation" in `#key?`, `#option?`, `#setting?`, `#dig`, `#subset`, `#slice`, `#slice_value`;
|
2253
|
+
- "load setting values from a file" (at instance level);
|
2254
|
+
- config improts (and exports);
|
2255
|
+
- pretty print :)));
|
1675
2256
|
|
1676
2257
|
## Contributing
|
1677
2258
|
|
1678
2259
|
- Fork it ( https://github.com/0exp/qonfig/fork )
|
1679
2260
|
- Create your feature branch (`git checkout -b feature/my-new-feature`)
|
1680
|
-
- Commit your changes (`git commit -am 'Add some feature'`)
|
2261
|
+
- Commit your changes (`git commit -am '[my-new-featre] Add some feature'`)
|
1681
2262
|
- Push to the branch (`git push origin feature/my-new-feature`)
|
1682
2263
|
- Create new Pull Request
|
1683
2264
|
|