qonfig 0.18.1 → 0.19.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/CHANGELOG.md +14 -0
  4. data/README.md +233 -34
  5. data/Rakefile +4 -2
  6. data/lib/qonfig/command_set.rb +14 -3
  7. data/lib/qonfig/commands/base.rb +37 -0
  8. data/lib/qonfig/commands/definition/add_nested_option.rb +3 -0
  9. data/lib/qonfig/commands/definition/add_option.rb +3 -0
  10. data/lib/qonfig/commands/definition/compose.rb +3 -0
  11. data/lib/qonfig/commands/definition/expose_json.rb +3 -0
  12. data/lib/qonfig/commands/definition/expose_self.rb +3 -0
  13. data/lib/qonfig/commands/definition/expose_yaml.rb +3 -0
  14. data/lib/qonfig/commands/definition/load_from_env.rb +3 -0
  15. data/lib/qonfig/commands/definition/load_from_json.rb +3 -0
  16. data/lib/qonfig/commands/definition/load_from_self.rb +3 -0
  17. data/lib/qonfig/commands/definition/load_from_yaml.rb +3 -0
  18. data/lib/qonfig/commands/instantiation/freeze_state.rb +18 -0
  19. data/lib/qonfig/commands/instantiation/values_file.rb +3 -0
  20. data/lib/qonfig/commands/instantiation.rb +1 -0
  21. data/lib/qonfig/data_set/class_builder.rb +11 -0
  22. data/lib/qonfig/data_set.rb +44 -16
  23. data/lib/qonfig/dsl.rb +10 -3
  24. data/lib/qonfig/errors.rb +24 -5
  25. data/lib/qonfig/plugins/abstract.rb +30 -1
  26. data/lib/qonfig/plugins/access_mixin.rb +11 -0
  27. data/lib/qonfig/plugins/pretty_print/data_set.rb +9 -0
  28. data/lib/qonfig/plugins/pretty_print/mixin.rb +24 -0
  29. data/lib/qonfig/plugins/pretty_print.rb +16 -0
  30. data/lib/qonfig/plugins/registry.rb +21 -0
  31. data/lib/qonfig/plugins/toml.rb +2 -2
  32. data/lib/qonfig/plugins.rb +15 -0
  33. data/lib/qonfig/settings/builder.rb +13 -2
  34. data/lib/qonfig/settings.rb +75 -8
  35. data/lib/qonfig/version.rb +1 -1
  36. data/lib/qonfig.rb +2 -0
  37. data/qonfig.gemspec +1 -1
  38. metadata +12 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ed2259a3f11b04bb0730f73f982228c20263340cd2aa0bd5c4e8d2a418ba04c
4
- data.tar.gz: 318f345a9f6dc250725ad74bc34a12d087e9bf50d8c7c54f3cbc5d29cb211749
3
+ metadata.gz: a79da0cb673ac91a97924b8b6c1a0a6ae193eb3e0529d784debe2b281827f130
4
+ data.tar.gz: f2280966ff22e8ef1bfbe55d62641be2c1edd0f5a7bfca208d832903f7ef85ab
5
5
  SHA512:
6
- metadata.gz: 3c97a92c975202ff93d5317b3e82552a54af184f47980d146239edb528fb7d4523927939d43b0c7d98ae8a1a85b3f29cc0368eaebc164e3b930eebb477c7e10f
7
- data.tar.gz: ea7e2b6e6def6d70eb7fa67f3e83c1e7920068ae253b3e2042a44164bf9486120e37395beee81c318c9ce450106ce5f4f4a0180c53f53c9e1dd3b116a4582508
6
+ metadata.gz: 86521c09f933f5e8deb88fb1a8cecb59e6a050006a76a0b3b18502c900e8cbafcca6fd46bd8b6d45c2caf4e7c007cda319b267951a7a09733f9ef8f4fd22cdd3
7
+ data.tar.gz: 8d180bf77e2a3082843a3a05b5ea36f88de70997100cf829c1824515c9c6c8e23cbcf58ff8f2b908a18efee26563def86bcaf92700ee19b8402b14a0c83f7c73
data/.rubocop.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  inherit_gem:
2
2
  armitage-rubocop:
3
3
  - lib/rubocop.general.yml
