qonfig 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -1
  4. data/.rubocop.yml +1 -1
  5. data/.travis.yml +3 -3
  6. data/CHANGELOG.md +10 -0
  7. data/README.md +146 -1
  8. data/Rakefile +2 -0
  9. data/lib/qonfig/command_set.rb +53 -55
  10. data/lib/qonfig/commands/add_nested_option.rb +36 -40
  11. data/lib/qonfig/commands/add_option.rb +33 -37
  12. data/lib/qonfig/commands/base.rb +9 -13
  13. data/lib/qonfig/commands/compose.rb +29 -33
  14. data/lib/qonfig/commands/expose_yaml.rb +154 -158
  15. data/lib/qonfig/commands/load_from_env.rb +77 -79
  16. data/lib/qonfig/commands/load_from_json.rb +52 -56
  17. data/lib/qonfig/commands/load_from_self.rb +57 -61
  18. data/lib/qonfig/commands/load_from_yaml.rb +54 -58
  19. data/lib/qonfig/commands.rb +15 -0
  20. data/lib/qonfig/configurable.rb +88 -90
  21. data/lib/qonfig/data_set/class_builder.rb +17 -21
  22. data/lib/qonfig/data_set.rb +186 -138
  23. data/lib/qonfig/dsl.rb +106 -108
  24. data/lib/qonfig/{error.rb → exceptions.rb} +13 -1
  25. data/lib/qonfig/loaders/basic.rb +30 -32
  26. data/lib/qonfig/loaders/json.rb +16 -23
  27. data/lib/qonfig/loaders/yaml.rb +16 -23
  28. data/lib/qonfig/loaders.rb +9 -0
  29. data/lib/qonfig/plugins/abstract.rb +7 -11
  30. data/lib/qonfig/plugins/access_mixin.rb +21 -25
  31. data/lib/qonfig/plugins/registry.rb +120 -124
  32. data/lib/qonfig/plugins.rb +56 -54
  33. data/lib/qonfig/settings/builder.rb +10 -14
  34. data/lib/qonfig/settings/key_guard.rb +60 -64
  35. data/lib/qonfig/settings/lock.rb +53 -57
  36. data/lib/qonfig/settings.rb +392 -354
  37. data/lib/qonfig/uploaders/base.rb +18 -0
  38. data/lib/qonfig/uploaders/file.rb +55 -0
  39. data/lib/qonfig/uploaders/json.rb +35 -0
  40. data/lib/qonfig/uploaders/yaml.rb +93 -0
  41. data/lib/qonfig/uploaders.rb +10 -0
  42. data/lib/qonfig/version.rb +1 -1
  43. data/lib/qonfig.rb +4 -21
  44. data/qonfig.gemspec +1 -1
  45. metadata +13 -6
@@ -1,419 +1,457 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Qonfig
4
- # rubocop:disable Metrics/ClassLength
3
+ # @api private
4
+ # @since 0.1.0
5
+ # rubocop:disable Metrics/ClassLength
6
+ class Qonfig::Settings
7
+ require_relative 'settings/lock'
8
+ require_relative 'settings/builder'
9
+ require_relative 'settings/key_guard'
10
+
11
+ # @return [Proc]
12
+ #
13
+ # @api private
14
+ # @since 0.11.0
15
+ BASIC_SETTING_KEY_TRANSFORMER = (proc { |value| value }).freeze
16
+
17
+ # @return [Proc]
18
+ #
19
+ # @api private
20
+ # @since 0.11.0
21
+ BASIC_SETTING_VALUE_TRANSFORMER = (proc { |value| value }).freeze
5
22
 
23
+ # @return [Hash]
24
+ #
6
25
  # @api private
7
26
  # @since 0.1.0
8
- class Settings
9
- # @return [Hash]
10
- #
11
- # @api private
12
- # @since 0.1.0
13
- attr_reader :__options__
14
-
15
- # @api private
16
- # @since 0.1.0
17
- def initialize
18
- @__options__ = {}
19
- @__lock__ = Lock.new
20
- end
27
+ attr_reader :__options__
21
28
 
