qonfig 0.20.0 → 0.21.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.
data/Rakefile CHANGED
@@ -3,11 +3,11 @@
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
5
  require 'rubocop'
6
+ require 'rubocop/rake_task'
6
7
  require 'rubocop-rails'
7
8
  require 'rubocop-performance'
8
9
  require 'rubocop-rspec'
9
10
  require 'rubocop-rake'
10
- require 'rubocop/rake_task'
11
11
 
12
12
  RuboCop::RakeTask.new(:rubocop) do |t|
13
13
  config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
data/lib/qonfig.rb CHANGED
@@ -4,6 +4,8 @@ require 'yaml'
4
4
  require 'json'
5
5
  require 'erb'
6
6
 
7
+ # @api public
8
+ # @since 0.1.0
7
9
  module Qonfig
8
10
  require_relative 'qonfig/errors'
9
11
  require_relative 'qonfig/loaders'
@@ -17,6 +19,7 @@ module Qonfig
17
19
  require_relative 'qonfig/configurable'
18
20
  require_relative 'qonfig/imports'
19
21
  require_relative 'qonfig/plugins'
22
+ require_relative 'qonfig/compacted'
20
23
 
21
24
  # @api public
22
25
  # @since 0.4.0
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.21.0
5
+ class Qonfig::Compacted < BasicObject
6
+ require_relative 'compacted/constructor'
7
+
8
+ # @since 0.21.0
9
+ extend ::Qonfig::DSL
10
+
11
+ class << self
12
+ # @param base_config_klass [Class<Qonfig::Compacted>]
13
+ # @param config_klass_definitions [Block]
14
+ # @return [Qonfig::Compacted]
15
+ #
16
+ # @api public
17
+ # @since 0.21.0
18
+ def build(base_config_klass = self, &config_klass_definitions)
19
+ raise(
20
+ ::Qonfig::ArgumentError,
21
+ 'Base class should be a type of Qonfig::Compacted'
22
+ ) unless base_config_klass <= ::Qonfig::Compacted
23
+
24
+ Class.new(base_config_klass, &config_klass_definitions).new
25
+ end
26
+
27
+ # @param data_set [Qonfig::DataSet]
28
+ # @param configurations [Block]
29
+ # @return [Qonfig::Compacted]
30
+ #
31
+ # @api public
32
+ # @since 0.21.0
33
+ def build_from(
34
+ data_set = ::Qonfig::Compacted::Constructor::NO_INITIAL_DATA_SET,
35
+ &configurations
36
+ )
37
+ compacted_config = allocate # NOTE: #tap does not exist on BasicObject :(
38
+ ::Qonfig::Compacted::Constructor.construct(compacted_config, data_set, &configurations)
39
+ compacted_config
40
+ end
41
+
42
+ # @param settings_map [Hash<Symbol|String,Any>]
43
+ # @option init_from [NilClass, Qonfig::DataSet]
44
+ # @param configurations [Block]
45
+ # @return [Boolean]
46
+ #
47
+ # @api public
48
+ # @since 0.21.0
49
+ def valid_with?(settings_map = {}, &configurations)
50
+ new(settings_map, &configurations)
51
+ true
52
+ rescue ::Qonfig::ValidationError
53
+ false
54
+ end
55
+ end
56
+
57
+ # @return [Qonfig::DataSet]
58
+ #
59
+ # @api private
60
+ # @since 0.21.0
61
+ attr_reader :____data_set____
62
+
63
+ # @param settings_map [Hash<Symbol|String,Any>]
64
+ # @param configuration [Block]
65
+ # @return [void]
66
+ #
67
+ # @see Qonfig::Compacted::Constructor
68
+ #
69
+ # @api public
70
+ # @since 0.21.0
71
+ def initialize(settings_map = {}, &configuration)
72
+ ::Qonfig::Compacted::Constructor.construct(
73
+ self,
74
+ ::Qonfig::Compacted::Constructor::NO_INITIAL_DATA_SET,
75
+ settings_map: settings_map,
76
+ &configuration
77
+ )
78
+ end
79
+
80
+ # @param key [String, Symbol]
81
+ # @return [Any]
82
+ #
83
+ # @api public
84
+ # @since 0.21.0
85
+ def [](key)
86
+ ____data_set____[key]
87
+ end
88
+
89
+ # @param key [String, Symbol]
90
+ # @param value [Any]
91
+ # @return [void]
92
+ #
93
+ # @api public
94
+ # @since 0.21.0
95
+ def []=(key, value)
96
+ ____data_set____[key] = value
97
+ end
98
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.21.0
5
+ module Qonfig::Compacted::Constructor
6
+ # @return [NilClass]
7
+ #
8
+ # @api private
9
+ # @since 0.21.0
10
+ NO_INITIAL_DATA_SET = nil
11
+
12
+ class << self
13
+ # @param compacted_config [Qonfig::Compacted]
14
+ # @param initial_data_set [NilClass, Qonfig::DataSet]
15
+ # Notice: cant define NO_INITIAL_DATA_SET (`nil`) as default value cuz Ruby will autoamtically
16
+ # transform any Qonfig::DataSet to Hash (thx for kwargs, Ruby >:()
17
+ # @option settings_map [Hash<String,Symbol|Any>]
18
+ # @param configuration [Block]
19
+ # @return [void]
20
+ #
21
+ # @api private
22
+ # @since 0.21.0
23
+ def construct(compacted_config, initial_data_set, settings_map: {}, &configuration)
24
+ prevent_incompatible_attributes!(compacted_config, initial_data_set)
25
+
26
+ if initial_data_set
27
+ construct_instance_from_data_set(
28
+ compacted_config,
29
+ initial_data_set,
30
+ settings_map,
31
+ &configuration
32
+ )
33
+ else
34
+ construct_isntance_from_commands(
35
+ compacted_config,
36
+ settings_map,
37
+ &configuration
38
+ )
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # @param compacted_config [Qonfig::Compacted]
45
+ # @param initial_data_set [Qonfig::DataSet]
46
+ # @param settings_map [Hash<String,Symbol|Any>]
47
+ # @param configuration [Block]
48
+ # @return [void]
49
+ #
50
+ # @api private
51
+ # @since 0.21.0
52
+ def construct_instance_from_data_set(
53
+ compacted_config,
54
+ initial_data_set,
55
+ settings_map,
56
+ &configuration
57
+ )
58
+ compacted_config.instance_eval do
59
+ @____data_set____ = initial_data_set
60
+ @____data_set____.configure(settings_map, &configuration)
61
+ @____data_set____.export_settings(self, '*', accessor: true, raw: true)
62
+ end
63
+ end
64
+
65
+ # @param compacted_config [Qonfig::Compacted]
66
+ # @param settings_map [Hash<String,Symbol|Any>]
67
+ # @param configuration [Block]
68
+ # @return [void]
69
+ #
70
+ # @see #construct_instance_from_data_set
71
+ #
72
+ # @api private
73
+ # @since 0.21.0
74
+ def construct_isntance_from_commands(
75
+ compacted_config,
76
+ settings_map,
77
+ &configuration
78
+ )
79
+ compacted_config_klass = (class << compacted_config; self; end).superclass
80
+ target_data_set_klass = Class.new(Qonfig::DataSet)
81
+ Qonfig::DSL::Inheritance.inherit(base: compacted_config_klass, child: target_data_set_klass)
82
+ target_data_set = target_data_set_klass.new
83
+
84
+ construct_instance_from_data_set(
85
+ compacted_config,
86
+ target_data_set,
87
+ settings_map,
88
+ &configuration
89
+ )
90
+ end
91
+
92
+ # @param compacted_config [Qonfig::Compacted]
93
+ # @param initial_data_set [NilClass, Qonfig::DataSet]
94
+ # @return [void]
95
+ #
96
+ # @api private
97
+ # @since 0.21.0
98
+ def prevent_incompatible_attributes!(compacted_config, initial_data_set)
99
+ unless (class << compacted_config; self; end).superclass <= Qonfig::Compacted
100
+ # :nocov:
101
+ raise(Qonfig::ArgumentError, 'Compacted config should be a type of Qonfig::Compacted')
102
+ # :nocov:
103
+ end
104
+
105
+ unless initial_data_set.nil? || initial_data_set.is_a?(Qonfig::DataSet)
106
+ raise(Qonfig::ArgumentError, 'Initial config should be a type of Qonfig::DataSet')
107
+ end
108
+ end
109
+ end
110
+ end
@@ -25,13 +25,25 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
25
25
  Class.new(base_dataset_klass, &config_klass_definitions).new
