qonfig 0.20.0 → 0.21.0

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