qonfig 0.16.0 → 0.17.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -1
  3. data/.travis.yml +6 -6
  4. data/CHANGELOG.md +17 -0
  5. data/README.md +630 -49
  6. data/gemfiles/with_external_deps.gemfile +2 -2
  7. data/lib/qonfig/commands/{add_nested_option.rb → definition/add_nested_option.rb} +1 -1
  8. data/lib/qonfig/commands/{add_option.rb → definition/add_option.rb} +1 -1
  9. data/lib/qonfig/commands/{compose.rb → definition/compose.rb} +1 -1
  10. data/lib/qonfig/commands/{expose_json.rb → definition/expose_json.rb} +1 -1
  11. data/lib/qonfig/commands/{expose_self.rb → definition/expose_self.rb} +1 -1
  12. data/lib/qonfig/commands/{expose_yaml.rb → definition/expose_yaml.rb} +1 -1
  13. data/lib/qonfig/commands/definition/load_from_env/value_converter.rb +82 -0
  14. data/lib/qonfig/commands/{load_from_env.rb → definition/load_from_env.rb} +1 -1
  15. data/lib/qonfig/commands/{load_from_json.rb → definition/load_from_json.rb} +1 -1
  16. data/lib/qonfig/commands/{load_from_self.rb → definition/load_from_self.rb} +1 -1
  17. data/lib/qonfig/commands/{load_from_yaml.rb → definition/load_from_yaml.rb} +1 -1
  18. data/lib/qonfig/commands/definition.rb +16 -0
  19. data/lib/qonfig/commands/instantiation/values_file.rb +171 -0
  20. data/lib/qonfig/commands/instantiation.rb +7 -0
  21. data/lib/qonfig/commands.rb +2 -10
  22. data/lib/qonfig/data_set/lock.rb +61 -4
  23. data/lib/qonfig/data_set.rb +151 -3
  24. data/lib/qonfig/dsl.rb +56 -16
  25. data/lib/qonfig/errors.rb +38 -11
  26. data/lib/qonfig/loaders/dynamic.rb +52 -0
  27. data/lib/qonfig/loaders/json.rb +6 -0
  28. data/lib/qonfig/loaders/yaml.rb +13 -0
  29. data/lib/qonfig/loaders.rb +3 -0
  30. data/lib/qonfig/plugins/toml/data_set.rb +13 -0
  31. data/lib/qonfig/plugins/toml/dsl.rb +6 -2
  32. data/lib/qonfig/plugins/toml/errors.rb +12 -0
  33. data/lib/qonfig/plugins/toml/loaders/dynamic.rb +31 -0
  34. data/lib/qonfig/plugins/toml/loaders/toml.rb +6 -0
  35. data/lib/qonfig/plugins/toml.rb +2 -0
  36. data/lib/qonfig/settings/builder.rb +1 -1
  37. data/lib/qonfig/settings.rb +21 -0
  38. data/lib/qonfig/validator/basic.rb +9 -1
  39. data/lib/qonfig/validator/builder/attribute_consistency.rb +29 -0
  40. data/lib/qonfig/validator/builder.rb +39 -14
  41. data/lib/qonfig/validator/dsl.rb +9 -1
  42. data/lib/qonfig/validator/method_based.rb +4 -2
  43. data/lib/qonfig/validator/predefined/common.rb +4 -2
  44. data/lib/qonfig/validator/predefined/registry.rb +0 -2
  45. data/lib/qonfig/validator/predefined/registry_control_mixin.rb +3 -2
  46. data/lib/qonfig/validator/proc_based.rb +4 -2
  47. data/lib/qonfig/version.rb +1 -1
  48. data/qonfig.gemspec +1 -1
  49. metadata +21 -15
  50. data/lib/qonfig/commands/load_from_env/value_converter.rb +0 -84
@@ -13,19 +13,24 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
13
13
  extend Qonfig::Validator::DSL
14
14
 
15
15
  class << self
16
+ # @param base_dataset_klass [Class<Qonfig::DataSet>]
16
17
  # @param config_klass_definitions [Proc]
17
18
  # @return [Qonfig::DataSet]
18
19
  #
19
20
  # @api public
20
21
  # @since 0.16.0
