qonfig 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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