26
26
  end
27
27
 
28
- # @param configurations [Hash<Symbol|String,Any>]
28
+ # @param base_dataset_klass [Class<Qonfig::DataSet>]
29
+ # @param config_klass_definitions [Proc]
30
+ # @return [Qonfig::Compacted]
31
+ #
32
+ # @api public
33
+ # @since 0.21.0
34
+ def build_compacted(base_dataset_klass = self, &config_klass_definitions)
35
+ build(base_dataset_klass, &config_klass_definitions).compacted
36
+ end
37
+
38
+ # @param settings_map [Hash<Symbol|String,Any>]
39
+ # @param configurations [Block]
29
40
  # @return [Boolean]
30
41
  #
31
42
  # @api public
32
43
  # @since 0.19.0
33
- def valid_with?(configurations = {})
34
- new(configurations)
44
+ # @version 0.21.0
45
+ def valid_with?(settings_map = {}, &configurations)
46
+ new(settings_map, &configurations)
35
47
  true
36
48
  rescue Qonfig::ValidationError
37
49
  false
@@ -89,62 +101,79 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
89
101
  # @option format [String, Symbol]
90
102
  # @option strict [Boolean]
91
103
  # @option expose [NilClass, String, Symbol] Environment key
104
+ # @param configurations [Block]
92
105
  # @return [void]
