qonfig 0.16.0 → 0.17.0

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