22
- # @param key [Symbol, String]
23
- # @param value [Object]
24
- # @return [void]
25
- #
26
- # @api private
27
- # @since 0.1.0
28
- def __define_setting__(key, value)
29
- __lock__.thread_safe_definition do
30
- key = __indifferently_accessable_option_key__(key)
31
-
32
- __prevent_core_method_intersection__(key)
33
-
34
- case
35
- when !__options__.key?(key)
36
- __options__[key] = value
37
- when __options__[key].is_a?(Qonfig::Settings) && value.is_a?(Qonfig::Settings)
38
- __options__[key].__append_settings__(value)
39
- else
40
- __options__[key] = value
41
- end
42
-
43
- __define_accessor__(key)
44
- end
45
- end
29
+ # @api private
30
+ # @since 0.1.0
31
+ def initialize
32
+ @__options__ = {}
33
+ @__lock__ = Lock.new
34
+ end
35
+
36
+ # @param key [Symbol, String]
37
+ # @param value [Object]
38
+ # @return [void]
39
+ #
40
+ # @api private
41
+ # @since 0.1.0
42
+ def __define_setting__(key, value)
43
+ __lock__.thread_safe_definition do
44
+ key = __indifferently_accessable_option_key__(key)
45
+
46
+ __prevent_core_method_intersection__(key)
46
47
 
47
- # @param settings [Qonfig::Settings]
48
- # @return [void]
49
- #
50
- # @api private
51
- # @since 0.1.0
52
- def __append_settings__(settings)
53
- __lock__.thread_safe_merge do
54
- settings.__options__.each_pair do |key, value|
55
- __define_setting__(key, value)
56
- end
48
+ case
49
+ when !__options__.key?(key)
50
+ __options__[key] = value
51
+ when __options__[key].is_a?(Qonfig::Settings) && value.is_a?(Qonfig::Settings)
52
+ __options__[key].__append_settings__(value)
53
+ else
54
+ __options__[key] = value
57
55
  end
58
- end
59
56
 
60
- # @param key [Symbol, String]
61
- # @return [Object]
62
- #
63
- # @api public
64
- # @since 0.1.0
65
- def [](key)
66
- __lock__.thread_safe_access { __get_value__(key) }
57
+ __define_accessor__(key)
67
58
  end
59
+ end
68
60
 
69
- # @param key [String, Symbol]
70
- # @param value [Object]
71
- # @return [void]
72
- #
73
- # @api public
74
- # @since 0.1.0
75
- def []=(key, value)
76
- __lock__.thread_safe_access { __set_value__(key, value) }
61
+ # @param settings [Qonfig::Settings]
62
+ # @return [void]
63
+ #
64
+ # @api private
65
+ # @since 0.1.0
66
+ def __append_settings__(settings)
67
+ __lock__.thread_safe_merge do
68
+ settings.__options__.each_pair do |key, value|
69
+ __define_setting__(key, value)
70
+ end
77
71
  end
72
+ end
78
73
 
79
- # @param options_map [Hash]
80
- # @return [void]
81
- #
82
- # @api private
83
- # @since 0.3.0
84
- def __apply_values__(options_map)
85
- __lock__.thread_safe_access { __set_values_from_map__(options_map) }
86
- end
74
+ # @param key [Symbol, String]
75
+ # @return [Object]
76
+ #
77
+ # @api public
78
+ # @since 0.1.0
79
+ def [](key)
80
+ __lock__.thread_safe_access { __get_value__(key) }
81
+ end
87
82
 