93
106
  #
94
107
  # @see Qonfig::DataSet#load_setting_values_from_file
95
108
  #
96
109
  # @api public
97
110
  # @since 0.17.0
98
- def load_from_file(file_path, format: :dynamic, strict: true, expose: nil)
111
+ # @version 0.21.0
112
+ def load_from_file(file_path, format: :dynamic, strict: true, expose: nil, &configurations)
99
113
  thread_safe_access do
100
- load_setting_values_from_file(file_path, format: format, strict: strict, expose: expose)
114
+ load_setting_values_from_file(
115
+ file_path, format: format, strict: strict, expose: expose, &configurations
116
+ )
101
117
  end
102
118
  end
103
119
 
104
120
  # @param file_path [String]
105
121
  # @option strict [Boolean]
106
122
  # @option expose [NilClass, String, Symbol] Environment key
123
+ # @param configurations [Block]
107
124
  # @return [void]
108
125
  #
109
126
  # @see Qonfig::DataSet#load_from_file
110
127
  #
111
128
  # @api public
112
129
  # @since 0.17.0
113
- def load_from_yaml(file_path, strict: true, expose: nil)
114
- load_from_file(file_path, format: :yml, strict: strict, expose: expose)
130
+ # @version 0.21.0
131
+ def load_from_yaml(file_path, strict: true, expose: nil, &configurations)
132
+ load_from_file(file_path, format: :yml, strict: strict, expose: expose, &configurations)
115
133
  end
116
134
 
117
135
  # @param file_path [String]
118
136
  # @option strict [Boolean]
119
137
  # @option expose [NilClass, String, Symbol] Environment key
