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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 985bd788cc637ab9a63a813e1a9a59510d4ea093c2d45101962fb28804688510
4
- data.tar.gz: 39018ae2f6eedb1049736164f00bb34abffe64fa045858e3908054099e83b66a
3
+ metadata.gz: ec197a7e1d7185ff8c4e5906e244c5cbce610d1449dc60cfb1d2a167a2e79921
4
+ data.tar.gz: 47d2d394cfcc97cf5ab58a198865490ecd4c9494c7ee7096474ff7a6f0c5d7f2
5
5
  SHA512:
6
- metadata.gz: 51aa8022ab1a25cafc4dd68f740b2aa4edcc63e8b1c58aa95863c12ce288d6da74c177f764cfc5a829cb0d46bff1699afb4a87d1df93ea780c345ad0e452b9b2
7
- data.tar.gz: 0d946fc7542ac3816bbf3e00f73a386e3178195bb2281a26d52e75c7b3bd57fe810213d8109c5d45db3d6713bfacb65603bc6373e593572a70d012ff3cea8c40
6
+ metadata.gz: 87e2688f74aa2dba959c423ea79ec36686c1873e20654826ad4eefc599da6f0d9967066e8de605b0f0a83d58465ecdb3f061e193fedc1aef6223d03794ffff7f
7
+ data.tar.gz: 107ccfc0dfe0ee109765699c4af58d431edd572d6ea30dace2449ff87d991bc8dbb555dedf95ccf7d3101cac2fb728fd7e44dec5c8a04a74583b006926e8ec46
data/.rubocop.yml CHANGED
@@ -21,3 +21,7 @@ RSpec/LeakyConstantDeclaration:
21
21
  # NOTE: support for old ruby versions
22
22
  Style/RedundantBegin:
23
23
  Enabled: false
24
+
25
+ # NOTE: too situative
26
+ Metrics/ParameterLists:
27
+ Enabled: false
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
- ## [Unreleased]
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 arbitary code with temporary settings](#run-arbitary-code-with-temporary-settings) (`#with(configs = {}, &arbitary_code)`)
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) (provides `load_from_toml`, `save_to_toml`, `expose_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 arbitary code with temporary settings](#run-arbitary-code-with-temporary-settings)
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 arbitary code with temporary settings
876
+ ### Run arbitrary code with temporary settings
760
877
 
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;
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 # => Qonfig::FileNotFoundError
2042
+ config = Config.new # no error
1744
2043
 
1745
- # non-strict behavior (strict: false)
2044
+ # strict behavior (strict: true)
1746
2045
  class Config < Qonfig::DataSet
1747
- values_file 'sidekiq.yml', strict: false
2046
+ values_file 'sidekiq.yml', strict: true
1748
2047
  end
1749
2048
 
1750
- config = Config.new # no error
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
@@ -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 inherited class should be a type of Qonfig::DataSet')
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
- # @param scope_pattern [String]
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
@@ -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 [Enumerable]
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 [Enumerable]
381
+ # @return [Enumerator]
320
382
  #
321
383
  # @yield [setting_key, setting_value]
322
384
  # @yieldparam setting_key [String]
@@ -5,5 +5,5 @@ module Qonfig
5
5
  #
6
6
  # @api public
7
7
  # @since 0.1.0
8
- VERSION = '0.17.0'
8
+ VERSION = '0.18.0'
9
9
  end
data/lib/qonfig.rb CHANGED
@@ -15,6 +15,7 @@ module Qonfig
15
15
  require_relative 'qonfig/dsl'
16
16
  require_relative 'qonfig/data_set'
17
17
  require_relative 'qonfig/configurable'
18
+ require_relative 'qonfig/imports'
18
19
  require_relative 'qonfig/plugins'
19
20
 
20
21
  # @api public
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.17.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-10-30 00:00:00.000000000 Z
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