88
- # @param keys [Array<String, Symbol>]
89
- # @return [Object]
90
- #
91
- # @api private
92
- # @since 0.2.0
93
- def __dig__(*keys)
94
- __lock__.thread_safe_access { __deep_access__(*keys) }
95
- end
83
+ # @param key [String, Symbol]
84
+ # @param value [Object]
85
+ # @return [void]
86
+ #
87
+ # @api public
88
+ # @since 0.1.0
89
+ def []=(key, value)
90
+ __lock__.thread_safe_access { __set_value__(key, value) }
91
+ end
96
92
 
97
- # @param keys [Array<String, Symbol>]
98
- # @return [Hash]
99
- #
100
- # @api private
101
- # @since 0.9.0
102
- def __slice__(*keys)
103
- __lock__.thread_safe_access { __deep_slice__(*keys) }
104
- end
93
+ # @param options_map [Hash]
94
+ # @return [void]
95
+ #
96
+ # @api private
97
+ # @since 0.3.0
98
+ def __apply_values__(options_map)
99
+ __lock__.thread_safe_access { __set_values_from_map__(options_map) }
100
+ end
105
101
 
106
- # @param keys [Array<String, Symbol>]
107
- # @return [Hash, Any]
108
- #
109
- # @api private
110
- # @since 0.10.0
111
- def __slice_value__(*keys)
112
- __lock__.thread_safe_access { __deep_slice_value__(*keys) }
113
- end
102
+ # @param keys [Array<String, Symbol>]
103
+ # @return [Object]
104
+ #
105
+ # @api private
106
+ # @since 0.2.0
107
+ def __dig__(*keys)
108
+ __lock__.thread_safe_access { __deep_access__(*keys) }
109
+ end
114
110
 
115
- # @return [Hash]
116
- #
117
- # @api private
118
- # @since 0.1.0
119
- def __to_hash__
120
- __lock__.thread_safe_access { __build_hash_representation__ }
121
- end
122
- alias_method :__to_h__, :__to_hash__
123
-
124
- # @return [void]
125
- #
126
- # @api private
127
- # @since 0.2.0
128
- def __clear__
129
- __lock__.thread_safe_access { __clear_option_values__ }
130
- end
111
+ # @param keys [Array<String, Symbol>]
112
+ # @return [Hash]
113
+ #
114
+ # @api private
115
+ # @since 0.9.0
116
+ def __slice__(*keys)
117
+ __lock__.thread_safe_access { __deep_slice__(*keys) }
118
+ end
131
119
 
132
- # @param method_name [String, Symbol]
133
- # @param arguments [Array<Object>]
134
- # @param block [Proc]
135
- # @return [void]
136
- #
137
- # @raise [Qonfig::UnknownSettingError]
138
- #
139
- # @api private
140
- # @since 0.1.0
141
- def method_missing(method_name, *arguments, &block)
142
- super
143
- rescue NoMethodError
144
- ::Kernel.raise(Qonfig::UnknownSettingError, "Setting with <#{method_name}> key doesnt exist!")
145
- end
120
+ # @param keys [Array<String, Symbol>]
121
+ # @return [Hash, Any]
122
+ #
123
+ # @api private
124
+ # @since 0.10.0
125
+ def __slice_value__(*keys)
126
+ __lock__.thread_safe_access { __deep_slice_value__(*keys) }
127
+ end
146
128
 
147
- # @return [Boolean]
148
- #
149
- # @api private
150
- # @since 0.1.0
151
- def respond_to_missing?(method_name, include_private = false)
152
- # :nocov:
153
- __options__.key?(method_name.to_s) || __options__.key?(method_name.to_sym) || super
154
- # :nocov:
129
+ # @option transform_key [Proc]
130
+ # @option transform_value [Proc]
131
+ # @return [Hash]
132
+ #
133
+ # @api private
134
+ # @since 0.1.0
135
+ # rubocop:disable Metrics/LineLength
136
+ def __to_hash__(transform_key: BASIC_SETTING_KEY_TRANSFORMER, transform_value: BASIC_SETTING_VALUE_TRANSFORMER)
137
+ unless transform_key.is_a?(Proc)
138
+ ::Kernel.raise(Qonfig::IncorrectKeyTransformerError, 'Key transformer should be a proc')
155
139
  end