138
+ # @param configurations [Block]
120
139
  # @return [void]
121
140
  #
122
141
  # @see Qonfig::DataSet#load_from_file
123
142
  #
124
143
  # @api public
125
144
  # @since 0.17.0
126
- def load_from_json(file_path, strict: true, expose: nil)
127
- load_from_file(file_path, format: :json, strict: strict, expose: expose)
145
+ # @version 0.21.0
146
+ def load_from_json(file_path, strict: true, expose: nil, &configurations)
147
+ load_from_file(file_path, format: :json, strict: strict, expose: expose, &configurations)
128
148
  end
129
149
 
130
150
  # @option format [String, Symbol]
131
151
  # @option strict [Boolean]
132
152
  # @option expose [NilClass, String, Symbol]
153
+ # @param configurations [Block]
133
154
  # @return [void]
134
155
  #
135
156
  # @api public
136
157
  # @since 0.17.0
137
- def load_from_self(format: :dynamic, strict: true, expose: nil)
138
- caller_location = caller(1, 1).first
158
+ # @version 0.21.0
159
+ def load_from_self(format: :dynamic, strict: true, expose: nil, &configurations)
160
+ caller_location = ::Kernel.caller(1, 1).first
139
161
 
140
162
  thread_safe_access do
141
163
  load_setting_values_from_file(
142
- :self, format: format, strict: strict, expose: expose, caller_location: caller_location
164
+ :self,
165
+ format: format,
166
+ strict: strict,
167
+ expose: expose,
168
+ caller_location: caller_location,
169
+ &configurations
143
170
  )
144
171
  end
145
172
  end
146
173
 
147
174
  # @param settings_map [Hash]
175
+ # @yield [cofnig]
176
+ # @yieldparam config [Qonfig::Settings]
148
177
  # @return [void]
149
178
  #
150
179
  # @api public
@@ -222,6 +251,20 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
222
251
  thread_safe_access { settings[key] }
223
252
  end
224
253
 
254
+ # @param key [String, Symbol]
255
+ # @param value [Any]
256
+ # @return [void]
257
+ #
258
+ # @raise [Qonfig::UnknownSettingError]
259
+ # @raise [Qonfig::FrozenSettingsError]
260
+ # @raise [Qonfig::AmbiguousSettingValueError]
261
+ #
262
+ # @api public
263
+ # @since 0.21.0
264
+ def []=(key, value)
265
+ thread_safe_access { settings[key] = value }
266
+ end
267
+
225
268
  # @param keys [Array<String, Symbol>]
226
269
  # @return [Object]
227
270
  #
@@ -312,21 +355,22 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
312
355
  thread_safe_access { validator.valid? }
313
356
  end
314
357
 
315
- # @param configurations [Hash<String,Symbol|Any>]
358
+ # @param settings_map [Hash<String,Symbol|Any>]
316
359
  # @return [Boolean]
317
360
  #
318
361
  # @api public
319
362
  # @since 0.19.0
320
- def valid_with?(configurations = {})
363
+ # @version 0.21.0
364
+ def valid_with?(settings_map = {}, &configurations)
321
365
  # NOTE:
322
- # 'dup.configure(configurations)' has better thread-safety than 'with(configurations)'
366
+ # 'dup.configure(settings_map)' has better thread-safety than 'with(settings_map)'
323
367
  # pros:
324
368
  # - no arbitrary lock is obtained;
325
369
  # - all threads can read and work :)
326
370
  # cons:
327
371
  # - useless ton of objects (new dataset, new settings, new locks, and etc);
328
372
  # - useless setting options assignment steps (self.dup + self.to_h + configure(to_h))
329
- dup.configure(configurations)
373
+ dup.configure(settings_map, &configurations)
330
374
  true
331
375
  rescue Qonfig::ValidationError
332
376
  false
@@ -400,6 +444,7 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
400
444
  # @option mappings [Hash<String|Symbol,String|Symbol>]