4
+ - lib/rubocop.rake.yml
4
5
  - lib/rubocop.rspec.yml
5
6
 
6
7
  AllCops:
data/CHANGELOG.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [0.19.0] - 2019-11-26
5
+ ### Added
6
+ - **FINALY**: support for dot-notation in `#key?`, `#option?`, `#setting?`, `#dig`, `#subset`, `#slice`, `#slice_value`, `[]`;
7
+ - `freeze_state!` DSL directive (all your configs becomes frozen after being instantiated immediately);
8
+ - Global `Qonfig::FrozenError` error for `frozen`-based exceptions;
9
+ - explicit validation of potential setting values:
10
+ - `#valid_with?(configurations = {})` - check that current config instalce will be valid with passed configurations;
11
+ - `.valid_with?(configurations = {})` - check that potential config instancess will be valid with passed configurations;
12
+ - `#pretty_print` plugin :) (`Qonfig.plugin(:pretty_print)`);
13
+ - `Qonfig.loaded_plugins`/`Qonfig.enabled_plugins` - show loaded plugins;
14
+
15
+ ### Changed
16
+ - `Qonfig::FrozenSettingsError` now inherits `Qonfig::FrozenError` type;
17
+
4
18
  ## [0.18.1] - 2019-11-05
5
19
  ### Added