156
140
 
157
- # @return [void]
158
- #
159
- # @api private
160
- # @since 0.1.0
161
- def __freeze__
162
- __lock__.thread_safe_access do
163
- __options__.freeze
164
-
165
- __options__.each_value do |value|
166
- value.__freeze__ if value.is_a?(Qonfig::Settings)
167
- end
168
- end
141
+ unless transform_value.is_a?(Proc)
142
+ ::Kernel.raise(Qonfig::IncorrectValueTransformerError, 'Value transformer should be a proc')
169
143
  end
170
144
 
171
- # @return [Boolean]
172
- #
173
- # @api private
174
- # @since 0.2.0
175
- def __is_frozen__
176
- __lock__.thread_safe_access { __options__.frozen? }
145
+ __lock__.thread_safe_access do
146
+ __build_hash_representation__(transform_key: transform_key, transform_value: transform_value)
177
147
  end
148
+ end
149
+ # rubocop:enable Metrics/LineLength
150
+ alias_method :__to_h__, :__to_hash__
178
151
 
179
- private
180
-
181
- # @return [Qonfig::Settings::Lock]
182
- #
183
- # @api private
184
- # @since 0.2.0
185
- attr_reader :__lock__
186
-
187
- # @param options_map [Hash]
188
- # @return [void]
189
- #
190
- # @raise [Qonfig::ArgumentError]
191
- # @raise [Qonfig::AmbiguousSettingValueError]
192
- #
193
- # @api private
194
- # @since 0.3.0
195
- def __set_values_from_map__(options_map)
196
- ::Kernel.raise(
197
- Qonfig::ArgumentError, 'Options map should be represented as a hash'
198
- ) unless options_map.is_a?(Hash)
199
-
200
- options_map.each_pair do |key, value|
201
- current_value = __get_value__(key)
202
-
203
- # NOTE: some duplications here was made only for the better code readability
204
- case
205
- when !current_value.is_a?(Qonfig::Settings)
206
- __set_value__(key, value)
207
- when current_value.is_a?(Qonfig::Settings) && value.is_a?(Hash)
208
- current_value.__apply_values__(value)
209
- when current_value.is_a?(Qonfig::Settings) && !value.is_a?(Hash)
210
- ::Kernel.raise(
211
- Qonfig::AmbiguousSettingValueError,
212
- "Can not redefine option <#{key}> that contains nested options"
213
- )
214
- end
215
- end
216
- end
152
+ # @return [void]
153
+ #
154
+ # @api private
155
+ # @since 0.2.0
156
+ def __clear__
157
+ __lock__.thread_safe_access { __clear_option_values__ }
158
+ end
217
159
 
218
- # @return [void]
219
- #
220
- # @raise [Qonfig::FrozenSettingsError]
221
- #
222
- # @api private
223
- # @since 0.2.0
224
- def __clear_option_values__
225
- ::Kernel.raise(
226
- Qonfig::FrozenSettingsError, 'Can not modify frozen settings'
227
- ) if __options__.frozen?
228
-
229
- __options__.each_pair do |key, value|
230
- if value.is_a?(Qonfig::Settings)
231
- value.__clear__
232
- else
233
- __options__[key] = nil
234
- end
235
- end
236
- end
160
+ # @param method_name [String, Symbol]
161
+ # @param arguments [Array<Object>]
162
+ # @param block [Proc]
163
+ # @return [void]
164
+ #
165
+ # @raise [Qonfig::UnknownSettingError]
166
+ #
167
+ # @api private
168
+ # @since 0.1.0
169
+ def method_missing(method_name, *arguments, &block)
170
+ super
171
+ rescue NoMethodError
172
+ ::Kernel.raise(Qonfig::UnknownSettingError, "Setting with <#{method_name}> key doesnt exist!")
173
+ end
237
174
 
