qonfig 0.18.1 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
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