21
- def build(&config_klass_definitions)
22
- Class.new(self, &config_klass_definitions).new
22
+ def build(base_dataset_klass = self, &config_klass_definitions)
23
+ unless base_dataset_klass <= Qonfig::DataSet
24
+ raise(Qonfig::ArgumentError, 'Base inherited class should be a type of Qonfig::DataSet')
25
+ end
26
+
27
+ Class.new(base_dataset_klass, &config_klass_definitions).new
23
28
  end
24
29
  end
25
30
 
26
31
  # @return [Qonfig::Settings]
27
32
  #
28
- # @api private
33
+ # @api public
29
34
  # @since 0.1.0
30
35
  attr_reader :settings
31
36
 
@@ -70,6 +75,65 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
70
75
  end
71
76
  end
72
77
 
78
+ # @param file_path [String, Symbol]
79
+ # @option format [String, Symbol]
80
+ # @option strict [Boolean]
81
+ # @option expose [NilClass, String, Symbol] Environment key
82
+ # @return [void]
83
+ #
84
+ # @see Qonfig::DataSet#load_setting_values_from_file
85
+ #
86
+ # @api public
87
+ # @since 0.17.0
88
+ def load_from_file(file_path, format: :dynamic, strict: true, expose: nil)
89
+ thread_safe_access do
90
+ load_setting_values_from_file(file_path, format: format, strict: strict, expose: expose)
91
+ end
92
+ end
93
+
94
+ # @param file_path [String]
95
+ # @option strict [Boolean]
96
+ # @option expose [NilClass, String, Symbol] Environment key
97
+ # @return [void]
98
+ #
99
+ # @see Qonfig::DataSet#load_from_file
100
+ #
101
+ # @api public
102
+ # @since 0.17.0
103
+ def load_from_yaml(file_path, strict: true, expose: nil)
104
+ load_from_file(file_path, format: :yml, strict: strict, expose: expose)
105
+ end
106
+
107
+ # @param file_path [String]
108
+ # @option strict [Boolean]
109
+ # @option expose [NilClass, String, Symbol] Environment key
110
+ # @return [void]
111
+ #
112
+ # @see Qonfig::DataSet#load_from_file
113
+ #
114
+ # @api public
115
+ # @since 0.17.0
116
+ def load_from_json(file_path, strict: true, expose: nil)
117
+ load_from_file(file_path, format: :json, strict: strict, expose: expose)
118
+ end
119
+
120
+ # @option format [String, Symbol]
121
+ # @option strict [Boolean]
122
+ # @option expose [NilClass, String, Symbol]
123
+ # @return [void]
124
+ #
125
+ # @api public
126
+ # @since 0.17.0
127
+ def load_from_self(format: :dynamic, strict: true, expose: nil)
128
+ caller_location = caller(1, 1).first
129
+
130
+ thread_safe_access do
131
+ load_setting_values_from_file(
132
+ :self, format: format, strict: strict, expose: expose, caller_location: caller_location
133
+ )
134
+ end
135
+ end
136
+
73
137
  # @param settings_map [Hash]
74
138
  # @return [void]
75
139
  #
@@ -184,6 +248,17 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
184
248
  thread_safe_access { settings.__subset__(*keys) }
185
249
  end
186
250
 
251
+ # @param key_path [Array<String, Symbol>]
252
+ # @return [Boolean]
253
+ #
254
+ # @api public
255
+ # @since 0.17.0
256
+ def key?(*key_path)
257
+ thread_safe_access { settings.__has_key__(*key_path) }
258
+ end
259
+ alias_method :option?, :key?
260
+ alias_method :setting?, :key?
261
+
187
262
  # @return [void]
188
263
  #
189
264
  # @api public
@@ -234,6 +309,41 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
234
309
  thread_safe_access { validator.validate! }
235
310
  end
236
311
 
312
+ # @param temporary_configurations [Hash<Symbol|String,Any>]
313
+ # @param arbitary_code [Block]
314
+ # @return [void]
315
+ #
316
+ # @api public
317
+ # @since 0.17.0
318
+ def with(temporary_configurations = {}, &arbitary_code)
319
+ with_arbitary_access do
320
+ begin
321
+ original_settings = @settings
322
+
323
+ temporary_settings = self.class.build.dup.tap do |copied_config|
324
+ copied_config.configure(temporary_configurations)
325
+ end.settings
326
+
327
+ @settings = temporary_settings
328
+ yield if block_given?
329
+ ensure
330
+ @settings = original_settings
331
+ end
332
+ end
333
+ end
334
+
335
+ # @return [Qonfig::DataSet]
336
+ #
337
+ # @api public
338
+ # @since 0.17.0
339
+ def dup
340
+ thread_safe_definition do
341
+ self.class.build.tap do |duplicate|
342
+ duplicate.configure(to_h)
343
+ end
344
+ end
345
+ end
346
+
237
347
  private