238
- # @param key [String, Symbol]
239
- # @return [Object]
240
- #
241
- # @raise [Qonfig::UnknownSettingError]
242
- #
243
- # @api private
244
- # @since 0.2.0
245
- def __get_value__(key)
246
- key = __indifferently_accessable_option_key__(key)
175
+ # @return [Boolean]
176
+ #
177
+ # @api private
178
+ # @since 0.1.0
179
+ def respond_to_missing?(method_name, include_private = false)
180
+ # :nocov:
181
+ __options__.key?(method_name.to_s) || __options__.key?(method_name.to_sym) || super
182
+ # :nocov:
183
+ end
247
184
 
248
- unless __options__.key?(key)
249
- ::Kernel.raise(Qonfig::UnknownSettingError, "Setting with <#{key}> key does not exist!")
250
- end
185
+ # @return [void]
186
+ #
187
+ # @api private
188
+ # @since 0.1.0
189
+ def __freeze__
190
+ __lock__.thread_safe_access do
191
+ __options__.freeze
251
192
 
252
- __options__[key]
193
+ __options__.each_value do |value|
194
+ value.__freeze__ if value.is_a?(Qonfig::Settings)
195
+ end
253
196
  end
197
+ end
254
198
 
255
- # @param key [String, Symbol]
256
- # @param value [Object]
257
- # @return [void]
258
- #
259
- # @raise [Qonfig::UnknownSettingError]
260
- # @raise [Qonfig::FrozenSettingsError]
261
- # @raise [Qonfig::AmbiguousSettingValueError]
262
- #
263
- # @api private
264
- # @since 0.2.0
265
- def __set_value__(key, value)
266
- key = __indifferently_accessable_option_key__(key)
199
+ # @return [Boolean]
200
+ #
201
+ # @api private
202
+ # @since 0.2.0
203
+ def __is_frozen__
204
+ __lock__.thread_safe_access { __options__.frozen? }
205
+ end
267
206
 
268
- unless __options__.key?(key)
269
- ::Kernel.raise(Qonfig::UnknownSettingError, "Setting with <#{key}> key does not exist!")
270
- end
207
+ private
271
208
 
272
- if __options__.frozen?
273
- ::Kernel.raise(Qonfig::FrozenSettingsError, 'Can not modify frozen settings')
274
- end
209
+ # @return [Qonfig::Settings::Lock]
210
+ #
211
+ # @api private
212
+ # @since 0.2.0
213
+ attr_reader :__lock__
214
+
215
+ # @param options_map [Hash]
216
+ # @return [void]
217
+ #
218
+ # @raise [Qonfig::ArgumentError]
219
+ # @raise [Qonfig::AmbiguousSettingValueError]
220
+ #
221
+ # @api private
222
+ # @since 0.3.0
223
+ def __set_values_from_map__(options_map)
224
+ ::Kernel.raise(
225
+ Qonfig::ArgumentError, 'Options map should be represented as a hash'
226
+ ) unless options_map.is_a?(Hash)
275
227
 
276
- if __options__[key].is_a?(Qonfig::Settings)
228
+ options_map.each_pair do |key, value|
229
+ current_value = __get_value__(key)
230
+
231
+ # NOTE: some duplications here was made only for the better code readability
232
+ case
233
+ when !current_value.is_a?(Qonfig::Settings)
234
+ __set_value__(key, value)
235
+ when current_value.is_a?(Qonfig::Settings) && value.is_a?(Hash)
236
+ current_value.__apply_values__(value)
237
+ when current_value.is_a?(Qonfig::Settings) && !value.is_a?(Hash)
277
238
  ::Kernel.raise(
278
239
  Qonfig::AmbiguousSettingValueError,
279
240
  "Can not redefine option <#{key}> that contains nested options"
280
241
  )
281
242
  end