401
445
  # @option raw [Boolean]
402
446
  # @option prefix [String, Symbol]
447
+ # @option accessor [Boolean]
403
448
  # @return [void]
404
449
  #
405
450
  # @api public
@@ -408,8 +453,9 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
408
453
  exportable_object,
409
454
  *exported_setting_keys,
410
455
  mappings: Qonfig::Imports::Mappings::EMPTY_MAPPINGS,
411
- raw: false,
412
- prefix: Qonfig::Imports::Abstract::EMPTY_PREFIX
456
+ raw: Qonfig::Imports::Abstract::DEFAULT_RAW_BEHAVIOR,
457
+ prefix: Qonfig::Imports::Abstract::EMPTY_PREFIX,
458
+ accessor: Qonfig::Imports::Abstract::AS_ACCESSOR
413
459
  )
414
460
  thread_safe_access do
415
461
  Qonfig::Imports::Export.export!(
@@ -418,11 +464,20 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
418
464
  *exported_setting_keys,
419
465
  prefix: prefix,
420
466
  raw: raw,
421
- mappings: mappings
467
+ mappings: mappings,
468
+ accessor: accessor
422
469
  )
423
470
  end
424
471
  end
425
472
 
473
+ # @return [Qonfig::Compacted]
474
+ #
475
+ # @api public
476
+ # @since 0.21.0
477
+ def compacted
478
+ Qonfig::Compacted.build_from(self)
479
+ end
480
+
426
481
  private
427
482
 
428
483
  # @return [Qonfig::Validation::Validators::Composite]
@@ -432,26 +487,6 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
432
487
  # @version 0.20.0
433
488
  attr_reader :validator
434
489
 
435
- # @return [void]
436
- #
437
- # @api private
438
- # @since 0.2.0
439
- # @version 0.19.0
440
- def build_settings
441
- @settings = Qonfig::Settings::Builder.build_definitions(self)
442
- validator.validate!
443
- Qonfig::Settings::Builder.build_state(self)
444
- end
445
-
446
- # @return [void]
447
- #
448
- # @api private
449
- # @since 0.13.0
450
- # @version 0.20.0
451
- def build_validator
452
- @validator = Qonfig::Validation::Validators::Composite.new(self)
453
- end
454
-
455
490
  # @param settings_map [Hash]
456
491
  # @param configurations [Proc]
457
492
  # @return [void]
@@ -469,9 +504,12 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
469
504
  #
470
505
  # @api private
471
506
  # @since 0.2.0
507
+ # @version 0.21.0
472
508
  def load!(settings_map = {}, &configurations)
473
- build_validator
474
- build_settings
509
+ Qonfig::Settings::Builder.build(self) do |settings, validator|
510
+ @settings = settings
511
+ @validator = validator
512
+ end
475
513
  apply_settings(settings_map, &configurations)
476
514
  end
477
515
 
@@ -480,6 +518,7 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
480
518
  # @option strict [Boolean]
481
519
  # @option expose [NilClass, String, Symbol]
482
520
  # @option callcer_location [NilClass, String]
521
+ # @param configurations [Block]
483
522
  # @return [void]
484
523
  #
485
524
  # @see Qonfig::Commands::Instantiation::ValuesFile
@@ -491,11 +530,13 @@ class Qonfig::DataSet # rubocop:disable Metrics/ClassLength
491
530
  format: :dynamic,
492
531
  strict: true,
493
532
  expose: nil,
494
- caller_location: nil
533
+ caller_location: nil,
534
+ &configurations
495
535
  )
496
536
  Qonfig::Commands::Instantiation::ValuesFile.new(
497
537
  file_path, caller_location, format: format, strict: strict, expose: expose
498
538
  ).call(self, settings)
539
+ apply_settings(&configurations)
499
540
  end
500
541
 
501
542
  # @param instructions [Block]