238
348
 
239
349
  # @return [Qonfig::Validator]
@@ -270,6 +380,16 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
270
380
  yield(settings) if block_given?
271
381
  end
272
382
 
383
+ # @return [void]
384
+ #
385
+ # @api private
386
+ # @since 0.17.0
387
+ def call_instance_management_commands
388
+ self.class.instance_commands.each do |instance_command|
389
+ instance_command.call(self, settings)
390
+ end
391
+ end
392
+
273
393
  # @param settings_map [Hash]
274
394
  # @param configurations [Proc]
275
395
  # @return [void]
@@ -279,9 +399,33 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
279
399
  def load!(settings_map = {}, &configurations)
280
400
  build_validator
281
401
  build_settings
402
+ call_instance_management_commands
282
403
  apply_settings(settings_map, &configurations)
283
404
  end
284
405
 
406
+ # @param file_path [String, Symbol]
407
+ # @option format [String, Symbol]
408
+ # @option strict [Boolean]
409
+ # @option expose [NilClass, String, Symbol]
410
+ # @option callcer_location [NilClass, String]
411
+ # @return [void]
412
+ #
413
+ # @see Qonfig::Commands::Instantiation::ValuesFile
414
+ #
415
+ # @api private
416
+ # @since 0.17.0
417
+ def load_setting_values_from_file(
418
+ file_path,
419
+ format: :dynamic,
420
+ strict: true,
421
+ expose: nil,
422
+ caller_location: nil
423
+ )
424
+ Qonfig::Commands::Instantiation::ValuesFile.new(
425
+ file_path, caller_location, format: format, strict: strict, expose: expose
426
+ ).call(self, settings)
427
+ end
428
+
285
429
  # @param instructions [Proc]
286
430
  # @return [Object]
287
431
  #
@@ -299,4 +443,8 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
299
443
  def thread_safe_definition(&instructions)
300
444
  @__lock__.thread_safe_definition(&instructions)
301
445
  end
446
+
447
+ def with_arbitary_access(&instructions)
448
+ @__lock__.with_arbitary_access(&instructions)
449
+ end
302
450
  end
data/lib/qonfig/dsl.rb CHANGED
@@ -10,12 +10,16 @@ module Qonfig::DSL
10
10
  # @api private
11
11
  # @since 0.1.0
12
12
  def extended(child_klass)
13
- child_klass.instance_variable_set(:@commands, Qonfig::CommandSet.new)
13
+ child_klass.instance_variable_set(:@definition_commands, Qonfig::CommandSet.new)
14
+ child_klass.instance_variable_set(:@instance_commands, Qonfig::CommandSet.new)
14
15
 
15
16
  child_klass.singleton_class.prepend(Module.new do
16
17
  def inherited(child_klass)
17
- child_klass.instance_variable_set(:@commands, Qonfig::CommandSet.new)
18
- child_klass.commands.concat(commands)
18
+ child_klass.instance_variable_set(:@definition_commands, Qonfig::CommandSet.new)
19
+ child_klass.instance_variable_set(:@instance_commands, Qonfig::CommandSet.new)
20
+
21
+ child_klass.definition_commands.concat(definition_commands)
22
+ child_klass.instance_commands.concat(instance_commands)
19
23
  super
20
24
  end
21
25
  end)
@@ -25,9 +29,17 @@ module Qonfig::DSL
25
29
  # @return [Qonfig::CommandSet]
26
30
  #
27
31
  # @api private
28
- # @since 0.1.0
29
- def commands
30
- @commands
32
+ # @since 0.17.0
33
+ def definition_commands
34
+ @definition_commands
35
+ end
36
+
37
+ # @return [Qonfig::CommandSet]
38
+ #
39
+ # @api private
40
+ # @since 0.17.0
41
+ def instance_commands
42
+ @instance_commands
31
43
  end
32
44
 
33
45
  # @param key [Symbol, String]
@@ -42,9 +54,9 @@ module Qonfig::DSL
42
54
  # @since 0.1.0
43
55
  def setting(key, initial_value = nil, &nested_settings)
44
56
  if block_given?