243
+ end
244
+ end
245
+
246
+ # @return [void]
247
+ #
248
+ # @raise [Qonfig::FrozenSettingsError]
249
+ #
250
+ # @api private
251
+ # @since 0.2.0
252
+ def __clear_option_values__
253
+ ::Kernel.raise(
254
+ Qonfig::FrozenSettingsError, 'Can not modify frozen settings'
255
+ ) if __options__.frozen?
256
+
257
+ __options__.each_pair do |key, value|
258
+ if value.is_a?(Qonfig::Settings)
259
+ value.__clear__
260
+ else
261
+ __options__[key] = nil
262
+ end
263
+ end
264
+ end
282
265
 
283
- __options__[key] = value
266
+ # @param key [String, Symbol]
267
+ # @return [Object]
268
+ #
269
+ # @raise [Qonfig::UnknownSettingError]
270
+ #
271
+ # @api private
272
+ # @since 0.2.0
273
+ def __get_value__(key)
274
+ key = __indifferently_accessable_option_key__(key)
275
+
276
+ unless __options__.key?(key)
277
+ ::Kernel.raise(Qonfig::UnknownSettingError, "Setting with <#{key}> key does not exist!")
284
278
  end
285
279
 
286
- # @param keys [Array<Symbol, String>]
287
- # @return [Object]
288
- #
289
- # @raise [Qonfig::ArgumentError]
290
- # @raise [Qonfig::UnknownSettingError]
291
- #
292
- # @api private
293
- # @since 0.2.0
294
- def __deep_access__(*keys)
295
- ::Kernel.raise(Qonfig::ArgumentError, 'Key list can not be empty') if keys.empty?
280
+ __options__[key]
281
+ end
296
282
 
297
- result = __get_value__(keys.first)
298
- rest_keys = Array(keys[1..-1])
283
+ # @param key [String, Symbol]
284
+ # @param value [Object]
285
+ # @return [void]
286
+ #
287
+ # @raise [Qonfig::UnknownSettingError]
288
+ # @raise [Qonfig::FrozenSettingsError]
289
+ # @raise [Qonfig::AmbiguousSettingValueError]
290
+ #
291
+ # @api private
292
+ # @since 0.2.0
293
+ def __set_value__(key, value)
294
+ key = __indifferently_accessable_option_key__(key)
299
295
 
300
- case
301
- when rest_keys.empty?
302
- result
303
- when !result.is_a?(Qonfig::Settings)
304
- ::Kernel.raise(
305
- Qonfig::UnknownSettingError,
306
- 'Setting with required digging sequence does not exist!'
307
- )
308
- when result.is_a?(Qonfig::Settings)
309
- result.__dig__(*rest_keys)
310
- end
296
+ unless __options__.key?(key)
297
+ ::Kernel.raise(Qonfig::UnknownSettingError, "Setting with <#{key}> key does not exist!")
311
298
  end
312
299
 
313
- # @param keys [Array<Symbol, String>]
314
- # @return [Hash]
315
- #
316
- # @raise [Qonfig::ArgumentError]
317
- # @raise [Qonfig::UnknownSettingError]
318
- #
319
- # @api private
320
- # @since 0.9.0
321
- def __deep_slice__(*keys)
322
- {}.tap do |result|
323
- __deep_access__(*keys).tap do |setting|
324
- required_key = __indifferently_accessable_option_key__(keys.last)
325
- result[required_key] = setting.is_a?(Qonfig::Settings) ? setting.__to_h__ : setting
326
- end
327
- end
300
+ if __options__.frozen?
301
+ ::Kernel.raise(Qonfig::FrozenSettingsError, 'Can not modify frozen settings')
328
302
  end
329
303
 
