qonfig 0.17.0 → 0.18.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 +4 -0
- data/CHANGELOG.md +9 -1
- data/README.md +313 -14
- data/lib/qonfig/data_set.rb +49 -1
- data/lib/qonfig/errors.rb +24 -0
- data/lib/qonfig/imports/abstract.rb +90 -0
- data/lib/qonfig/imports/direct_key.rb +110 -0
- data/lib/qonfig/imports/dsl.rb +46 -0
- data/lib/qonfig/imports/export.rb +39 -0
- data/lib/qonfig/imports/general.rb +131 -0
- data/lib/qonfig/imports/mappings.rb +120 -0
- data/lib/qonfig/imports.rb +23 -0
- data/lib/qonfig/settings/key_matcher.rb +9 -8
- data/lib/qonfig/settings.rb +66 -4
- data/lib/qonfig/version.rb +1 -1
- data/lib/qonfig.rb +1 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec197a7e1d7185ff8c4e5906e244c5cbce610d1449dc60cfb1d2a167a2e79921
|
4
|
+
data.tar.gz: 47d2d394cfcc97cf5ab58a198865490ecd4c9494c7ee7096474ff7a6f0c5d7f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87e2688f74aa2dba959c423ea79ec36686c1873e20654826ad4eefc599da6f0d9967066e8de605b0f0a83d58465ecdb3f061e193fedc1aef6223d03794ffff7f
|
7
|
+
data.tar.gz: 107ccfc0dfe0ee109765699c4af58d431edd572d6ea30dace2449ff87d991bc8dbb555dedf95ccf7d3101cac2fb728fd7e44dec5c8a04a74583b006926e8ec46
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
-
## [
|
4
|
+
## [0.18.0] - 2019-11-04
|
5
|
+
### Added
|
6
|
+
- `#keys` - returns a list of all config keys in dot-notation format;
|
7
|
+
- `#root_keys` - returns a list of root config keys;
|
8
|
+
- Inroduce `Import API`:
|
9
|
+
- `.import_settings` - DSL method for importing configuration settings (from a config instance) as instance methods of a class;
|
10
|
+
- `#export_settings` - config's instance method that exports config settings to an arbitrary object as singelton methods;
|
11
|
+
|
12
|
+
## [0.17.0] - 2019-10-30
|
5
13
|
### Added
|
6
14
|
- Introduce `strict` validations: `strict: false` option ignores `nil` values and used by default;
|
7
15
|
- Setting's key existence check methods: `#key?(*key_path)`, `#setting?(*key_path)`, `#option?(*key_path)`;
|
data/README.md
CHANGED
@@ -44,12 +44,16 @@ require 'qonfig'
|
|
44
44
|
- [Instantiation without class definition](#instantiation-without-class-definition) (`Qonfig::DataSet.build(&definitions)`)
|
45
45
|
- [Interaction](#interaction)
|
46
46
|
- [Iteration over setting keys](#iteration-over-setting-keys) (`#each_setting`, `#deep_each_setting`)
|
47
|
+
- [List of config keys](#list-of-config-keys) (`#keys`, `#root_keys`)
|
47
48
|
- [Config reloading](#config-reloading) (reload config definitions and option values)
|
48
49
|
- [Clear options](#clear-options) (set to `nil`)
|
49
50
|
- [State freeze](#state-freeze)
|
50
51
|
- [Settings as Predicates](#settings-as-predicates)
|
51
52
|
- [Setting key existence](#setting-key-existence) (`#key?`/`#option?`/`#setting?`)
|
52
|
-
- [Run
|
53
|
+
- [Run arbitrary code with temporary settings](#run-arbitrary-code-with-temporary-settings) (`#with(configs = {}, &arbitrary_code)`)
|
54
|
+
- [Import settings / Export settings](#import-settings--export-settings)
|
55
|
+
- [Import config settings](#import-config-settings) (`as instance methods`)
|
56
|
+
- [Export config settings](#export-config-settings) (`as singleton methods`)
|
53
57
|
- [Validation](#validation)
|
54
58
|
- [Introduction](#introduction)
|
55
59
|
- [Key search pattern](#key-search-pattern)
|
@@ -75,7 +79,7 @@ require 'qonfig'
|
|
75
79
|
- [Save to JSON file](#save-to-json-file) (`#save_to_json`)
|
76
80
|
- [Save to YAML file](#save-to-yaml-file) (`#save_to_yaml`)
|
77
81
|
- [Plugins](#plugins)
|
78
|
-
- [toml](#plugins-toml) (
|
82
|
+
- [toml](#plugins-toml) (support for `TOML` format)
|
79
83
|
- [Roadmap](#roadmap)
|
80
84
|
---
|
81
85
|
|
@@ -493,6 +497,8 @@ GeneralApplication.config.to_h
|
|
493
497
|
|
494
498
|
### Instantiation without class definition
|
495
499
|
|
500
|
+
- without inheritance:
|
501
|
+
|
496
502
|
```ruby
|
497
503
|
config = Qonfig::DataSet.build do
|
498
504
|
setting :user, 'D@iVeR'
|
@@ -510,17 +516,35 @@ config.settings.password # => 'test123'
|
|
510
516
|
config.custom_method # => 'custom_result'
|
511
517
|
```
|
512
518
|
|
519
|
+
- with inheritance:
|
520
|
+
|
521
|
+
```ruby
|
522
|
+
class GeneralConfig < Qonfig::DataSet
|
523
|
+
setting :db_adapter, :postgresql
|
524
|
+
end
|
525
|
+
|
526
|
+
config = Qonfig::DataSet.build(GeneralConfig) do
|
527
|
+
setting :web_api, 'api.google.com'
|
528
|
+
end
|
529
|
+
|
530
|
+
config.is_a?(Qonfig::DataSet) # => true
|
531
|
+
|
532
|
+
config.settings.db_adapter # => :postgresql
|
533
|
+
config.settings.web_api # => "api.google.com"
|
534
|
+
```
|
535
|
+
|
513
536
|
---
|
514
537
|
|
515
538
|
## Interaction
|
516
539
|
|
517
540
|
- [Iteration over setting keys](#iteration-over-setting-keys) (`#each_setting`, `#deep_each_setting`)
|
541
|
+
- [List of config keys](#list-of-config-keys) (`#keys`, `#root_keys`)
|
518
542
|
- [Config reloading](#config-reloading) (reload config definitions and option values)
|
519
|
-
- [Clear options](#clear-options) (set to nil)
|
543
|
+
- [Clear options](#clear-options) (set to `nil`)
|
520
544
|
- [State freeze](#state-freeze)
|
521
545
|
- [Settings as Predicates](#settings-as-predicates)
|
522
546
|
- [Setting key existence](#setting-key-existence) (`#key?`/`#option?`/`#setting?`)
|
523
|
-
- [Run
|
547
|
+
- [Run arbitrary code with temporary settings](#run-arbitrary-code-with-temporary-settings)
|
524
548
|
|
525
549
|
---
|
526
550
|
|
@@ -576,8 +600,96 @@ config.deep_each_setting { |key, value| { key => value } }
|
|
576
600
|
|
577
601
|
---
|
578
602
|
|
603
|
+
### List of config keys
|
604
|
+
|
605
|
+
- `#keys` - returns a list of all config keys in dot-notation format;
|
606
|
+
- `all_variants:` - get all possible variants of the config's keys sequences (`false` by default);
|
607
|
+
- `only_root:` - get only the root config keys (`false` by default);
|
608
|
+
- `#root_keys` - returns a list of root config keys (an alias for `#keys(only_root: true)`);
|
609
|
+
|
610
|
+
```ruby
|
611
|
+
# NOTE: suppose we have the following config
|
612
|
+
|
613
|
+
class Config < Qonfig::DataSet
|
614
|
+
setting :credentials do
|
615
|
+
setting :social do
|
616
|
+
setting :service, 'instagram'
|
617
|
+
setting :login, '0exp'
|
618
|
+
end
|
619
|
+
|
620
|
+
setting :admin do
|
621
|
+
setting :enabled, true
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
setting :server do
|
626
|
+
setting :type, 'cloud'
|
627
|
+
setting :options do
|
628
|
+
setting :os, 'CentOS'
|
629
|
+
end
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
config = Config.new
|
634
|
+
```
|
635
|
+
|
636
|
+
#### Default behavior
|
637
|
+
|
638
|
+
```ruby
|
639
|
+
config.keys
|
640
|
+
|
641
|
+
# the result:
|
642
|
+
[
|
643
|
+
"credentials.social.service",
|
644
|
+
"credentials.social.login",
|
645
|
+
"credentials.admin.enabled",
|
646
|
+
"server.type",
|
647
|
+
"server.options.os"
|
648
|
+
]
|
649
|
+
```
|
650
|
+
|
651
|
+
#### All key variants
|
652
|
+
|
653
|
+
```ruby
|
654
|
+
config.keys(all_variants: true)
|
655
|
+
|
656
|
+
# the result:
|
657
|
+
[
|
658
|
+
"credentials",
|
659
|
+
"credentials.social",
|
660
|
+
"credentials.social.service",
|
661
|
+
"credentials.social.login",
|
662
|
+
"credentials.admin",
|
663
|
+
"credentials.admin.enabled",
|
664
|
+
"server",
|
665
|
+
"server.type",
|
666
|
+
"server.options",
|
667
|
+
"server.options.os"
|
668
|
+
]
|
669
|
+
```
|
670
|
+
|
671
|
+
#### Only root keys
|
672
|
+
|
673
|
+
```ruby
|
674
|
+
config.keys(only_root: true)
|
675
|
+
|
676
|
+
# the result:
|
677
|
+
['credentials', 'server']
|
678
|
+
```
|
679
|
+
|
680
|
+
```ruby
|
681
|
+
config.root_keys
|
682
|
+
|
683
|
+
# the result:
|
684
|
+
['credentials', 'server']
|
685
|
+
```
|
686
|
+
|
687
|
+
---
|
688
|
+
|
579
689
|
### Config reloading
|
580
690
|
|
691
|
+
- method signature: `#reload!(configurations = {}, &configuration)`;
|
692
|
+
|
581
693
|
```ruby
|
582
694
|
class Config < Qonfig::DataSet
|
583
695
|
setting :db do
|
@@ -624,6 +736,9 @@ config.settings.enable_api # => true # value from instant change
|
|
624
736
|
|
625
737
|
### Clear options
|
626
738
|
|
739
|
+
- set all config's settings to `nil`;
|
740
|
+
- method signature: `#clear!`;
|
741
|
+
|
627
742
|
```ruby
|
628
743
|
class Config
|
629
744
|
setting :database do
|
@@ -659,6 +774,8 @@ config.settings.web_api.endpoint # => nil
|
|
659
774
|
|
660
775
|
### State freeze
|
661
776
|
|
777
|
+
- method signature: `#freeze!`;
|
778
|
+
|
662
779
|
```ruby
|
663
780
|
class Config < Qonfig::DataSet
|
664
781
|
setting :logger, Logger.new(STDOUT)
|
@@ -756,10 +873,10 @@ config.option?(:credentials, :password) # => true
|
|
756
873
|
|
757
874
|
---
|
758
875
|
|
759
|
-
### Run
|
876
|
+
### Run arbitrary code with temporary settings
|
760
877
|
|
761
|
-
- provides a way to run an
|
762
|
-
- your
|
878
|
+
- provides a way to run an arbitrary code with temporarily specified settings;
|
879
|
+
- your arbitrary code can temporary change any setting too - all settings will be returned to the original state;
|
763
880
|
- (it is convenient to run code samples by this way in tests (with substitued configs));
|
764
881
|
- it is fully thread-safe `:)`;
|
765
882
|
|
@@ -791,6 +908,188 @@ config.settings.queue.options # => {}
|
|
791
908
|
|
792
909
|
---
|
793
910
|
|
911
|
+
## Import settings / Export settings
|
912
|
+
|
913
|
+
- [Import config settings](#import-config-settings) (`as instance methods`)
|
914
|
+
- [Export config settings](#export-config-settings) (`as singleton methods`)
|
915
|
+
|
916
|
+
Sometimes the nesting of configs in your project is quite high, and it makes you write the rather "cumbersome" code
|
917
|
+
(`config.settings.web_api.credentials.account.auth_token` for example). Frequent access to configs in this way is inconvinient - so developers wraps
|
918
|
+
such code by methods or variables. In order to make developer's life easer `Qonfig` provides a special Import API simplifies the config importing
|
919
|
+
(gives you `.import_settings` DSL) and gives an ability to instant config setting export from a config object (gives you `#export_settings` config's method).
|
920
|
+
|
921
|
+
---
|
922
|
+
|
923
|
+
### Import config settings
|
924
|
+
|
925
|
+
- `Qonfig::Imports` - a special mixin that provides the convenient DSL to work with config import features (`.import_settings` method);
|
926
|
+
- `.import_settings` - DSL method for importing configuration settings (from a config instance) as instance methods of a class;
|
927
|
+
- (**IMPORTANT**) `import_settings` imports config settings as access methods to config's settings (creates `attr_reader`s for your config);
|
928
|
+
- signature: `.import_settings(config_object, *setting_keys, mappings: {}, prefix: '', raw: false)`
|
929
|
+
- `config_object` - an instance of `Qonfig::DataSet` whose config settings should be imported;
|
930
|
+
- `*setting_keys` - an array of dot-notaed config's setting keys that should be imported
|
931
|
+
(dot-notaed key is a key that describes each part of nested setting key as a string separated by `dot`-symbol);
|
932
|
+
- last part of dot-notated key will become a name of the setting access instance method;
|
933
|
+
- `mappings:` - a map of keys that describes custom method names for each imported setting;
|
934
|
+
- `prefix:` - prexifies setting access method name with custom prefix;
|
935
|
+
- `raw:` - use nested settings as objects or hashify them (`false` by default (means "hashify nested settings"));
|
936
|
+
|
937
|
+
---
|
938
|
+
|
939
|
+
Suppose we have a config with deeply nested keys:
|
940
|
+
|
941
|
+
```ruby
|
942
|
+
# NOTE: (Qonfig::DataSet.build creates a class and instantly instantiates it)
|
943
|
+
AppConfig = Qonfig::DataSet.build do
|
944
|
+
setting :web_api do
|
945
|
+
setting :credentials do
|
946
|
+
setting :account do
|
947
|
+
setting :login, 'DaiveR'
|
948
|
+
setting :auth_token, 'IAdkoa0@()1239uA'
|
949
|
+
end
|
950
|
+
end
|
951
|
+
end
|
952
|
+
end
|
953
|
+
```
|
954
|
+
|
955
|
+
Let's see what we can to do :)
|
956
|
+
|
957
|
+
#### Import a set of setting keys (simple dot-noated key list)
|
958
|
+
|
959
|
+
- last part of dot-notated key will become a name of the setting access instance method;
|
960
|
+
|
961
|
+
```ruby
|
962
|
+
class ServiceObject
|
963
|
+
include Qonfig::Imports
|
964
|
+
|
965
|
+
import_settings(AppConfig,
|
966
|
+
'web_api.credentials.account.login',
|
967
|
+
'web_api.credentials.account'
|
968
|
+
)
|
969
|
+
end
|
970
|
+
|
971
|
+
service = ServiceObject.new
|
972
|
+
|
973
|
+
service.login # => "D@iVeR"
|
974
|
+
service.account # => { "login" => "D@iVeR", "auth_token" => IAdkoa0@()1239uA" }
|
975
|
+
```
|
976
|
+
|
977
|
+
#### Import with custom method names (mappings)
|
978
|
+
|
979
|
+
- `mappings:` defines a map of keys that describes custom method names for each imported setting;
|
980
|
+
|
981
|
+
```ruby
|
982
|
+
class ServiceObject
|
983
|
+
include Qonfig::Imports
|
984
|
+
|
985
|
+
import_settings(AppConfig, mappings: {
|
986
|
+
account_data: 'web_api.credentials.account', # NOTE: name access method with "account_data"
|
987
|
+
secret_token: 'web_api.credentials.account.auth_token' # NOTE: name access method with "secret_token"
|
988
|
+
})
|
989
|
+
end
|
990
|
+
|
991
|
+
service = ServiceObject.new
|
992
|
+
|
993
|
+
service.account_data # => { "login" => "D@iVeR", "auth_token" => "IAdkoa0@()1239uA" }
|
994
|
+
service.auth_token # => "IAdkoa0@()1239uA"
|
995
|
+
```
|
996
|
+
|
997
|
+
#### Prexify method name
|
998
|
+
|
999
|
+
- `prefix:` - prexifies setting access method name with custom prefix;
|
1000
|
+
|
1001
|
+
```ruby
|
1002
|
+
class ServiceObject
|
1003
|
+
include Qonfig::Imports
|
1004
|
+
|
1005
|
+
import_settings(AppConfig,
|
1006
|
+
'web_api.credentials.account',
|
1007
|
+
mappings: { secret_token: 'web_api.credentials.account.auth_token' },
|
1008
|
+
prefix: 'config_'
|
1009
|
+
)
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
service = ServiceObject.new
|
1013
|
+
|
1014
|
+
service.config_credentials # => { login" => "D@iVeR", "auth_token" => "IAdkoa0@()1239uA" }
|
1015
|
+
service.config_secret_token # => "IAdkoa0@()1239uA"
|
1016
|
+
```
|
1017
|
+
|
1018
|
+
#### Import nested settings as raw Qonfig::Settings objects
|
1019
|
+
|
1020
|
+
- `raw: false` is used by default (hashify nested settings)
|
1021
|
+
|
1022
|
+
```ruby
|
1023
|
+
# NOTE: import nested settings as raw objects (raw: true)
|
1024
|
+
class ServiceObject
|
1025
|
+
include Qonfig::Imports
|
1026
|
+
|
1027
|
+
import_settings(AppConfig, 'web_api.credentials', raw: true)
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
service = ServiceObject.new
|
1031
|
+
|
1032
|
+
service.credentials # => <Qonfig::Settings:0x00007ff8>
|
1033
|
+
service.credentials.account.login # => "D@iVeR"
|
1034
|
+
service.credentials.account.auth_token # => "IAdkoa0@()1239uA"
|
1035
|
+
```
|
1036
|
+
|
1037
|
+
```ruby
|
1038
|
+
# NOTE: import nested settings as converted-to-hash objects (raw: false) (default behavior)
|
1039
|
+
class ServiceObject
|
1040
|
+
include Qonfig::Imports
|
1041
|
+
|
1042
|
+
import_settings(AppConfig, 'web_api.credentials', raw: false)
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
service = ServiceObject.new
|
1046
|
+
|
1047
|
+
service.credentials # => { "account" => { "login" => "D@iVeR", "auth_token" => "IAdkoa0@()1239uA"} }
|
1048
|
+
```
|
1049
|
+
|
1050
|
+
---
|
1051
|
+
|
1052
|
+
### Export config settings
|
1053
|
+
|
1054
|
+
- all config objects can export their settings to an arbitrary object as singleton methods;
|
1055
|
+
- (**IMPORTANT**) `export_settings` exports config settings as access methods to config's settings (creates `attr_reader`s for your config);
|
1056
|
+
- signature: `#export(exportable_object, *setting_keys, mappings: {}, prefix: '', raw: false)`:
|
1057
|
+
- `exportable_object` - an arbitrary object for exporting;
|
1058
|
+
- `*setting_keys` - an array of dot-notaed config's setting keys that should be exported
|
1059
|
+
(dot-notaed key is a key that describes each part of nested setting key as a string separated by `dot`-symbol);
|
1060
|
+
- last part of dot-notated key will become a name of the setting access instance method;
|
1061
|
+
- `mappings:` - a map of keys that describes custom method names for each exported setting;
|
1062
|
+
- `prefix:` - prexifies setting access method name with custom prefix;
|
1063
|
+
- `raw:` - use nested settings as objects or hashify them (`false` by default (means "hashify nested settings"));
|
1064
|
+
- works in `.import_settings` manner [doc](#import-config-settings) (see examples and documentation above `:)`)
|
1065
|
+
|
1066
|
+
```ruby
|
1067
|
+
class Config < Qonfig::DataSet
|
1068
|
+
setting :web_api do
|
1069
|
+
setting :credentials do
|
1070
|
+
setting :account do
|
1071
|
+
setting :login, 'DaiveR'
|
1072
|
+
setting :auth_token, 'IAdkoa0@()1239uA'
|
1073
|
+
end
|
1074
|
+
end
|
1075
|
+
end
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
class ServiceObject; end
|
1079
|
+
|
1080
|
+
config = Config.new
|
1081
|
+
service = ServiceObject.new
|
1082
|
+
|
1083
|
+
service.config_account # => NoMethodError
|
1084
|
+
|
1085
|
+
# NOTE: export settings as access methods to config's settings
|
1086
|
+
config.export(service, 'web_api.credentials.account', prefix: 'config_')
|
1087
|
+
|
1088
|
+
service.account # => { "login" => "D@iVeR", "auth_token" => "IAdkoa0@()1239uA" }
|
1089
|
+
```
|
1090
|
+
|
1091
|
+
---
|
1092
|
+
|
794
1093
|
## Validation
|
795
1094
|
|
796
1095
|
- [Introduction](#introduction)
|
@@ -1735,19 +2034,19 @@ config.settings.options.threads # => 10 (development keys subset)
|
|
1735
2034
|
#### File does not exist
|
1736
2035
|
|
1737
2036
|
```ruby
|
1738
|
-
# strict behavior (default)
|
2037
|
+
# non-strict behavior (default)
|
1739
2038
|
class Config < Qonfig::DataSet
|
1740
2039
|
values_file 'sidekiq.yml'
|
1741
2040
|
end
|
1742
2041
|
|
1743
|
-
config = Config.new #
|
2042
|
+
config = Config.new # no error
|
1744
2043
|
|
1745
|
-
#
|
2044
|
+
# strict behavior (strict: true)
|
1746
2045
|
class Config < Qonfig::DataSet
|
1747
|
-
values_file 'sidekiq.yml', strict:
|
2046
|
+
values_file 'sidekiq.yml', strict: true
|
1748
2047
|
end
|
1749
2048
|
|
1750
|
-
config = Config.new #
|
2049
|
+
config = Config.new # => Qonfig::FileNotFoundError
|
1751
2050
|
```
|
1752
2051
|
|
1753
2052
|
---
|
@@ -2201,6 +2500,8 @@ enabled: true
|
|
2201
2500
|
dynamic: 10
|
2202
2501
|
```
|
2203
2502
|
|
2503
|
+
---
|
2504
|
+
|
2204
2505
|
### Plugins
|
2205
2506
|
|
2206
2507
|
```ruby
|
@@ -2250,8 +2551,6 @@ Qonfig.plugin(:toml)
|
|
2250
2551
|
- **Minor**:
|
2251
2552
|
- custom global (and class-level) validators (with a special Validator Definition DSL);
|
2252
2553
|
- 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
2554
|
- pretty print :)));
|
2256
2555
|
|
2257
2556
|
## Contributing
|
data/lib/qonfig/data_set.rb
CHANGED
@@ -21,7 +21,7 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
|
|
21
21
|
# @since 0.16.0
|
22
22
|
def build(base_dataset_klass = self, &config_klass_definitions)
|
23
23
|
unless base_dataset_klass <= Qonfig::DataSet
|
24
|
-
raise(Qonfig::ArgumentError, 'Base
|
24
|
+
raise(Qonfig::ArgumentError, 'Base class should be a type of Qonfig::DataSet')
|
25
25
|
end
|
26
26
|
|
27
27
|
Class.new(base_dataset_klass, &config_klass_definitions).new
|
@@ -309,6 +309,26 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
|
|
309
309
|
thread_safe_access { validator.validate! }
|
310
310
|
end
|
311
311
|
|
312
|
+
# @option all_variants [Boolean]
|
313
|
+
# @option only_root [Boolean]
|
314
|
+
# @return [Array<String>]
|
315
|
+
#
|
316
|
+
# @api public
|
317
|
+
# @since 0.18.0
|
318
|
+
def keys(all_variants: false, only_root: false)
|
319
|
+
thread_safe_access do
|
320
|
+
only_root ? settings.__root_keys__ : settings.__keys__(all_variants: all_variants)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# @return [Array<String>]
|
325
|
+
#
|
326
|
+
# @api public
|
327
|
+
# @since 0.18.0
|
328
|
+
def root_keys
|
329
|
+
thread_safe_access { settings.__root_keys__ }
|
330
|
+
end
|
331
|
+
|
312
332
|
# @param temporary_configurations [Hash<Symbol|String,Any>]
|
313
333
|
# @param arbitary_code [Block]
|
314
334
|
# @return [void]
|
@@ -344,6 +364,34 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
|
|
344
364
|
end
|
345
365
|
end
|
346
366
|
|
367
|
+
# @param exportable_object [Object]
|
368
|
+
# @param exported_setting_keys [Array<String,Symbol>]
|
369
|
+
# @option mappings [Hash<String|Symbol,String|Symbol>]
|
370
|
+
# @option raw [Boolean]
|
371
|
+
# @option prefix [String, Symbol]
|
372
|
+
# @return [void]
|
373
|
+
#
|
374
|
+
# @api public
|
375
|
+
# @since 0.18.0
|
376
|
+
def export_settings(
|
377
|
+
exportable_object,
|
378
|
+
*exported_setting_keys,
|
379
|
+
mappings: Qonfig::Imports::Abstract::EMPTY_MAPPINGS,
|
380
|
+
raw: false,
|
381
|
+
prefix: Qonfig::Imports::Abstract::EMPTY_PREFIX
|
382
|
+
)
|
383
|
+
thread_safe_access do
|
384
|
+
Qonfig::Imports::Export.export!(
|
385
|
+
exportable_object,
|
386
|
+
self,
|
387
|
+
*exported_setting_keys,
|
388
|
+
prefix: prefix,
|
389
|
+
raw: raw,
|
390
|
+
mappings: mappings
|
391
|
+
)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
347
395
|
private
|
348
396
|
|
349
397
|
# @return [Qonfig::Validator]
|
data/lib/qonfig/errors.rb
CHANGED
@@ -156,4 +156,28 @@ module Qonfig
|
|
156
156
|
# @api public
|
157
157
|
# @since 0.12.0
|
158
158
|
UnresolvedPluginDependencyError = Class.new(PluginError)
|
159
|
+
|
160
|
+
# @see Qonfig::Imports::Abstract
|
161
|
+
#
|
162
|
+
# @api public
|
163
|
+
# @since 0.18.0
|
164
|
+
IncompatibleImportedConfigError = Class.new(ArgumentError)
|
165
|
+
|
166
|
+
# @see Qonfig::Imports::DirectKey
|
167
|
+
#
|
168
|
+
# @api public
|
169
|
+
# @since 0.18.0
|
170
|
+
IncorrectImportKeyError = Class.new(ArgumentError)
|
171
|
+
|
172
|
+
# @see Qonfig::Imports::Abstract
|
173
|
+
#
|
174
|
+
# @api public
|
175
|
+
# @since 0.18.0
|
176
|
+
IncorrectImportPrefixError = Class.new(ArgumentError)
|
177
|
+
|
178
|
+
# @see Qonfig::Imports::Mappings
|
179
|
+
#
|
180
|
+
# @api public
|
181
|
+
# @since 0.18.0
|
182
|
+
IncorrectImportMappingsError = Class.new(ArgumentError)
|
159
183
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.18.0
|
5
|
+
class Qonfig::Imports::Abstract
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.18.0
|
10
|
+
EMPTY_PREFIX = ''
|
11
|
+
|
12
|
+
# @return [Boolean]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
# @since 0.18.0
|
16
|
+
DEFAULT_RAW_BEHAVIOR = false
|
17
|
+
|
18
|
+
# @param seeded_klass [Class]
|
19
|
+
# @param imported_config [Qonfig::DataSet]
|
20
|
+
# @option prefix [String, Symbol]
|
21
|
+
# @option raw [Boolean]
|
22
|
+
# @return [void]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
# @since 0.18.0
|
26
|
+
def initialize(seeded_klass, imported_config, prefix: EMPTY_PREFIX, raw: DEFAULT_RAW_BEHAVIOR)
|
27
|
+
@seeded_klass = seeded_klass
|
28
|
+
@imported_config = imported_config
|
29
|
+
@prefix = prefix
|
30
|
+
@raw = !!raw
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param settings_interface [Module]
|
34
|
+
# @return [void]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
# @since 0.18.0
|
38
|
+
def import!(settings_interface = Module.new)
|
39
|
+
# :nocov:
|
40
|
+
raise NoMethodError
|
41
|
+
# :nocov:
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# @return [Boolean]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
# @since 0.18.0
|
50
|
+
attr_reader :raw
|
51
|
+
|
52
|
+
# @return [String, Symbol]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
# @since 0.18.0
|
56
|
+
attr_reader :prefix
|
57
|
+
|
58
|
+
# @return [Class]
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
# @since 0.18.0
|
62
|
+
attr_reader :seeded_klass
|
63
|
+
|
64
|
+
# @return [Qonfig::DataSet]
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
# @since 0.18.0
|
68
|
+
attr_reader :imported_config
|
69
|
+
|
70
|
+
# @param imported_config [Qonfig::DataSet]
|
71
|
+
# @param prefix [String, Symbol]
|
72
|
+
# @return [void]
|
73
|
+
#
|
74
|
+
# @raise [Qonfig::IncompatibleImportedConfigError]
|
75
|
+
# @raise [Qonfig::IncorrectImportPrefixError]
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
# @since 0.18.0
|
79
|
+
def prevent_incompatible_import_params!(imported_config, prefix)
|
80
|
+
raise(
|
81
|
+
Qonfig::IncompatibleImportedConfigError,
|
82
|
+
'Imported config object should be an isntance of Qonfig::DataSet'
|
83
|
+
) unless imported_config.is_a?(Qonfig::DataSet)
|
84
|
+
|
85
|
+
raise(
|
86
|
+
Qonfig::IncorrectImportPrefixError,
|
87
|
+
'Import method prefix should be a type of string or symbol'
|
88
|
+
) unless prefix.is_a?(String) || prefix.is_a?(Symbol)
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.18.0
|
5
|
+
class Qonfig::Imports::DirectKey < Qonfig::Imports::Abstract
|
6
|
+
# @param seeded_klass [Class]
|
7
|
+
# @param imported_config [Qonfig::DataSet]
|
8
|
+
# @param keys [Array<String,Symbol>]
|
9
|
+
# @option prefix [String, Symbol]
|
10
|
+
# @option raw [Boolean]
|
11
|
+
# @return [void]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @since 0.18.8
|
15
|
+
def initialize(
|
16
|
+
seeded_klass,
|
17
|
+
imported_config,
|
18
|
+
*keys,
|
19
|
+
prefix: EMPTY_PREFIX,
|
20
|
+
raw: DEFAULT_RAW_BEHAVIOR
|
21
|
+
)
|
22
|
+
prevent_incompatible_import_params!(imported_config, prefix, keys)
|
23
|
+
super(seeded_klass, imported_config, prefix: prefix, raw: raw)
|
24
|
+
@keys = keys
|
25
|
+
@key_matchers = build_setting_key_matchers(keys)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param settings_interfcae [Module]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.18.0
|
33
|
+
def import!(settings_interface = Module.new) # rubocop:disable Metrics/AbcSize
|
34
|
+
key_matchers.each do |key_matcher|
|
35
|
+
raise(
|
36
|
+
Qonfig::UnknownSettingError,
|
37
|
+
"Setting with <#{key_matcher.scope_pattern}> key does not exist!"
|
38
|
+
) unless (imported_config.keys(all_variants: true).any? do |setting_key|
|
39
|
+
key_matcher.match?(setting_key)
|
40
|
+
end)
|
41
|
+
|
42
|
+
imported_config.keys(all_variants: true).each do |setting_key|
|
43
|
+
next unless key_matcher.match?(setting_key)
|
44
|
+
|
45
|
+
setting_key_path_sequence = setting_key.split('.')
|
46
|
+
access_method_name = setting_key_path_sequence.last
|
47
|
+
access_method_name = "#{prefix}#{access_method_name}" unless prefix.empty?
|
48
|
+
|
49
|
+
settings_interface.module_exec(raw, imported_config) do |raw, imported_config|
|
50
|
+
unless raw
|
51
|
+
# NOTE: get setting value via slice_value
|
52
|
+
define_method(access_method_name) do
|
53
|
+
imported_config.slice_value(*setting_key_path_sequence)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
# NOTE: get setting object (concrete value or Qonfig::Settings object)
|
57
|
+
define_method(access_method_name) do
|
58
|
+
imported_config.dig(*setting_key_path_sequence)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# @return [Array<String,Symbol>]
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
# @since 0.18.8
|
72
|
+
attr_reader :keys
|
73
|
+
|
74
|
+
# @return [Array<Qonfig::Settings::KeyMatcher>]
|
75
|
+
#
|
76
|
+
# @api private
|
77
|
+
# @since 0.18.0
|
78
|
+
attr_reader :key_matchers
|
79
|
+
|
80
|
+
# @param imported_config [Qonfig::DataSet]
|
81
|
+
# @param prefix [String, Symbol]
|
82
|
+
# @param keys [Array<String,Symbol>]
|
83
|
+
# @return [void]
|
84
|
+
#
|
85
|
+
# @raise [Qonfig::IncompatibleImportedConfigError]
|
86
|
+
# @raise [Qonfig::IncorrectImportPrefixError]
|
87
|
+
# @raise [Qonfig::IncorrectImportKeyError]
|
88
|
+
#
|
89
|
+
# @see Qonfig::Imports::Abstract#prevent_incompatible_import_params
|
90
|
+
#
|
91
|
+
# @api private
|
92
|
+
# @since 0.18.0
|
93
|
+
def prevent_incompatible_import_params!(imported_config, prefix, keys)
|
94
|
+
super(imported_config, prefix)
|
95
|
+
|
96
|
+
raise(
|
97
|
+
Qonfig::IncorrectImportKeyError,
|
98
|
+
'Imported config keys should be a type of string or symbol'
|
99
|
+
) unless keys.all? { |key| key.is_a?(String) || key.is_a?(Symbol) }
|
100
|
+
end
|
101
|
+
|
102
|
+
# @param keys [Array<String,Symbol>]
|
103
|
+
# @return [Array<Qonfig::KeyMatcher>]
|
104
|
+
#
|
105
|
+
# @api private
|
106
|
+
# @since 0.18.0
|
107
|
+
def build_setting_key_matchers(keys)
|
108
|
+
keys.map { |key| Qonfig::Settings::KeyMatcher.new(key) }
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.18.0
|
5
|
+
module Qonfig::Imports::DSL
|
6
|
+
class << self
|
7
|
+
# @param base_klass [Class]
|
8
|
+
# @return [void]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
# @since 0.18.0
|
12
|
+
def included(base_klass)
|
13
|
+
base_klass.extend(ClassMethods)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
# @since 0.18.0
|
19
|
+
module ClassMethods
|
20
|
+
# @param imported_config [Qonfig::DataSet]
|
21
|
+
# @param imported_setting_keys [Array<String,Symbol>]
|
22
|
+
# @option prefix [String, Symbol]
|
23
|
+
# @option raw [Boolean]
|
24
|
+
# @option mappings [Hash<String|Symbol,String|Symbol>]
|
25
|
+
# @return [void]
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
# @since 0.18.0
|
29
|
+
def import_settings(
|
30
|
+
imported_config,
|
31
|
+
*imported_setting_keys,
|
32
|
+
prefix: Qonfig::Imports::Abstract::EMPTY_PREFIX,
|
33
|
+
raw: Qonfig::Imports::Abstract::DEFAULT_RAW_BEHAVIOR,
|
34
|
+
mappings: Qonfig::Imports::Mappings::EMPTY_MAPPINGS
|
35
|
+
)
|
36
|
+
Qonfig::Imports::General.import!(
|
37
|
+
self,
|
38
|
+
imported_config,
|
39
|
+
*imported_setting_keys,
|
40
|
+
prefix: prefix,
|
41
|
+
raw: raw,
|
42
|
+
mappings: mappings
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.18.0
|
5
|
+
module Qonfig::Imports::Export
|
6
|
+
class << self
|
7
|
+
# @param exportable_object [Object]
|
8
|
+
# @param exported_config [Qonfig::DataSet]
|
9
|
+
# @param exported_setting_keys [Array<String,Symbol>]
|
10
|
+
# @option mappings [Hash<String|Symbol,String|Symbol>]
|
11
|
+
# @option raw [Boolean]
|
12
|
+
# @option prefix [String, Symbol]
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
# @since 0.18.0
|
17
|
+
def export!(
|
18
|
+
exportable_object,
|
19
|
+
exported_config,
|
20
|
+
*exported_setting_keys,
|
21
|
+
mappings: Qonfig::Imports::Abstract::EMPTY_MAPPINGS,
|
22
|
+
raw: false,
|
23
|
+
prefix: Qonfig::Imports::Abstract::EMPTY_PREFIX
|
24
|
+
)
|
25
|
+
unless exportable_object.is_a?(Module)
|
26
|
+
exportable_object = exportable_object.singleton_class
|
27
|
+
end
|
28
|
+
|
29
|
+
Qonfig::Imports::General.import!(
|
30
|
+
exportable_object,
|
31
|
+
exported_config,
|
32
|
+
*exported_setting_keys,
|
33
|
+
prefix: prefix,
|
34
|
+
raw: raw,
|
35
|
+
mappings: mappings
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.18.0
|
5
|
+
class Qonfig::Imports::General
|
6
|
+
class << self
|
7
|
+
# @param seeded_klass [Class, Object]
|
8
|
+
# @param imported_config [Qonfig::DataSet]
|
9
|
+
# @param imported_keys [Array<String, Symbol>]
|
10
|
+
# @option mappings [Hash<String|Symbol,String|Symbol>]
|
11
|
+
# @option prefix [String, Symbol]
|
12
|
+
# @option raw [Boolean]
|
13
|
+
# @return void]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
# @since 0.18.0
|
17
|
+
def import!(
|
18
|
+
seeded_klass,
|
19
|
+
imported_config,
|
20
|
+
*imported_keys,
|
21
|
+
mappings: EMPTY_MAPPINGS,
|
22
|
+
prefix: EMPTY_PREFIX,
|
23
|
+
raw: false
|
24
|
+
)
|
25
|
+
new(
|
26
|
+
seeded_klass,
|
27
|
+
imported_config,
|
28
|
+
*imported_keys,
|
29
|
+
mappings: mappings,
|
30
|
+
prefix: prefix,
|
31
|
+
raw: raw
|
32
|
+
).import!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param seeded_klass [Class, Object]
|
37
|
+
# @param imported_config [Qonfig::DataSet]
|
38
|
+
# @param imported_keys [Array<String, Symbol>]
|
39
|
+
# @option mappings [Hash<String|Symbol,String|Symbol>]
|
40
|
+
# @option prefix [String, Symbol]
|
41
|
+
# @option raw [Boolean]
|
42
|
+
# @return void]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
# @since 0.18.0
|
46
|
+
def initialize(
|
47
|
+
seeded_klass,
|
48
|
+
imported_config,
|
49
|
+
*imported_keys,
|
50
|
+
mappings: EMPTY_MAPPINGS,
|
51
|
+
prefix: EMPTY_PREFIX,
|
52
|
+
raw: false
|
53
|
+
)
|
54
|
+
@seeded_klass = seeded_klass
|
55
|
+
@direct_key_importer = build_direct_key_importer(
|
56
|
+
seeded_klass, imported_config, *imported_keys, prefix: prefix, raw: raw
|
57
|
+
)
|
58
|
+
@mappings_importer = build_mappings_importer(
|
59
|
+
seeded_klass, imported_config, mappings: mappings, prefix: prefix, raw: raw
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param settings_interface [Module]
|
64
|
+
# @return [void]
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
# @since 0.18.0
|
68
|
+
def import!(settings_interface = Module.new)
|
69
|
+
direct_key_importer.import!(settings_interface)
|
70
|
+
mappings_importer.import!(settings_interface)
|
71
|
+
seeded_klass.include(settings_interface)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# @return [Class]
|
77
|
+
#
|
78
|
+
# @api private
|
79
|
+
# @since 0.18.0
|
80
|
+
attr_reader :seeded_klass
|
81
|
+
|
82
|
+
# @return [Qonfig::Imports::DirectKey]
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
# @since 0.18.0
|
86
|
+
attr_reader :direct_key_importer
|
87
|
+
|
88
|
+
# @return [Qonfig::Imports::Mappings]
|
89
|
+
#
|
90
|
+
# @api private
|
91
|
+
# @since 0.18.0
|
92
|
+
attr_reader :mappings_importer
|
93
|
+
|
94
|
+
# @param seeded_klass [Class]
|
95
|
+
# @param imported_config [Qonfig::DataSet]
|
96
|
+
# @param imported_keys [Array<String,Symbol>]
|
97
|
+
# @option prefix [String, Symbol]
|
98
|
+
# @option raw [Boolean]
|
99
|
+
# @return [Qonfig::Imports::DirectKey]
|
100
|
+
#
|
101
|
+
# @api private
|
102
|
+
# @since 0.18.0
|
103
|
+
def build_direct_key_importer(seeded_klass, imported_config, *imported_keys, prefix:, raw:)
|
104
|
+
Qonfig::Imports::DirectKey.new(
|
105
|
+
seeded_klass,
|
106
|
+
imported_config,
|
107
|
+
*imported_keys,
|
108
|
+
prefix: prefix,
|
109
|
+
raw: raw
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param seeded_klass [Class]
|
114
|
+
# @param imported_config [Qonfig::DataSet]
|
115
|
+
# @option mappings [Hash<Symbol|String,Symbol|String>]
|
116
|
+
# @option prefix [String, Symbol]
|
117
|
+
# @option raw [Boolean]
|
118
|
+
# @return [Qonfig::Imports::Mappings]
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
# @since 0.18.0
|
122
|
+
def build_mappings_importer(seeded_klass, imported_config, mappings:, prefix:, raw:)
|
123
|
+
Qonfig::Imports::Mappings.new(
|
124
|
+
seeded_klass,
|
125
|
+
imported_config,
|
126
|
+
mappings: mappings,
|
127
|
+
prefix: prefix,
|
128
|
+
raw: raw
|
129
|
+
)
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.18.0
|
5
|
+
class Qonfig::Imports::Mappings < Qonfig::Imports::Abstract
|
6
|
+
# @return [Hash]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.18.0
|
10
|
+
EMPTY_MAPPINGS = {}.freeze
|
11
|
+
|
12
|
+
# @param seeded_klass [Class]
|
13
|
+
# @param imported_config [Qonfig::DataSet]
|
14
|
+
# @option prefix [String, Symbol]
|
15
|
+
# @option raw [Boolean]
|
16
|
+
# @option mappings [Hash<Symbol|String,Symbol|String>]
|
17
|
+
# @return [void]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
# @since 0.18.0
|
21
|
+
def initialize(
|
22
|
+
seeded_klass,
|
23
|
+
imported_config,
|
24
|
+
mappings: EMPTY_MAPPINGS,
|
25
|
+
prefix: EMPTY_PREFIX,
|
26
|
+
raw: DEFAULT_RAW_BEHAVIOR
|
27
|
+
)
|
28
|
+
prevent_incompatible_import_params!(imported_config, prefix, mappings)
|
29
|
+
super(seeded_klass, imported_config, prefix: prefix, raw: raw)
|
30
|
+
@mappings = mappings
|
31
|
+
@key_matchers = build_setting_key_matchers(mappings)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param settings_interface [Module]
|
35
|
+
# @return [void]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
# @since 0.18.0
|
39
|
+
def import!(settings_interface = Module.new) # rubocop:disable Metrics/AbcSize
|
40
|
+
key_matchers.each_pair do |(mapped_method_name, key_matcher)|
|
41
|
+
raise(
|
42
|
+
Qonfig::UnknownSettingError,
|
43
|
+
"Setting with <#{key_matcher.scope_pattern}> key does not exist!"
|
44
|
+
) unless (imported_config.keys(all_variants: true).any? do |setting_key|
|
45
|
+
key_matcher.match?(setting_key)
|
46
|
+
end)
|
47
|
+
|
48
|
+
imported_config.keys(all_variants: true).each do |setting_key|
|
49
|
+
next unless key_matcher.match?(setting_key)
|
50
|
+
|
51
|
+
setting_key_path_sequence = setting_key.split('.')
|
52
|
+
mapped_method_name = "#{prefix}#{mapped_method_name}" unless prefix.empty?
|
53
|
+
|
54
|
+
settings_interface.module_exec(raw, imported_config) do |raw, imported_config|
|
55
|
+
unless raw
|
56
|
+
# NOTE: get setting value via slice_value
|
57
|
+
define_method(mapped_method_name) do
|
58
|
+
imported_config.slice_value(*setting_key_path_sequence)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
# NOTE: get setting object (concrete value or Qonfig::Settings object)
|
62
|
+
define_method(mapped_method_name) do
|
63
|
+
imported_config.dig(*setting_key_path_sequence)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# @return [Hash<Symbol|String,Symbol|String>]
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
# @since 0.18.0
|
77
|
+
attr_reader :mappings
|
78
|
+
|
79
|
+
# @return [Hash<String|Symbol,Qonfig::Settings::KeyMatcher>]
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
# @since 0.18.0
|
83
|
+
attr_reader :key_matchers
|
84
|
+
|
85
|
+
# @param imported_config [Qonfig::DataSet]
|
86
|
+
# @param prefix [String, Symbol]
|
87
|
+
# @param mappings [Hash<Symbol|String,Symbol|String>]
|
88
|
+
# @return [void]
|
89
|
+
#
|
90
|
+
# @raise [Qonfig::IncompatibleImportedConfigError]
|
91
|
+
# @raise [Qonfig::IncorrectImportPrefixError]
|
92
|
+
# @raise [Qonfig::IncorrectImportMappingsError]
|
93
|
+
#
|
94
|
+
# @see Qonfig::Imports::Abstract#prevent_incompatible_import_params!
|
95
|
+
#
|
96
|
+
# @api private
|
97
|
+
# @since 0.18.0
|
98
|
+
def prevent_incompatible_import_params!(imported_config, prefix, mappings)
|
99
|
+
super(imported_config, prefix)
|
100
|
+
|
101
|
+
raise(
|
102
|
+
Qonfig::IncorrectImportMappingsError,
|
103
|
+
'Import mappings should be a type of hash with String-or-Symbol keys and values'
|
104
|
+
) unless mappings.is_a?(Hash) && (mappings.each_pair.all? do |(mapping_key, mapping_value)|
|
105
|
+
(mapping_key.is_a?(String) || mapping_key.is_a?(Symbol)) &&
|
106
|
+
(mapping_value.is_a?(String) || mapping_value.is_a?(Symbol))
|
107
|
+
end)
|
108
|
+
end
|
109
|
+
|
110
|
+
# @param mappings [Hash<Symbol|String,Symbol|String>]
|
111
|
+
# @return [Hash<String|Symbol,Qonfig::Settings::KeyMatcher>]
|
112
|
+
#
|
113
|
+
# @api private
|
114
|
+
# @since 0.18.0
|
115
|
+
def build_setting_key_matchers(mappings)
|
116
|
+
mappings.each_with_object({}) do |(mapped_method_name, required_setting_key), matchers|
|
117
|
+
matchers[mapped_method_name] = Qonfig::Settings::KeyMatcher.new(required_setting_key)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
# @since 0.18.0
|
5
|
+
module Qonfig::Imports
|
6
|
+
require_relative 'imports/abstract'
|
7
|
+
require_relative 'imports/direct_key'
|
8
|
+
require_relative 'imports/mappings'
|
9
|
+
require_relative 'imports/general'
|
10
|
+
require_relative 'imports/dsl'
|
11
|
+
require_relative 'imports/export'
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# @param base_klass [Class]
|
15
|
+
# @return [void]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
# @since 0.18.0
|
19
|
+
def included(base_klass)
|
20
|
+
base_klass.include(Qonfig::Imports::DSL)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -39,7 +39,13 @@ class Qonfig::Settings::KeyMatcher
|
|
39
39
|
# @since 0.13.0
|
40
40
|
INFINITE_REGEXP_PATTERN = '\.*.*'
|
41
41
|
|
42
|
-
# @
|
42
|
+
# @return [String]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
# @since 0.13.0
|
46
|
+
attr_reader :scope_pattern
|
47
|
+
|
48
|
+
# @param scope_pattern [String, Symbol]
|
43
49
|
# @return [void]
|
44
50
|
#
|
45
51
|
# @raise [Qonfig::ArgumentError]
|
@@ -47,9 +53,10 @@ class Qonfig::Settings::KeyMatcher
|
|
47
53
|
# @api private
|
48
54
|
# @since 0.13.0
|
49
55
|
def initialize(scope_pattern)
|
56
|
+
scope_pattern = scope_pattern.to_s if scope_pattern.is_a?(Symbol)
|
50
57
|
raise Qonfig::ArgumentError unless scope_pattern.is_a?(String)
|
51
58
|
|
52
|
-
@scope_pattern = scope_pattern
|
59
|
+
@scope_pattern = scope_pattern.dup.freeze
|
53
60
|
@scope_pattern_size = count_scope_pattern_size(scope_pattern)
|
54
61
|
@pattern_matcher = build_pattern_matcher(scope_pattern)
|
55
62
|
end
|
@@ -72,12 +79,6 @@ class Qonfig::Settings::KeyMatcher
|
|
72
79
|
# @since 0.13.0
|
73
80
|
attr_reader :pattern_matcher
|
74
81
|
|
75
|
-
# @return [String]
|
76
|
-
#
|
77
|
-
# @api private
|
78
|
-
# @since 0.13.0
|
79
|
-
attr_reader :scope_pattern
|
80
|
-
|
81
82
|
# @return [Integer, Float::INFINITY]
|
82
83
|
#
|
83
84
|
# @api private
|
data/lib/qonfig/settings.rb
CHANGED
@@ -194,11 +194,11 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
194
194
|
# rubocop:disable Metrics/LineLength
|
195
195
|
def __to_hash__(transform_key: BASIC_SETTING_KEY_TRANSFORMER, transform_value: BASIC_SETTING_VALUE_TRANSFORMER)
|
196
196
|
unless transform_key.is_a?(Proc)
|
197
|
-
::Kernel.raise(Qonfig::IncorrectKeyTransformerError, 'Key transformer should be a proc')
|
197
|
+
::Kernel.raise(Qonfig::IncorrectKeyTransformerError, 'Key transformer should be a type of proc')
|
198
198
|
end
|
199
199
|
|
200
200
|
unless transform_value.is_a?(Proc)
|
201
|
-
::Kernel.raise(Qonfig::IncorrectValueTransformerError, 'Value transformer should be a proc')
|
201
|
+
::Kernel.raise(Qonfig::IncorrectValueTransformerError, 'Value transformer should be a type of proc')
|
202
202
|
end
|
203
203
|
|
204
204
|
__lock__.thread_safe_access do
|
@@ -208,6 +208,23 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
208
208
|
# rubocop:enable Metrics/LineLength
|
209
209
|
alias_method :__to_h__, :__to_hash__
|
210
210
|
|
211
|
+
# @option all_variants [Boolean]
|
212
|
+
# @return [Array<String>]
|
213
|
+
#
|
214
|
+
# @api private
|
215
|
+
# @since 0.18.0
|
216
|
+
def __keys__(all_variants: false)
|
217
|
+
__lock__.thread_safe_access { __setting_keys__(all_variants: all_variants) }
|
218
|
+
end
|
219
|
+
|
220
|
+
# @return [Array<String>]
|
221
|
+
#
|
222
|
+
# @api private
|
223
|
+
# @since 0.18.0
|
224
|
+
def __root_keys__
|
225
|
+
__lock__.thread_safe_access { __root_setting_keys__ }
|
226
|
+
end
|
227
|
+
|
211
228
|
# @return [void]
|
212
229
|
#
|
213
230
|
# @api private
|
@@ -289,6 +306,51 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
289
306
|
# @since 0.2.0
|
290
307
|
attr_reader :__lock__
|
291
308
|
|
309
|
+
# @option all_variants [Boolean]
|
310
|
+
# @return [Array<String>]
|
311
|
+
#
|
312
|
+
# @api private
|
313
|
+
# @since 0.18.0
|
314
|
+
def __setting_keys__(all_variants: false)
|
315
|
+
# NOTE: generate a set of keys return simple 'a.b.c.d'
|
316
|
+
setting_keys_set = Set.new.tap do |setting_keys|
|
317
|
+
__deep_each_key_value_pair__ do |setting_key, _setting_value|
|
318
|
+
setting_keys << setting_key
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
if all_variants
|
323
|
+
# NOTE:
|
324
|
+
# We have { a: { b: { c: { d : 1 } } } }
|
325
|
+
# Its mean that we have these keys:
|
326
|
+
# - 'a' # => returns { b: { c: { d: 1 } } }
|
327
|
+
# - 'a.b' # => returns { c: { d: 1 } }
|
328
|
+
# - 'a.b.c' # => returns { d: 1 }
|
329
|
+
# - 'a.b.c.d' # => returns 1
|
330
|
+
# So, get them all :)
|
331
|
+
|
332
|
+
setting_keys_set.each_with_object(Set.new) do |setting_key, varianted_setting_keys|
|
333
|
+
setting_key_paths = setting_key.split('.')
|
334
|
+
combination_size = setting_key_paths.size
|
335
|
+
|
336
|
+
combination_size.times do |merged_key_patterns_count|
|
337
|
+
sub_setting_key = setting_key_paths.slice(0..merged_key_patterns_count).join('.')
|
338
|
+
varianted_setting_keys << sub_setting_key
|
339
|
+
end
|
340
|
+
end
|
341
|
+
else
|
342
|
+
setting_keys_set
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
# @return [Array<String>]
|
347
|
+
#
|
348
|
+
# @api private
|
349
|
+
# @since 0.18.0
|
350
|
+
def __root_setting_keys__
|
351
|
+
__options__.keys
|
352
|
+
end
|
353
|
+
|
292
354
|
# @param key_path [Array<String, Symbol>]
|
293
355
|
# @return [Boolean]
|
294
356
|
#
|
@@ -302,7 +364,7 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
302
364
|
end
|
303
365
|
|
304
366
|
# @param block [Proc]
|
305
|
-
# @return [
|
367
|
+
# @return [Enumerator]
|
306
368
|
#
|
307
369
|
# @yield [setting_key, setting_value]
|
308
370
|
# @yieldparam key [String]
|
@@ -316,7 +378,7 @@ class Qonfig::Settings # NOTE: Layout/ClassStructure is disabled only for CORE_M
|
|
316
378
|
|
317
379
|
# @param initial_setting_key [String, NilClass]
|
318
380
|
# @param block [Proc]
|
319
|
-
# @return [
|
381
|
+
# @return [Enumerator]
|
320
382
|
#
|
321
383
|
# @yield [setting_key, setting_value]
|
322
384
|
# @yieldparam setting_key [String]
|
data/lib/qonfig/version.rb
CHANGED
data/lib/qonfig.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qonfig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rustam Ibragimov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coveralls
|
@@ -158,6 +158,13 @@ files:
|
|
158
158
|
- lib/qonfig/data_set/lock.rb
|
159
159
|
- lib/qonfig/dsl.rb
|
160
160
|
- lib/qonfig/errors.rb
|
161
|
+
- lib/qonfig/imports.rb
|
162
|
+
- lib/qonfig/imports/abstract.rb
|
163
|
+
- lib/qonfig/imports/direct_key.rb
|
164
|
+
- lib/qonfig/imports/dsl.rb
|
165
|
+
- lib/qonfig/imports/export.rb
|
166
|
+
- lib/qonfig/imports/general.rb
|
167
|
+
- lib/qonfig/imports/mappings.rb
|
161
168
|
- lib/qonfig/loaders.rb
|
162
169
|
- lib/qonfig/loaders/basic.rb
|
163
170
|
- lib/qonfig/loaders/dynamic.rb
|