45
- commands << Qonfig::Commands::AddNestedOption.new(key, nested_settings)
57
+ definition_commands << Qonfig::Commands::Definition::AddNestedOption.new(key, nested_settings)
46
58
  else
47
- commands << Qonfig::Commands::AddOption.new(key, initial_value)
59
+ definition_commands << Qonfig::Commands::Definition::AddOption.new(key, initial_value)
48
60
  end
49
61
  end
50
62
 
@@ -56,7 +68,7 @@ module Qonfig::DSL
56
68
  # @api private
57
69
  # @sine 0.1.0
58
70
  def compose(data_set_klass)
59
- commands << Qonfig::Commands::Compose.new(data_set_klass)
71
+ definition_commands << Qonfig::Commands::Definition::Compose.new(data_set_klass)
60
72
  end
61
73
 
62
74
  # @param file_path [String]
@@ -68,7 +80,9 @@ module Qonfig::DSL
68
80
  # @api public
69
81
  # @since 0.2.0
70
82
  def load_from_yaml(file_path, strict: true)
71
- commands << Qonfig::Commands::LoadFromYAML.new(file_path, strict: strict)
83
+ definition_commands << Qonfig::Commands::Definition::LoadFromYAML.new(
84
+ file_path, strict: strict
85
+ )
72
86
  end
73
87
 
74
88
  # @return [void]
@@ -79,7 +93,10 @@ module Qonfig::DSL
79
93
  # @since 0.2.0
80
94
  def load_from_self(format: :yaml)
81
95
  caller_location = caller(1, 1).first
82
- commands << Qonfig::Commands::LoadFromSelf.new(caller_location, format: format)
96
+
97
+ definition_commands << Qonfig::Commands::Definition::LoadFromSelf.new(
98
+ caller_location, format: format
99
+ )
83
100
  end
84
101
 
85
102
  # @option convert_values [Boolean]
@@ -91,7 +108,7 @@ module Qonfig::DSL
91
108
  # @api public
92
109
  # @since 0.2.0
93
110
  def load_from_env(convert_values: false, prefix: nil, trim_prefix: false)