330
- # @param keys [Array<Symbol, String>]
331
- # @return [Hash]
332
- #
333
- # @raise [Qonfig::ArgumentError]
334
- # @raise [Qonfig::UnknownSettingError]
335
- #
336
- # @api private
337
- # @since 0.1.0
338
- def __deep_slice_value__(*keys)
339
- required_key = __indifferently_accessable_option_key__(keys.last)
340
- __deep_slice__(*keys)[required_key]
304
+ if __options__[key].is_a?(Qonfig::Settings)
305
+ ::Kernel.raise(
306
+ Qonfig::AmbiguousSettingValueError,
307
+ "Can not redefine option <#{key}> that contains nested options"
308
+ )
341
309
  end
342
310
 
343
- # @param options_part [Hash]
344
- # @return [Hash]
345
- #
346
- # @api private
347
- # @since 0.2.0
348
- def __build_hash_representation__(options_part = __options__)
349
- options_part.each_with_object({}) do |(key, value), hash|
350
- case
351
- when value.is_a?(Hash)
352
- hash[key] = __build_hash_representation__(value)
353
- when value.is_a?(Qonfig::Settings)
354
- hash[key] = value.__to_hash__
355
- else
356
- hash[key] = value
357
- end
358
- end
311
+ __options__[key] = value
312
+ end
313
+
314
+ # @param keys [Array<Symbol, String>]
315
+ # @return [Object]
316
+ #
317
+ # @raise [Qonfig::ArgumentError]
318
+ # @raise [Qonfig::UnknownSettingError]
319
+ #
320
+ # @api private
321
+ # @since 0.2.0
322
+ def __deep_access__(*keys)
323
+ ::Kernel.raise(Qonfig::ArgumentError, 'Key list can not be empty') if keys.empty?
324
+
325
+ result = __get_value__(keys.first)
326
+ rest_keys = Array(keys[1..-1])
327
+
328
+ case
329
+ when rest_keys.empty?
330
+ result
331
+ when !result.is_a?(Qonfig::Settings)
332
+ ::Kernel.raise(
333
+ Qonfig::UnknownSettingError,
334
+ 'Setting with required digging sequence does not exist!'
335
+ )
336
+ when result.is_a?(Qonfig::Settings)
337
+ result.__dig__(*rest_keys)
359
338
  end
339
+ end
360
340
 
361
- # @param key [Symbol, String]
362
- # @return [void]
363
- #
364
- # @api private
365
- # @since 0.1.0
366
- def __define_accessor__(key)
367
- define_singleton_method(key) do
368
- self.[](key)
341
+ # @param keys [Array<Symbol, String>]
342
+ # @return [Hash]
343
+ #
344
+ # @raise [Qonfig::ArgumentError]
345
+ # @raise [Qonfig::UnknownSettingError]
346
+ #
347
+ # @api private
348
+ # @since 0.9.0
349
+ def __deep_slice__(*keys)
350
+ {}.tap do |result|
351
+ __deep_access__(*keys).tap do |setting|
352
+ required_key = __indifferently_accessable_option_key__(keys.last)
353
+ result[required_key] = setting.is_a?(Qonfig::Settings) ? setting.__to_h__ : setting
369
354
  end
355
+ end
356
+ end
370
357
 
371
- define_singleton_method("#{key}=") do |value|
372
- self.[]=(key, value)
373
- end
358
+ # @param keys [Array<Symbol, String>]
359
+ # @return [Hash]
360
+ #
361
+ # @raise [Qonfig::ArgumentError]
362
+ # @raise [Qonfig::UnknownSettingError]
363
+ #
364
+ # @api private
365
+ # @since 0.1.0
366
+ def __deep_slice_value__(*keys)
367
+ required_key = __indifferently_accessable_option_key__(keys.last)
368
+ __deep_slice__(*keys)[required_key]
369
+ end
370
+
371
+ # @param options_part [Hash]
372
+ # @option transform_key [Proc]
373
+ # @option transform_value [Proc]
374
+ # @return [Hash]
375
+ #
376
+ # @api private
377
+ # @since 0.2.0
378
+ def __build_hash_representation__(options_part = __options__, transform_key:, transform_value:)
379
+ options_part.each_with_object({}) do |(key, value), hash|
380
+ final_key = transform_key.call(key)
374
381
 