6
20
  - New `yield_all:` attribute for `#deep_each_setting` method (`#deep_each_setting(yield_all: false, &block)`))
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Qonfig · [![Gem Version](https://badge.fury.io/rb/qonfig.svg)](https://badge.fury.io/rb/qonfig) [![Build Status](https://travis-ci.org/0exp/qonfig.svg?branch=master)](https://travis-ci.org/0exp/qonfig) [![Coverage Status](https://coveralls.io/repos/github/0exp/qonfig/badge.svg?branch=master)](https://coveralls.io/github/0exp/qonfig?branch=master)
2
2
 
3
3
  Config. Defined as a class. Used as an instance. Support for inheritance and composition.
4
- Lazy instantiation. Thread-safe. Command-style DSL. Validation layer. Support for **YAML**, **TOML**, **JSON**, **\_\_END\_\_**, **ENV**.
4
+ Lazy instantiation. Thread-safe. Command-style DSL. Validation layer. **DOT-NOTATION**!
5
+ Support for **YAML**, **TOML**, **JSON**, **\_\_END\_\_**, **ENV**.
5
6
  Extremely simple to define. Extremely simple to use. That's all? **NOT** :)
6
7
 
7
8
  ## Installation
@@ -47,7 +48,7 @@ require 'qonfig'
47
48
  - [List of config keys](#list-of-config-keys) (`#keys`, `#root_keys`)
48
49
  - [Config reloading](#config-reloading) (reload config definitions and option values)
49
50
  - [Clear options](#clear-options) (set to `nil`)
50
- - [State freeze](#state-freeze)
51
+ - [Frozen state](#frozen-state) (`.freeze_state!`, `#freeze!`, `#frozen?`)
51
52
  - [Settings as Predicates](#settings-as-predicates)
52
53
  - [Setting key existence](#setting-key-existence) (`#key?`/`#option?`/`#setting?`)
53
54
  - [Run arbitrary code with temporary settings](#run-arbitrary-code-with-temporary-settings) (`#with(configs = {}, &arbitrary_code)`)
@@ -60,6 +61,7 @@ require 'qonfig'
60
61
  - [Proc-based validation](#proc-based-validation)
61
62
  - [Method-based validation](#method-based-validation)
62
63
  - [Predefined validations](#predefined-validations)
64
+ - [Validation of potential setting values](#validation-of-potential-setting-values)
63
65
  - [Work with files](#work-with-files)
64
66
  - **Setting keys definition**
65
67
  - [Load from YAML file](#load-from-yaml-file)
@@ -80,6 +82,7 @@ require 'qonfig'
80
82
  - [Save to YAML file](#save-to-yaml-file) (`#save_to_yaml`)
81
83
  - [Plugins](#plugins)
82
84
  - [toml](#plugins-toml) (support for `TOML` format)
85
+ - [pretty_print](#plugins-pretty_print) (beautified/prettified console output)
83
86
  - [Roadmap](#roadmap)
84
87
  ---
85
88
 
@@ -138,6 +141,8 @@ config.settings.enable_graphql # => false
138
141
 
139
142
  #### access via index-method []
140
143
 
144
+ - without dot-notation:
145
+
141
146
  ```ruby
142
147
  # get option value via index (with indifferent (string / symbol / mixed) access)
143
148
  config.settings[:project_id] # => nil
@@ -158,16 +163,37 @@ config[:project_id] # => nil
158
163
  config[:enable_graphql] # => false
159
164
  ```
160
165
 
166
+ - with dot-notation:
167
+
168
+ ```ruby
169
+ config.settings['vendor_api.host'] # => 'app.service.com'
170
+ config.settings['vendor_api.user'] # => 'test_user'
171
+
172
+ config['vendor_api.host'] # => 'app.service.com'
173
+ config['vendor_api.user'] # => 'test_user'
174
+ ```
175
+
161
176
  #### .dig
162
177
 
178
+ - without dot-notation:
179
+
163
180
  ```ruby
164
181
  # get option value in Hash#dig manner (and fail when the required key does not exist);
165
182
  config.dig(:vendor_api, :host) # => 'app.service.com' # (key exists)
166
183
  config.dig(:vendor_api, :port) # => Qonfig::UnknownSettingError # (key does not exist)
167
184
  ```
168
185
 
186
+ - with dot-notation:
187
+
188
+ ```ruby
189
+ config.dig('vendor_api.host') # => 'app.service.com' # (key exists)
190
+ config.dig('vendor_api.port') # => Qonfig::UnknownSettingError # (key does not exist)
191
+ ```
192
+
169
193
  #### .slice
170
194
 
195
+ - without dot-notation:
196
+
171
197
  ```ruby
172
198
  # get a hash slice of setting options (and fail when the required key does not exist);
173
199
  config.slice(:vendor_api) # => { 'vendor_api' => { 'host' => 'app_service', 'user' => 'test_user' } }
@@ -176,8 +202,18 @@ config.slice(:project_api) # => Qonfig::UnknownSettingError # (key does not exis
176
202
  config.slice(:vendor_api, :port) # => Qonfig::UnknownSettingError # (key does not exist)
177
203
  ```
178
204
 
205
+ - with dot-notation:
206
+
207
+ ```ruby
208
+ config.slice('vendor_api.user') # => { 'user' => 'test_user' }
209
+ config.slice('vendor_api.port') # => Qonfig::UnknownSettingError # (key does not exist)
210
+ ```
211
+
212
+
179
213
  #### .slice_value
180
214
 
215
+ - without dot-notaiton:
216
+
181
217
  ```ruby
182
218
  # get value from the slice of setting options using the given key set
183
219
  # (and fail when the required key does not exist) (works in slice manner);
@@ -188,8 +224,17 @@ config.slice_value(:project_api) # => Qonfig::UnknownSettingError # (key does no
188
224
  config.slice_value(:vendor_api, :port) # => Qonfig::UnknownSettingError # (key does not exist)
189
225
  ```
190
226
 
227
+ - with dot-notation:
228
+
229
+ ```ruby
230
+ config.slice_value('vendor_api.user') # => 'test_user'
231
+ config.slice_value('vendor_api.port') # => Qonfig::UnknownSettingError # (key does not exist)
232
+ ```
233
+
191
234
  #### .subset
192
235
 
236
+ - without dot-notation:
237
+
193
238
  ```ruby
194
239
  # - get a subset (a set of sets) of config settings represented as a hash;
195
240
  # - each key (or key set) represents a requirement of a certain setting key;
@@ -201,6 +246,13 @@ config.subset(:project_id, [:vendor_api, :host], [:credentials, :user, :login])
201
246
  # => { 'project_id' => nil, 'host' => 'app.service.com', 'login' => 'D@iVeR' }
202
247
  ```
203
248
 
249
+ - with dot-notation:
250
+
251
+ ```ruby
252
+ config.subset('project_id', 'vendor_api.host', 'credentials.user.login')
253
+ # => { 'project_id' => nil, 'host' => 'app.service.com', 'login' => 'D@iVeR' }
254
+ ```
255
+
204
256
  ---
205
257
 
206
258
  ### Configuration
@@ -541,7 +593,7 @@ config.settings.web_api # => "api.google.com"
541
593
  - [List of config keys](#list-of-config-keys) (`#keys`, `#root_keys`)
542
594
  - [Config reloading](#config-reloading) (reload config definitions and option values)
543
595
  - [Clear options](#clear-options) (set to `nil`)
544
- - [State freeze](#state-freeze)
596
+ - [Frozen state](#frozen-state) (`.freeze_state!`, `#freeze!`, `#frozen?`)
545
597
  - [Settings as Predicates](#settings-as-predicates)
546
598
  - [Setting key existence](#setting-key-existence) (`#key?`/`#option?`/`#setting?`)
547
599
  - [Run arbitrary code with temporary settings](#run-arbitrary-code-with-temporary-settings)
@@ -787,7 +839,9 @@ config.settings.web_api.endpoint # => nil
787
839
 
788
840
  ---
789
841
 
790
- ### State freeze
842
+ ### Frozen state
843
+
844
+ #### Instance-level
791
845
 
792
846
  - method signature: `#freeze!`;
793
847
 
@@ -811,6 +865,32 @@ config.reload! # => Qonfig::FrozenSettingsError
811
865
  config.clear! # => Qonfig::FrozenSettingsError
812
866
  ```
813
867
 
868
+ #### Definition-level
869
+
870
+ - DSL-method signature: `freeze_state!`
871
+ - indicaes that all your config instances should be frozen;
872
+ - `freeze_state!` DSL command is not inherited (your child and composed config classes will not have this declaration);
873
+
874
+ ```ruby
875
+ # --- base class ---
876
+ class Config < Qonfig::DataSet
877
+ setting :test, true
878
+ freeze_state!
879
+ end
880
+
881
+ config = Config.new
882
+ config.frozen? # => true
883
+ config.settings.test = false # => Qonfig::FrozenSettingsError
884
+
885
+ # --- child class ---
886
+ class InheritedConfig < Config
887
+ end
888
+
889
+ inherited_config = InheritedConfig.new
890
+ config.frozen? # => false
891
+ config.settings.test = false # ok :)
892
+ ```
893
+
814
894
  ---
815
895
 
816
896
  ### Settings as Predicates
@@ -1100,7 +1180,7 @@ service.config_account # => NoMethodError
1100
1180
  # NOTE: export settings as access methods to config's settings
1101
1181
  config.export(service, 'web_api.credentials.account', prefix: 'config_')
1102
1182
 
1103
- service.account # => { "login" => "D@iVeR", "auth_token" => "IAdkoa0@()1239uA" }
1183
+ service.config_account # => { "login" => "D@iVeR", "auth_token" => "IAdkoa0@()1239uA" }
1104
1184
  ```
1105
1185
 
1106
1186
  ---
@@ -1112,6 +1192,7 @@ service.account # => { "login" => "D@iVeR", "auth_token" => "IAdkoa0@()1239uA" }
1112
1192
  - [Proc-based validation](#proc-based-validation)
1113
1193
  - [Method-based validation](#method-based-validation)
1114
1194
  - [Predefined validations](#predefined-validations)
1195
+ - [Validation of potential setting values](#validation-of-potential-setting-values)
1115
1196
 
1116
1197
  ---
1117
1198
 
@@ -1133,11 +1214,12 @@ If you want to check the config object completely you can define a custom valida
1133
1214
  - `strict: true` does not ignores validations for settings with `nil`;
1134
1215
  - `strict: false` is used by default;
1135
1216
  - provides special [key search pattern](#key-search-pattern) for matching setting key names;
1217
+ - you can validate potential setting values without any assignment ([documentation](#validation-of-potential-setting-values))
1136
1218
  - uses the [key search pattern](#key-search-pattern) for definging what the setting key should be validated;
1137
1219
  - you can define your own custom validation logic and validate dataset instance completely;
1138
1220
  - validation logic should return **truthy** or **falsy** value;
1139
- - supprots two validation techniques (**proc-based** ([doc](#proc-based-validation)) and **dataset-method-based** ([doc](#method-based-validation))):
1140
- - **proc-based** (`setting validation`) ([doc](#proc-based-validation))
1221
+ - supprots two validation techniques (**proc-based** ([documentation](#proc-based-validation)) and **dataset-method-based** ([documentation](#method-based-validation))):
1222
+ - **proc-based** (`setting validation`) ([documentation](#proc-based-validation))
1141
1223
  ```ruby
1142
1224
  validate('db.user', strict: true) do |value|
1143
1225
  value.is_a?(String)
@@ -1149,7 +1231,7 @@ If you want to check the config object completely you can define a custom valida
1149
1231
  settings.user == User[1]
1150
1232
  end
1151
1233
  ```
1152
- - **dataset-method-based** (`setting validation`) ([doc](#method-based-validation))
1234
+ - **dataset-method-based** (`setting validation`) ([documentation](#method-based-validation))
1153
1235
  ```ruby
1154
1236
  validate 'db.user', by: :check_user, strict: true
1155
1237
 
@@ -1157,7 +1239,7 @@ If you want to check the config object completely you can define a custom valida
1157
1239
  value.is_a?(String)
1158
1240
  end
1159
1241
  ```
1160
- - **dataset-method-based** (`dataset validation`) ([doc](#method-based-validation))
1242
+ - **dataset-method-based** (`dataset validation`) ([documentation](#method-based-validation))
1161
1243
  ```ruby
1162
1244
  validate by: :check_config, strict: false
1163
1245
 
@@ -1165,24 +1247,9 @@ If you want to check the config object completely you can define a custom valida
1165
1247
  settings.user == User[1]
1166
1248
  end
1167
1249
  ```
1168
- - provides a **set of standard validations** ([doc](#predefined-validations)):
1250
+ - provides a **set of standard validations** ([documentation](#predefined-validations)):
1169
1251
  - DSL: `validate 'key.pattern', :predefned_validator`;
1170
1252
  - supports `strict` behavior;
1171
- - realized validators:
1172
- - `integer`
1173
- - `float`
1174
- - `numeric`
1175
- - `big_decimal`
1176
- - `boolean`
1177
- - `string`
1178
- - `symbol`
1179
- - `text` (string or symbol)
1180
- - `array`
1181
- - `hash`
1182
- - `proc`
1183
- - `class`
1184
- - `module`
1185
- - `not_nil`
1186
1253
 
1187
1254
  ---
1188
1255
 
@@ -1399,6 +1466,52 @@ config.settings.ignorance = nil # => Qonfig::ValidationError (cant be nil)
1399
1466
 
1400
1467
  ---
1401
1468
 
1469
+ ### Validation of potential setting values
1470
+
1471
+ - (**instance-level**) `#valid_with?(configurations = {})` - check that current config instalce will be valid with passed configurations;
1472
+ - (**class-level**) `.valid_with?(configurations = {})` - check that potential config instancess will be valid with passed configurations;
1473
+ - makes no assignments;
1474
+
1475
+ #### #valid_with? (instance-level)
1476
+
1477
+ ```ruby
1478
+ class Config < Qonfig::DataSet
1479
+ setting :enabled, false
1480
+ setting :queue do
1481
+ setting :adapter, 'sidekiq'
1482
+ end
1483
+
1484
+ validate :enabled, :boolean
1485
+ validate 'queue.adapter', :string
1486
+ end
1487
+
1488
+ config = Config.new
1489
+
1490
+ config.valid_with?(enabled: true, queue: { adapter: 'que' }) # => true
1491
+ config.valid_with?(enabled: 123) # => false (should be a type of boolean)
1492
+ config.valid_with?(enabled: true, queue: { adapter: Sidekiq }) # => false (queue.adapter should be a type of string)
1493
+ ```
1494
+
1495
+ #### .valid_with? (class-level)
1496
+
1497
+ ```ruby
1498
+ class Config < Qonfig::DataSet
1499
+ setting :enabled, false
1500
+ setting :queue do
1501
+ setting :adapter, 'sidekiq'
1502
+ end
1503
+
1504
+ validate :enabled, :boolean
1505
+ validate 'queue.adapter', :string
1506
+ end
1507
+
1508
+ Config.valid_with?(enabled: true, queue: { adapter: 'que' }) # => true
1509
+ Config.valid_with?(enabled: 123) # => false (should be a type of boolean)
1510
+ Config.valid_with?(enabled: true, queue: { adapter: Sidekiq }) # => false (queue.adapter should be a type of string)
1511
+ ```
1512
+
1513
+ ---
1514
+
1402
1515
  ## Work with files
1403
1516
 
1404
1517
  - **Setting keys definition**
@@ -2519,17 +2632,36 @@ dynamic: 10
2519
2632
 
2520
2633
  ### Plugins
2521
2634
 
2635
+ - [toml](#plugins-toml) (provides `load_from_toml`, `save_to_toml`, `expose_toml`);
2636
+ - [pretty_print](#plugins-pretty_print) (beautified/prettified console output);
2637
+
2638
+ ---
2639
+
2640
+ #### Usage
2641
+
2642
+ - show available plugins:
2643
+
2522
2644
  ```ruby
2523
- # --- show names of registered plugins ---
2524
- Qonfig.plugins # => array of strings
2645
+ Qonfig.plugins # => ["pretty_print", "toml", ..., ...]
2646
+ ```
2647
+
2648
+ - load specific plugin:
2525
2649
 
2526
- # --- load specific plugin ---
2527
- Qonfig.plugin(:plugin_name) # or Qonfig.plugin('plugin_name')
2650
+ ```ruby
2651
+ Qonfig.plugin(:pretty_print) # or Qonfig.plugin('pretty_print')
2652
+ # -- or --
2653
+ Qonfig.enable(:pretty_print) # or Qonfig.enable('pretty_print')
2654
+ # -- or --
2655
+ Qonfig.load(:pretty_print) # or Qonfig.load('pretty_print')
2528
2656
  ```
2529
2657
 
2530
- Provided plugins:
2658
+ - show load plugins:
2531
2659
 
2532
- - [toml](#plugins-toml) (provides `load_from_toml`, `save_to_toml`, `expose_toml`)
2660
+ ```ruby
2661
+ Qonfig.loaded_plugins # => ["pretty_print"]
2662
+ # -- or --
2663
+ Qonfig.enabled_plugins # => ["pretty_print"]
2664
+ ```
2533
2665
 
2534
2666
  ---
2535
2667
 
@@ -2551,8 +2683,77 @@ require 'toml-rb'
2551
2683
  # 2) enable plugin
2552
2684
  Qonfig.plugin(:toml)
2553
2685
 
2554
- # 3) use :)
2686
+ # 3) use toml :)
2555
2687
  ```
2688
+
2689
+ ---
2690
+
2691
+ ### Plugins: pretty_print
2692
+
2693
+ - `Qonfig.plugin(:pretty_print)`
2694
+ - gives you really comfortable and beautiful console output;
2695
+ - represents all setting keys in dot-notation format;
2696
+
2697
+ #### Example:
2698
+
2699
+ ```ruby
2700
+ class Config < Qonfig::DataSet
2701
+ setting :api do
2702
+ setting :domain, 'google.ru'
2703
+ setting :creds do
2704
+ setting :account, 'D@iVeR'
2705
+ setting :password, 'test123'
2706
+ end
2707
+ end
2708
+
2709
+ setting :log_requests, true
2710
+ setting :use_proxy, true
2711
+ end
2712
+
2713
+ config = Config.new
2714
+ ```
2715
+
2716
+ - before:
2717
+
2718
+ ```shell
2719
+ => #<Config:0x00007f9b6c01dab0
2720
+ @__lock__=
2721
+ #<Qonfig::DataSet::Lock:0x00007f9b6c01da60
2722
+ @access_lock=#<Thread::Mutex:0x00007f9b6c01da38>,
2723
+ @arbitary_lock=#<Thread::Mutex:0x00007f9b6c01d9e8>,
2724
+ @definition_lock=#<Thread::Mutex:0x00007f9b6c01da10>>,
2725
+ @settings=
2726
+ #<Qonfig::Settings:0x00007f9b6c01d858
2727
+ @__lock__=
2728
+ #<Qonfig::Settings::Lock:0x00007f9b6c01d808
2729
+ @access_lock=#<Thread::Mutex:0x00007f9b6c01d7b8>,
2730
+ @definition_lock=#<Thread::Mutex:0x00007f9b6c01d7e0>,
2731
+ @merge_lock=#<Thread::Mutex:0x00007f9b6c01d790>>,
2732
+ @__mutation_callbacks__=
2733
+ #<Qonfig::Settings::Callbacks:0x00007f9b6c01d8d0
2734
+ @callbacks=[#<Proc:0x00007f9b6c01d8f8@/Users/daiver/Projects/qonfig/lib/qonfig/settings/builder.rb:39>],
2735
+ @lock=#<Thread::Mutex:0x00007f9b6c01d880>>,
2736
+ @__options__=
2737
+ {"api"=>
2738
+ #<Qonfig::Settings:0x00007f9b6c01d498
2739
+ # ... and etc
2740
+ ```
2741
+
2742
+ - after:
2743
+
2744
+ ```shell
2745
+ => #<Config:0x00007f9b6c01dab0
2746
+ api.domain: "google.ru",
2747
+ api.creds.account: "D@iVeR",
2748
+ api.creds.password: "test123",
2749
+ log_requests: true,
2750
+ use_proxy: true>
2751
+
2752
+ # -- or --
2753
+
2754
+ => #<Config:0x00007f9b6c01dab0 api.domain: "google.ru", api.creds.account: "D@iVeR", api.creds.password: "test123", log_requests: true, use_proxy: true>
2755
+ ```
2756
+
2556
2757
  ---
2557
2758
 
2558
2759
  ## Roadmap
@@ -2565,8 +2766,6 @@ Qonfig.plugin(:toml)
2565
2766
  - Rails reload plugin;
2566
2767
  - **Minor**:
2567
2768
  - custom global (and class-level) validators (with a special Validator Definition DSL);
2568
- - support for "dot notation" in `#key?`, `#option?`, `#setting?`, `#dig`, `#subset`, `#slice`, `#slice_value`;
2569
- - pretty print :)));
2570
2769
 
2571
2770
  ## Contributing
2572
2771
 
data/Rakefile CHANGED
@@ -3,16 +3,18 @@
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
5
  require 'rubocop'
6
- require 'rubocop-rspec'
6
+ require 'rubocop-rails'
7
7
  require 'rubocop-performance'
8
+ require 'rubocop-rspec'
9
+ require 'rubocop-rake'
8
10
  require 'rubocop/rake_task'
9
11
 
10
12
  RuboCop::RakeTask.new(:rubocop) do |t|
11
13
  config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
12
-
13
14
  t.options = ['--config', config_path]
14
15
  t.requires << 'rubocop-rspec'
15
16
  t.requires << 'rubocop-performance'
17
+ t.requires << 'rubocop-rake'
16
18
  end
17
19
 
18
20
  RSpec::Core::RakeTask.new(:rspec)
@@ -42,12 +42,22 @@ class Qonfig::CommandSet
42
42
  end
43
43
 
44
44
  # @param command_set [Qonfig::CommandSet]
45
+ # @param concat_condition [Block]
46
+ # @yield [command]
47
+ # @yieldparam command [Qonfig::Commands::Base]
45
48
  # @return [void]
46
49
  #
47
50
  # @api private
48
51
  # @since 0.1.0
49
- def concat(command_set)
50
- thread_safe { commands.concat(command_set.commands) }
52
+ # @version 0.19.0
53
+ def concat(command_set, &concant_condition)
54
+ thread_safe do
55
+ if block_given?
56
+ command_set.each { |command| (commands << command) if yield(command) }
57
+ else
58
+ command_set.each { |command| commands << command }
59
+ end
60
+ end
51
61
  end
52
62
 
53
63
  # @return [Qonfig::CommandSet]
@@ -67,7 +77,8 @@ class Qonfig::CommandSet
67
77
  #
68
78
  # @api private
69
79
  # @since 0.2.0
80
+ # @version 0.19.0
70
81
  def thread_safe(&block)
71
- @access_lock.synchronize(&block)
82
+ @access_lock.owned? ? yield : @access_lock.synchronize(&block)
72
83
  end
73
84
  end
@@ -3,6 +3,35 @@
3
3
  # @api private
4
4
  # @since 0.1.0
5
5
  class Qonfig::Commands::Base
6
+ class << self
7
+ # @param identifier [Boolean]
8
+ # @return [Boolean]
9
+ #
10
+ # @api private
11
+ # @since 0.19.0
12
+ def inheritable=(identifier)
13
+ @inheritable = identifier
14
+ end
15
+
16
+ # @return [Boolean]
17
+ #
18
+ # @api private
19
+ # @since 0.19.0
20
+ def inheritable?
21
+ @inheritable
22
+ end
23
+
24
+ # @param child_klass [Class]
25
+ # @return [Boolean]
26
+ #
27
+ # @api private
28
+ # @since 0.19.0
29
+ def inherited(child_klass)
30
+ child_klass.instance_variable_set(:@inheritable, true)
31
+ super
32
+ end
33
+ end
34
+
6
35
  # @param data_set [Qonfig::DataSet]
7
36
  # @param settings [Qonfig::Settings]
8
37
  # @return [void]
@@ -10,4 +39,12 @@ class Qonfig::Commands::Base
10
39
  # @api private
11
40
  # @since 0.1.0
12
41
  def call(data_set, settings); end
42
+
43
+ # @return [Boolean]
44
+ #
45
+ # @api private
46
+ # @since 0.19.0
47
+ def inheritable?
48
+ self.class.inheritable?
49
+ end
13
50
  end
@@ -3,6 +3,9 @@
3
3
  # @api private
4
4
  # @since 0.1.0
5
5
  class Qonfig::Commands::Definition::AddNestedOption < Qonfig::Commands::Base
6
+ # @since 0.19.0
7
+ self.inheritable = true
8
+
6
9
  # @return [Symbol, String]
7
10
  #
8
11
  # @api private
@@ -3,6 +3,9 @@
3
3
  # @api private
4
4
  # @since 0.1.0
5
5
  class Qonfig::Commands::Definition::AddOption < Qonfig::Commands::Base
6
+ # @since 0.19.0
7
+ self.inheritable = true
8
+
6
9
  # @return [Symbol, String]
7
10
  #
8
11
  # @api private
@@ -3,6 +3,9 @@
3
3
  # @api private
4
4
  # @since 0.1.0
5
5
  class Qonfig::Commands::Definition::Compose < Qonfig::Commands::Base
6
+ # @since 0.19.0
7
+ self.inheritable = true
8
+
6
9
  # @return [Qonfig::DataSet]
7
10
  #
8
11
  # @api private
@@ -3,6 +3,9 @@
3
3
  # @api private
4
4
  # @since 0.14.0
5
5
  class Qonfig::Commands::Definition::ExposeJSON < Qonfig::Commands::Base
6
+ # @since 0.19.0
7
+ self.inheritable = true
8
+
6
9
  # @return [Hash]
7
10
  #
8
11
  # @api private
@@ -3,6 +3,9 @@
3
3
  # @api private
4
4
  # @since 0.14.0
5
5
  class Qonfig::Commands::Definition::ExposeSelf < Qonfig::Commands::Base
6
+ # @since 0.19.0
7
+ self.inheritable = true
8
+
6
9
  # @return [String, Symbol]
7
10
  #
8
11
  # @api private
@@ -3,6 +3,9 @@
3
3
  # @api private
4
4
  # @since 0.7.0
5
5
  class Qonfig::Commands::Definition::ExposeYAML < Qonfig::Commands::Base
6
+ # @since 0.19.0
7
+ self.inheritable = true
8
+
6
9
  # @return [Hash]
7
10
  #
8
11
  # @api private
@@ -5,6 +5,9 @@
5
5
  class Qonfig::Commands::Definition::LoadFromENV < Qonfig::Commands::Base
6
6
  require_relative 'load_from_env/value_converter'
7
7
 
8
+ # @since 0.19.0
9
+ self.inheritable = true
10
+
8
11
  # @return [Boolean]
9
12
  #
10
13
  # @api private
@@ -3,6 +3,9 @@
3
3
  # @api private
4
4
  # @since 0.5.0
5
5
  class Qonfig::Commands::Definition::LoadFromJSON < Qonfig::Commands::Base
6
+ # @since 0.19.0
7
+ self.inheritable = true
8
+
6
9
  # @return [String]
7
10
  #
8
11
  # @api private
@@ -3,6 +3,9 @@
3
3
  # @api private
4
4
  # @since 0.2.0
5
5
  class Qonfig::Commands::Definition::LoadFromSelf < Qonfig::Commands::Base
6
+ # @since 0.19.0
7
+ self.inheritable = true
8
+
6
9
  # @return [String, Symbol]
7
10
  #
8
11
  # @api private