94
- commands << Qonfig::Commands::LoadFromENV.new(
111
+ definition_commands << Qonfig::Commands::Definition::LoadFromENV.new(
95
112
  convert_values: convert_values,
96
113
  prefix: prefix,
97
114
  trim_prefix: trim_prefix
@@ -105,7 +122,7 @@ module Qonfig::DSL
105
122
  # @api public
106
123
  # @since 0.5.0
107
124
  def load_from_json(file_path, strict: true)
108
- commands << Qonfig::Commands::LoadFromJSON.new(file_path, strict: strict)
125
+ definition_commands << Qonfig::Commands::Definition::LoadFromJSON.new(file_path, strict: strict)
109
126
  end
110
127
 
111
128
  # @param file_path [String]
@@ -117,7 +134,9 @@ module Qonfig::DSL
117
134
  # @api public
118
135
  # @since 0.7.0
119
136
  def expose_yaml(file_path, strict: true, via:, env:)
120
- commands << Qonfig::Commands::ExposeYAML.new(file_path, strict: strict, via: via, env: env)
137
+ definition_commands << Qonfig::Commands::Definition::ExposeYAML.new(
138
+ file_path, strict: strict, via: via, env: env
139
+ )
121
140
  end
122
141
 
123
142
  # @param file_path [String]
@@ -129,7 +148,9 @@ module Qonfig::DSL
129
148
  # @api public
130
149
  # @since 0.14.0
131
150
  def expose_json(file_path, strict: true, via:, env:)
132
- commands << Qonfig::Commands::ExposeJSON.new(file_path, strict: strict, via: via, env: env)
151
+ definition_commands << Qonfig::Commands::Definition::ExposeJSON.new(
152
+ file_path, strict: strict, via: via, env: env
153
+ )
133
154
  end
134
155
 
135
156
  # @option env [Symbol, String]
@@ -141,6 +162,25 @@ module Qonfig::DSL
141
162
  # @since 0.14.0
142
163
  def expose_self(env:, format: :yaml)
143
164
  caller_location = caller(1, 1).first
144
- commands << Qonfig::Commands::ExposeSelf.new(caller_location, env: env, format: format)
165
+
166
+ definition_commands << Qonfig::Commands::Definition::ExposeSelf.new(
167
+ caller_location, env: env, format: format
168
+ )
169
+ end
170
+
171
+ # @param file_path [String]
172
+ # @option format [String, Symbol]
173
+ # @option strict [Boolean]
174
+ # @option expose [NilClass, String, Symbol] Environment key
175
+ # @return [void]
176
+ #
177
+ # @api public
178
+ # @since 0.17.0
179
+ def values_file(file_path, format: :dynamic, strict: false, expose: nil)
180
+ caller_location = caller(1, 1).first
181
+
182
+ instance_commands << Qonfig::Commands::Instantiation::ValuesFile.new(
183
+ file_path, caller_location, format: format, strict: strict, expose: expose
184
+ )
145
185
  end
146
186
  end
data/lib/qonfig/errors.rb CHANGED
@@ -47,8 +47,8 @@ module Qonfig
47
47
 
48
48
  # @see Qonfig::Settings
49
49
  # @see Qonfig::Settings::KeyGuard
50
- # @see Qonfig::Commands::AddOption
51
- # @see Qonfig::Commands::AddNestedOption
50
+ # @see Qonfig::Commands::Definition::AddOption
51
+ # @see Qonfig::Commands::Definition::AddNestedOption
52
52
  #
53
53
  # @api public
54
54
  # @since 0.2.0
@@ -69,24 +69,30 @@ module Qonfig
69
69
  # :nocov:
70
70
  end
71
71
 
72
- # @see Qonfig::Commands::LoadFromYAML
72
+ # @see Qonfig::Commands::Instantiation::ValuesFile
73
+ #
74
+ # @api public
75
+ # @since 0.17.0
76
+ IncompatibleDataStructureError = Class.new(Error)
77
+
78
+ # @see Qonfig::Commands::Definition::LoadFromYAML
73
79
  #
74
80
  # @api public
75
81
  # @since 0.2.0
76
- IncompatibleYAMLStructureError = Class.new(Error)
82
+ IncompatibleYAMLStructureError = Class.new(IncompatibleDataStructureError)
77
83
 
78
- # @see Qonfig::Commands::LoadFromJSON
84
+ # @see Qonfig::Commands::Definition::LoadFromJSON
79
85
  #
80
86
  # @api public
81
87
  # @since 0.5.0
82
- IncompatibleJSONStructureError = Class.new(Error)
88
+ IncompatibleJSONStructureError = Class.new(IncompatibleDataStructureError)
83
89
 
84
- # @see Qonfig::Commands::LoadFromSelf
85
- # @see Qonfig::Commands::ExposeSelf
90
+ # @see Qonfig::Commands::Definition::LoadFromSelf
91
+ # @see Qonfig::Commands::Definition::ExposeSelf
86
92
  #
87
93
  # @api public
88
94
  # @since 0.15.0
89
- IncompatibleEndDataStructureError = Class.new(Error)
95
+ IncompatibleEndDataStructureError = Class.new(IncompatibleDataStructureError)
90
96
 
91
97
  # @see Qonfig::Loaders::YAML
92
98
  #
@@ -94,12 +100,33 @@ module Qonfig
94
100
  # @since 0.2.0
95
101
  FileNotFoundError = Class.new(Errno::ENOENT)
96
102
 
97
- # @see Qonfig::Commands::LoadFromSelf
103
+ # @see Qonfig::Commands::Definition::LoadFromSelf
104
+ # @see Qonfig::Loaders::EndData
98
105
  #
99
106
  # @api public
100
107
  # @since 0.2.0
101
108
  SelfDataNotFoundError = Class.new(Error)
102
109
 
110
+ # @see Qonfig::Loaders::JSON
111
+ # @see Qonfig::Loaders::Dynamic
112
+ #
113
+ # @api public
114
+ # @since 0.17.0
115
+ JSONLoaderParseError = Class.new(::JSON::ParserError)
116
+
117
+ # @see Qonfig::Loaders::YAML
118
+ # @see Qonfig::Loaders::Dynamic
119
+ #
120
+ # @api public
121
+ # @since 0.17.0
122
+ YAMLLoaderParseError = Class.new(::Psych::SyntaxError)
123
+
124
+ # @see Qonfig::Loaders::Dynamic
125
+ #
126
+ # @api public
127
+ # @since 0.17.0
128
+ DynamicLoaderParseError = Class.new(Error)
129
+
103
130
  # @see Qonfig::Plugins::Regsitry
104
131
  #
105
132
  # @api private
@@ -112,7 +139,7 @@ module Qonfig
112
139
  # @since 0.4.0
113
140
  UnregisteredPluginError = Class.new(Error)
114
141
 
115
- # @see Qonfig::Commands::ExposeYAML
142
+ # @see Qonfig::Commands::Definition::ExposeYAML
116
143
  #
117
144
  # @api public
118
145
  # @since 0.7.0
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.17.0
5
+ class Qonfig::Loaders::Dynamic < Qonfig::Loaders::Basic
6
+ class << self
7
+ # @param data [String]
8
+ # @return [Object]
9
+ #
10
+ # @raise [Qonfig::DynamicLoaderParseError]
11
+ #
12
+ # @api private
13
+ # @since 0.17.0
14
+ def load(data)
15
+ try_to_load_json_data(data)
16
+ rescue Qonfig::JSONLoaderParseError
17
+ begin
18
+ try_to_load_yaml_data(data)
19
+ rescue Qonfig::YAMLLoaderParseError
20
+ raise Qonfig::DynamicLoaderParseError, 'File data has unknown format'
21
+ end
22
+ end
23
+
24
+ # @return [Hash]
25
+ #
26
+ # @api private
27
+ # @since 0.17.0
28
+ def load_empty_data
29
+ {}
30
+ end
31
+
32
+ private
33
+
34
+ # @param data [String]
35
+ # @return [Object]
36
+ #
37
+ # @api private
38
+ # @since 0.17.0
39
+ def try_to_load_yaml_data(data)
40
+ Qonfig::Loaders::YAML.load(data)
41
+ end
42
+
43
+ # @param data [String]
44
+ # @return [Object]
45
+ #
46
+ # @api private
47
+ # @since 0.17.0
48
+ def try_to_load_json_data(data)
49
+ Qonfig::Loaders::JSON.load(data)
50
+ end
51
+ end
52
+ end
@@ -7,10 +7,16 @@ class Qonfig::Loaders::JSON < Qonfig::Loaders::Basic
7
7
  # @param data [String]
8
8
  # @return [Object]
9
9
  #
10
+ # @raise [Qonfig::JSONLoaderParseError]
11
+ #
10
12
  # @api private
11
13
  # @since 0.5.0
12
14
  def load(data)
13
15
  ::JSON.parse(data, max_nesting: false, allow_nan: true)
16
+ rescue ::JSON::ParserError => error
17
+ raise(Qonfig::JSONLoaderParseError.new(error.message).tap do |exception|
18
+ exception.set_backtrace(error.backtrace)
19
+ end)
14
20
  end
15
21
 
16
22
  # @return [Object]
@@ -7,10 +7,23 @@ class Qonfig::Loaders::YAML < Qonfig::Loaders::Basic
7
7
  # @param data [String]
8
8
  # @return [Object]
9
9
  #
10
+ # @raise [Qonfig::YAMLLoaderParseError]
11
+ #
10
12
  # @api private
11
13
  # @since 0.2.0
12
14
  def load(data)
13
15
  ::YAML.load(ERB.new(data).result)
16
+ rescue ::Psych::SyntaxError => error
17
+ raise(
18
+ Qonfig::YAMLLoaderParseError.new(
19
+ error.file,
20
+ error.line,
21
+ error.column,
22
+ error.offset,
23
+ error.problem,
24
+ error.context
25
+ ).tap { |exception| exception.set_backtrace(error.backtrace) }
26
+ )
14
27
  end
15
28
 
16
29
  # @return [Object]
@@ -6,6 +6,7 @@ module Qonfig::Loaders
6
6
  require_relative 'loaders/basic'
7
7
  require_relative 'loaders/json'
8
8
  require_relative 'loaders/yaml'
9
+ require_relative 'loaders/dynamic'
9
10
  require_relative 'loaders/end_data'
10
11
 
11
12
  class << self
@@ -22,6 +23,8 @@ module Qonfig::Loaders
22
23
  Qonfig::Loaders::YAML
23
24
  when 'json'
24
25
  Qonfig::Loaders::JSON
26
+ when 'dynamic'
27
+ Qonfig::Loaders::Dynamic
25
28
  else
26
29
  raise(Qonfig::UnsupportedLoaderFormatError, "<#{format}> format is not supported.")
27
30
  end
@@ -16,4 +16,17 @@ class Qonfig::DataSet
16
16
  end
17
17
  end
18
18
  alias_method :dump_to_toml, :save_to_toml
19
+
20
+ # @param file_path [String]
21
+ # @option strict [Boolean]
22
+ # @option expose [NilClass, String, Symbol] Environment key
23
+ # @return [void]
24
+ #
25
+ # @see Qonfig::DataSet#load_from_file
26
+ #
27
+ # @api public
28
+ # @since 0.17.0
29
+ def load_from_toml(file_path, strict: true, expose: nil)
30
+ load_from_file(file_path, format: :toml, strict: strict, expose: expose)
31
+ end
19
32
  end
@@ -10,7 +10,9 @@ module Qonfig::DSL
10
10
  # @api public
11
11
  # @since 0.12.0
12
12
  def load_from_toml(file_path, strict: true)
13
- commands << Qonfig::Commands::LoadFromTOML.new(file_path, strict: strict)
13
+ definition_commands << Qonfig::Commands::LoadFromTOML.new(
14
+ file_path, strict: strict
15
+ )
14
16
  end
15
17
 
16
18
  # @param file_path [String]
@@ -22,6 +24,8 @@ module Qonfig::DSL
22
24
  # @api public
23
25
  # @since 0.12.0
24
26
  def expose_toml(file_path, strict: true, via:, env:)
25
- commands << Qonfig::Commands::ExposeTOML.new(file_path, strict: strict, via: via, env: env)
27
+ definition_commands << Qonfig::Commands::ExposeTOML.new(
28
+ file_path, strict: strict, via: via, env: env
29
+ )
26
30
  end
27
31
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.17.0
5
+ module Qonfig
6
+ # @see Qonfig::Loaders::TOML
7
+ # @see Qondig::Loaders::Dynamic
8
+ #
9
+ # @api public
10
+ # @since 0.17.0
11
+ TOMLLoaderParseError = Class.new(::TomlRB::ParseError)
12
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.17.0
5
+ class Qonfig::Loaders::Dynamic < Qonfig::Loaders::Basic
6
+ class << self
7
+ prepend(Module.new do
8
+ # @param data [String]
9
+ # @return [Object]
10
+ #
11
+ # @api private
12
+ # @since 0.17.0
13
+ def load(data)
14
+ try_to_load_toml_data(data)
15
+ rescue Qonfig::TOMLLoaderParseError
16
+ super(data)
17
+ end
18
+
19
+ private
20
+
21
+ # @param data [String]
22
+ # @return [Object]
23
+ #
24
+ # @api private
25
+ # @since 0.17.0
26
+ def try_to_load_toml_data(data)
27
+ Qonfig::Loaders::TOML.load(data)
28
+ end
29
+ end)
30
+ end
31
+ end
@@ -7,10 +7,16 @@ class Qonfig::Loaders::TOML < Qonfig::Loaders::Basic
7
7
  # @param data [String]
8
8
  # @return [Object]
9
9
  #
10
+ # @raise [Qonfig::TOMLLoaderParseError]
11
+ #
10
12
  # @api private
11
13
  # @since 0.12.0
12
14
  def load(data)
13
15
  ::TomlRB.parse(ERB.new(data).result)
16
+ rescue ::TomlRB::ParseError => error
17
+ raise(Qonfig::TOMLLoaderParseError.new(error.message).tap do |exception|
18
+ exception.set_backtrace(error.backtrace)
19
+ end)
14
20
  end
15
21
 
16
22
  # @return [Object]
@@ -15,8 +15,10 @@ class Qonfig::Plugins::TOML < Qonfig::Plugins::Abstract
15
15
  ) unless const_defined?('::TomlRB')
16
16
 
17
17
  require_relative 'toml/tomlrb_fixes'
18
+ require_relative 'toml/errors'
18
19
  require_relative 'toml/loaders'
19
20
  require_relative 'toml/loaders/toml'
21
+ require_relative 'toml/loaders/dynamic'
20
22
  require_relative 'toml/uploaders/toml'
21
23
  require_relative 'toml/commands/load_from_toml'
22
24
  require_relative 'toml/commands/expose_toml'
@@ -11,7 +11,7 @@ module Qonfig::Settings::Builder
11
11
  # @since 0.2.0
12
12
  def build(data_set)
13
13
  Qonfig::Settings.new(build_mutation_callbacks(data_set)).tap do |settings|
14
- data_set.class.commands.dup.each do |command|
14
+ data_set.class.definition_commands.dup.each do |command|
15
15
  command.call(data_set, settings)
16
16
  end
17
17
  end