375
- define_singleton_method("#{key}?") do
376
- !!self.[](key)
382
+ case
383
+ when value.is_a?(Hash)
384
+ hash[final_key] = __build_hash_representation__(
385
+ value,
386
+ transform_key: transform_key,
387
+ transform_value: transform_value
388
+ )
389
+ when value.is_a?(Qonfig::Settings)
390
+ hash[final_key] = value.__to_hash__(
391
+ transform_key: transform_key,
392
+ transform_value: transform_value
393
+ )
394
+ else
395
+ final_value = transform_value.call(value)
396
+ hash[final_key] = final_value
377
397
  end
378
398
  end
399
+ end
379
400
 
380
- # @param key [Symbol, String]
381
- # @return [String]
382
- #
383
- # @raise [Qonfig::ArgumentError]
384
- # @see Qonfig::Settings::KeyGuard
385
- #
386
- # @api private
387
- # @since 0.2.0
388
- def __indifferently_accessable_option_key__(key)
389
- KeyGuard.new(key).prevent_incompatible_key_type!
390
- key.to_s
401
+ # @param key [Symbol, String]
402
+ # @return [void]
403
+ #
404
+ # @api private
405
+ # @since 0.1.0
406
+ def __define_accessor__(key)
407
+ define_singleton_method(key) do
408
+ self.[](key)
391
409
  end
392
410
 
393
- # @param key [Symbol, String]
394
- # @return [void]
395
- #
396
- # @raise [Qonfig::CoreMethodIntersectionError]
397
- # @see Qonfig::Settings::KeyGuard
398
- #
399
- # @api private
400
- # @since 0.2.0
401
- def __prevent_core_method_intersection__(key)
402
- KeyGuard.new(key).prevent_core_method_intersection!
411
+ define_singleton_method("#{key}=") do |value|
412
+ self.[]=(key, value)
403
413
  end
404
414
 
405
- # rubocop:disable Layout/ClassStructure
406
- # @return [Array<String>]
407
- #
408
- # @api private
409
- # @since 0.2.0
410
- CORE_METHODS = Array(
411
- instance_methods(false) |
412
- private_instance_methods(false) |
413
- %i[super define_singleton_method self]
414
- ).map(&:to_s).freeze
415
- # rubocop:enable Layout/ClassStructure
415
+ define_singleton_method("#{key}?") do
416
+ !!self.[](key)
417
+ end
416
418
  end
417
419
 
418
- # rubocop:enable Metrics/ClassLength
420
+ # @param key [Symbol, String]
421
+ # @return [String]
422
+ #
423
+ # @raise [Qonfig::ArgumentError]
424
+ # @see Qonfig::Settings::KeyGuard
425
+ #
426
+ # @api private
427
+ # @since 0.2.0
428
+ def __indifferently_accessable_option_key__(key)
429
+ KeyGuard.new(key).prevent_incompatible_key_type!
430
+ key.to_s
431
+ end
432
+
433
+ # @param key [Symbol, String]
434
+ # @return [void]
435
+ #
436
+ # @raise [Qonfig::CoreMethodIntersectionError]
437
+ # @see Qonfig::Settings::KeyGuard
438
+ #
439
+ # @api private
440
+ # @since 0.2.0
441
+ def __prevent_core_method_intersection__(key)
442
+ KeyGuard.new(key).prevent_core_method_intersection!
443
+ end
444
+
445
+ # rubocop:disable Layout/ClassStructure
446
+ # @return [Array<String>]
447
+ #
448
+ # @api private
449
+ # @since 0.2.0
450
+ CORE_METHODS = Array(
451
+ instance_methods(false) |
452
+ private_instance_methods(false) |
453
+ %i[super define_singleton_method self]
454
+ ).map(&:to_s).freeze
455
+ # rubocop:enable Layout/ClassStructure
419
456
  end
457
+ # rubocop:enable Metrics/ClassLength