anyway_config 2.0.2 → 2.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f9746b519b5adfe5e3a9b1f8753c8bac8a0c89cac457fa52c96c482bdf77897
4
- data.tar.gz: b105ab28f23df78e54d163487c75f43b4ec3ed69d761bd92d91d0d080ccb770b
3
+ metadata.gz: 2c71bc14b4c2822f12237ce9931c8ff7110c02694a8130477901d3e282c0d08c
4
+ data.tar.gz: de7ef174a92b14e9eb62b70c27ec9ce01f202acf5ed6f3af74666973ec8d81a7
5
5
  SHA512:
6
- metadata.gz: f9eda4f4738f72fc3db0d35584b696f310102e4a9caaeebfdf42c991fe54b983f7ec36da7e14dc0b8fac834fd627b387000254f9fc7f43966ef45e268bdc4950
7
- data.tar.gz: bc2abf29581fa77b0b467861a8bf4a8225690f8f258eb299d7c76b6337990ce0aa423fe7fda043dd1dcbbd6f2beaad5c227a36117f6aa018190bd42714b2cd0b
6
+ metadata.gz: 809b732f5d26976789919febd120191102bb8d40e31130d37bdd0832e748dbe371856f3b57fed97973ac978718562d2e5de65203ab273e380b15c31fd36c44a2
7
+ data.tar.gz: c5f6c3aa86c0c6843442c09273fd832f830c0930fe0285493fc0a0fdffbf5fb8918ecd8b45532f7e8676b06c200b6d709873ba83ce65bbabc223c4ed48fbc066
@@ -1,5 +1,9 @@
1
1
  # Change log
2
2
 
3
+ ## 2.0.3 (2020-05-12)
4
+
5
+ - Enable [auto-transpiling](https://github.com/ruby-next/ruby-next#transpiled-files-vs-vcs-vs-installing-from-source) to allow installing from source. ([@palkan][])
6
+
3
7
  ## 2.0.2 (2020-04-24)
4
8
 
5
9
  - Make sure configs are eager loaded in Rails when `config.eager_load = true`. ([@palkan][])
@@ -11,9 +11,7 @@ module Anyway # :nodoc:
11
11
 
12
12
  using(Module.new do
13
13
  refine Object do
14
- def vm_object_id
15
- (object_id << 1).to_s(16)
16
- end
14
+ def vm_object_id() ; (object_id << 1).to_s(16); end
17
15
  end
18
16
  end)
19
17
 
@@ -72,9 +70,7 @@ module Anyway # :nodoc:
72
70
  @name = name
73
71
  end
74
72
 
75
- def apply_to(config)
76
- config.send(name)
77
- end
73
+ def apply_to(config) ; config.send(name); end
78
74
  end
79
75
 
80
76
  class << self
@@ -110,23 +106,21 @@ module Anyway # :nodoc:
110
106
  def defaults
111
107
  return @defaults if instance_variable_defined?(:@defaults)
112
108
 
113
- @defaults =
114
- if superclass < Anyway::Config
115
- superclass.defaults.deep_dup
116
- else
117
- new_empty_config
118
- end
109
+ @defaults = if superclass < Anyway::Config
110
+ superclass.defaults.deep_dup
111
+ else
112
+ new_empty_config
113
+ end
119
114
  end
120
115
 
121
116
  def config_attributes
122
117
  return @config_attributes if instance_variable_defined?(:@config_attributes)
123
118
 
124
- @config_attributes =
125
- if superclass < Anyway::Config
126
- superclass.config_attributes.dup
127
- else
128
- []
129
- end
119
+ @config_attributes = if superclass < Anyway::Config
120
+ superclass.config_attributes.dup
121
+ else
122
+ []
123
+ end
130
124
  end
131
125
 
132
126
  def required(*names)
@@ -140,12 +134,11 @@ module Anyway # :nodoc:
140
134
  def required_attributes
141
135
  return @required_attributes if instance_variable_defined?(:@required_attributes)
142
136
 
143
- @required_attributes =
144
- if superclass < Anyway::Config
145
- superclass.required_attributes.dup
146
- else
147
- []
148
- end
137
+ @required_attributes = if superclass < Anyway::Config
138
+ superclass.required_attributes.dup
139
+ else
140
+ []
141
+ end
149
142
  end
150
143
 
151
144
  def on_load(*names, &block)
@@ -161,12 +154,11 @@ module Anyway # :nodoc:
161
154
  def load_callbacks
162
155
  return @load_callbacks if instance_variable_defined?(:@load_callbacks)
163
156
 
164
- @load_callbacks =
165
- if superclass <= Anyway::Config
166
- superclass.load_callbacks.dup
167
- else
168
- []
169
- end
157
+ @load_callbacks = if superclass <= Anyway::Config
158
+ superclass.load_callbacks.dup
159
+ else
160
+ []
161
+ end
170
162
  end
171
163
 
172
164
  def config_name(val = nil)
@@ -186,26 +178,21 @@ module Anyway # :nodoc:
186
178
  end
187
179
  end
188
180
 
189
- def explicit_config_name?
190
- !explicit_config_name.nil?
191
- end
181
+ def explicit_config_name?() ; !explicit_config_name.nil?; end
192
182
 
193
183
  def env_prefix(val = nil)
194
184
  return (@env_prefix = val.to_s.upcase) unless val.nil?
195
185
 
196
186
  return @env_prefix if instance_variable_defined?(:@env_prefix)
197
187
 
198
- @env_prefix =
199
- if superclass < Anyway::Config && superclass.explicit_config_name?
200
- superclass.env_prefix
201
- else
202
- config_name.upcase
203
- end
188
+ @env_prefix = if superclass < Anyway::Config && superclass.explicit_config_name?
189
+ superclass.env_prefix
190
+ else
191
+ config_name.upcase
192
+ end
204
193
  end
205
194
 
206
- def new_empty_config
207
- {}
208
- end
195
+ def new_empty_config() ; {}; end
209
196
 
210
197
  private
211
198
 
@@ -339,13 +326,9 @@ module Anyway # :nodoc:
339
326
  base_config
340
327
  end
341
328
 
342
- def dig(*keys)
343
- values.dig(*keys)
344
- end
329
+ def dig(*keys) ; values.dig(*keys); end
345
330
 
346
- def to_h
347
- values.deep_dup.deep_freeze
348
- end
331
+ def to_h() ; values.deep_dup.deep_freeze; end
349
332
 
350
333
  def dup
351
334
  self.class.allocate.tap do |new_config|
@@ -360,13 +343,9 @@ module Anyway # :nodoc:
360
343
  Anyway.env.fetch(env_prefix).delete("conf") || Settings.default_config_path.call(name)
361
344
  end
362
345
 
363
- def deconstruct_keys(keys)
364
- values.deconstruct_keys(keys)
365
- end
346
+ def deconstruct_keys(keys) ; values.deconstruct_keys(keys); end
366
347
 
367
- def to_source_trace
368
- __trace__&.to_h
369
- end
348
+ def to_source_trace() ; __trace__&.to_h; end
370
349
 
371
350
  def inspect
372
351
  "#<#{self.class}:0x#{vm_object_id.rjust(16, "0")} config_name=\"#{config_name}\" env_prefix=\"#{env_prefix}\" " \
@@ -13,9 +13,7 @@ module Anyway
13
13
  end
14
14
 
15
15
  refine Thread::Backtrace::Location do
16
- def path_lineno
17
- "#{path}:#{lineno}"
18
- end
16
+ def path_lineno() ; "#{path}:#{lineno}"; end
19
17
  end
20
18
  end)
21
19
 
@@ -35,12 +33,12 @@ module Anyway
35
33
  end
36
34
 
37
35
  def record_value(val, *path, key, **opts)
38
- trace =
39
- if val.is_a?(Hash)
40
- Trace.new.tap { |_1| _1.merge_values(val, **opts) }
41
- else
42
- Trace.new(:value, val, **opts)
43
- end
36
+ trace = if val.is_a?(Hash)
37
+ Trace.new.tap { |_1| _1.merge_values(val, **opts) }
38
+ else
39
+ Trace.new(:value, val, **opts)
40
+ end
41
+
44
42
  target_trace = path.empty? ? self : value.dig(*path)
45
43
  target_trace.value[key.to_s] = trace
46
44
 
@@ -79,13 +77,9 @@ module Anyway
79
77
  value.keep_if(*__rest__, &__block__)
80
78
  end
81
79
 
82
- def clear
83
- value.clear
84
- end
80
+ def clear() ; value.clear; end
85
81
 
86
- def trace?
87
- type == :trace
88
- end
82
+ def trace?() ; type == :trace; end
89
83
 
90
84
  def to_h
91
85
  if trace?
@@ -95,9 +89,7 @@ module Anyway
95
89
  end
96
90
  end
97
91
 
98
- def dup
99
- self.class.new(type, value.dup, source)
100
- end
92
+ def dup() ; self.class.new(type, value.dup, source); end
101
93
 
102
94
  def pretty_print(q)
103
95
  if trace?
@@ -146,9 +138,7 @@ module Anyway
146
138
  (Thread.current[:__anyway__trace_stack__] ||= [])
147
139
  end
148
140
 
149
- def current_trace
150
- trace_stack.last
151
- end
141
+ def current_trace() ; trace_stack.last; end
152
142
 
153
143
  alias tracing? current_trace
154
144
 
@@ -0,0 +1,393 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "anyway/optparse_config"
4
+ require "anyway/dynamic_config"
5
+
6
+ module Anyway # :nodoc:
7
+ using RubyNext
8
+ using Anyway::Ext::DeepDup
9
+ using Anyway::Ext::DeepFreeze
10
+ using Anyway::Ext::Hash
11
+
12
+ using(Module.new do
13
+ refine Object do
14
+ def vm_object_id() ; (object_id << 1).to_s(16); end
15
+ end
16
+ end)
17
+
18
+ # Base config class
19
+ # Provides `attr_config` method to describe
20
+ # configuration parameters and set defaults
21
+ class Config
22
+ PARAM_NAME = /^[a-z_]([\w]+)?$/
23
+
24
+ # List of names that couldn't be used as config names
25
+ # (the class instance methods we use)
26
+ RESERVED_NAMES = %i[
27
+ config_name
28
+ env_prefix
29
+ values
30
+ class
31
+ clear
32
+ deconstruct_keys
33
+ dig
34
+ dup
35
+ initialize
36
+ load
37
+ load_from_sources
38
+ option_parser
39
+ pretty_print
40
+ raise_validation_error
41
+ reload
42
+ resolve_config_path
43
+ to_h
44
+ to_source_trace
45
+ write_config_attr
46
+ ].freeze
47
+
48
+ class Error < StandardError; end
49
+ class ValidationError < Error; end
50
+
51
+ include OptparseConfig
52
+ include DynamicConfig
53
+
54
+ class BlockCallback
55
+ attr_reader :block
56
+
57
+ def initialize(block)
58
+ @block = block
59
+ end
60
+
61
+ def apply_to(config)
62
+ config.instance_exec(&block)
63
+ end
64
+ end
65
+
66
+ class NamedCallback
67
+ attr_reader :name
68
+
69
+ def initialize(name)
70
+ @name = name
71
+ end
72
+
73
+ def apply_to(config) ; config.send(name); end
74
+ end
75
+
76
+ class << self
77
+ def attr_config(*args, **hargs)
78
+ new_defaults = hargs.deep_dup
79
+ new_defaults.stringify_keys!
80
+
81
+ defaults.merge! new_defaults
82
+
83
+ new_keys = ((args + new_defaults.keys) - config_attributes)
84
+
85
+ validate_param_names! new_keys.map(&:to_s)
86
+
87
+ new_keys.map!(&:to_sym)
88
+
89
+ unless (reserved_names = (new_keys & RESERVED_NAMES)).empty?
90
+ raise ArgumentError, "Can not use the following reserved names as config attrubutes: " \
91
+ "#{reserved_names.sort.map(&:to_s).join(", ")}"
92
+ end
93
+
94
+ config_attributes.push(*new_keys)
95
+
96
+ define_config_accessor(*new_keys)
97
+
98
+ # Define predicate methods ("param?") for attributes
99
+ # having `true` or `false` as default values
100
+ new_defaults.each do |key, val|
101
+ next unless val.is_a?(TrueClass) || val.is_a?(FalseClass)
102
+ alias_method :"#{key}?", :"#{key}"
103
+ end
104
+ end
105
+
106
+ def defaults
107
+ return @defaults if instance_variable_defined?(:@defaults)
108
+
109
+ @defaults = if superclass < Anyway::Config
110
+ superclass.defaults.deep_dup
111
+ else
112
+ new_empty_config
113
+ end
114
+ end
115
+
116
+ def config_attributes
117
+ return @config_attributes if instance_variable_defined?(:@config_attributes)
118
+
119
+ @config_attributes = if superclass < Anyway::Config
120
+ superclass.config_attributes.dup
121
+ else
122
+ []
123
+ end
124
+ end
125
+
126
+ def required(*names)
127
+ unless (unknown_names = (names - config_attributes)).empty?
128
+ raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}"
129
+ end
130
+
131
+ required_attributes.push(*names)
132
+ end
133
+
134
+ def required_attributes
135
+ return @required_attributes if instance_variable_defined?(:@required_attributes)
136
+
137
+ @required_attributes = if superclass < Anyway::Config
138
+ superclass.required_attributes.dup
139
+ else
140
+ []
141
+ end
142
+ end
143
+
144
+ def on_load(*names, &block)
145
+ raise ArgumentError, "Either methods or block should be specified, not both" if block_given? && !names.empty?
146
+
147
+ if block_given?
148
+ load_callbacks << BlockCallback.new(block)
149
+ else
150
+ load_callbacks.push(*names.map { NamedCallback.new(_1) })
151
+ end
152
+ end
153
+
154
+ def load_callbacks
155
+ return @load_callbacks if instance_variable_defined?(:@load_callbacks)
156
+
157
+ @load_callbacks = if superclass <= Anyway::Config
158
+ superclass.load_callbacks.dup
159
+ else
160
+ []
161
+ end
162
+ end
163
+
164
+ def config_name(val = nil)
165
+ return (@explicit_config_name = val.to_s) unless val.nil?
166
+
167
+ return @config_name if instance_variable_defined?(:@config_name)
168
+
169
+ @config_name = explicit_config_name || build_config_name
170
+ end
171
+
172
+ def explicit_config_name
173
+ return @explicit_config_name if instance_variable_defined?(:@explicit_config_name)
174
+
175
+ @explicit_config_name =
176
+ if superclass.respond_to?(:explicit_config_name)
177
+ superclass.explicit_config_name
178
+ end
179
+ end
180
+
181
+ def explicit_config_name?() ; !explicit_config_name.nil?; end
182
+
183
+ def env_prefix(val = nil)
184
+ return (@env_prefix = val.to_s.upcase) unless val.nil?
185
+
186
+ return @env_prefix if instance_variable_defined?(:@env_prefix)
187
+
188
+ @env_prefix = if superclass < Anyway::Config && superclass.explicit_config_name?
189
+ superclass.env_prefix
190
+ else
191
+ config_name.upcase
192
+ end
193
+ end
194
+
195
+ def new_empty_config() ; {}; end
196
+
197
+ private
198
+
199
+ def define_config_accessor(*names)
200
+ names.each do |name|
201
+ accessors_module.module_eval <<~RUBY, __FILE__, __LINE__ + 1
202
+ def #{name}=(val)
203
+ __trace__&.record_value(val, \"#{name}\", Tracing.current_trace_source)
204
+ # DEPRECATED: instance variable set will be removed in 2.1
205
+ @#{name} = values[:#{name}] = val
206
+ end
207
+
208
+ def #{name}
209
+ values[:#{name}]
210
+ end
211
+ RUBY
212
+ end
213
+ end
214
+
215
+ def accessors_module
216
+ return @accessors_module if instance_variable_defined?(:@accessors_module)
217
+
218
+ @accessors_module = Module.new.tap do |mod|
219
+ include mod
220
+ end
221
+ end
222
+
223
+ def build_config_name
224
+ unless name
225
+ raise "Please, specify config name explicitly for anonymous class " \
226
+ "via `config_name :my_config`"
227
+ end
228
+
229
+ # handle two cases:
230
+ # - SomeModule::Config => "some_module"
231
+ # - SomeConfig => "some"
232
+ unless name =~ /^(\w+)(\:\:)?Config$/
233
+ raise "Couldn't infer config name, please, specify it explicitly" \
234
+ "via `config_name :my_config`"
235
+ end
236
+
237
+ Regexp.last_match[1].tap(&:downcase!)
238
+ end
239
+
240
+ def validate_param_names!(names)
241
+ invalid_names = names.reject { |name| name =~ PARAM_NAME }
242
+ return if invalid_names.empty?
243
+
244
+ raise ArgumentError, "Invalid attr_config name: #{invalid_names.join(", ")}.\n" \
245
+ "Valid names must satisfy /#{PARAM_NAME.source}/."
246
+ end
247
+ end
248
+
249
+ on_load :validate_required_attributes!
250
+
251
+ attr_reader :config_name, :env_prefix
252
+
253
+ # Instantiate config instance.
254
+ #
255
+ # Example:
256
+ #
257
+ # my_config = Anyway::Config.new()
258
+ #
259
+ # # provide some values explicitly
260
+ # my_config = Anyway::Config.new({some: :value})
261
+ #
262
+ def initialize(overrides = nil)
263
+ @config_name = self.class.config_name
264
+
265
+ raise ArgumentError, "Config name is missing" unless @config_name
266
+
267
+ @env_prefix = self.class.env_prefix
268
+ @values = {}
269
+
270
+ load(overrides)
271
+ end
272
+
273
+ def reload(overrides = nil)
274
+ clear
275
+ load(overrides)
276
+ self
277
+ end
278
+
279
+ def clear
280
+ values.clear
281
+ @__trace__ = nil
282
+ self
283
+ end
284
+
285
+ def load(overrides = nil)
286
+ base_config = self.class.defaults.deep_dup
287
+
288
+ trace = Tracing.capture do
289
+ Tracing.trace!(:defaults) { base_config }
290
+
291
+ load_from_sources(
292
+ base_config,
293
+ name: config_name,
294
+ env_prefix: env_prefix,
295
+ config_path: resolve_config_path(config_name, env_prefix)
296
+ )
297
+
298
+ if overrides
299
+ Tracing.trace!(:load) { overrides }
300
+
301
+ base_config.deep_merge!(overrides)
302
+ end
303
+ end
304
+
305
+ base_config.each do |key, val|
306
+ write_config_attr(key.to_sym, val)
307
+ end
308
+
309
+ # Trace may contain unknown attributes
310
+ trace&.keep_if { |key| self.class.config_attributes.include?(key.to_sym) }
311
+
312
+ # Run on_load callbacks
313
+ self.class.load_callbacks.each { _1.apply_to(self) }
314
+
315
+ # Set trace after we write all the values to
316
+ # avoid changing the source to accessor
317
+ @__trace__ = trace
318
+
319
+ self
320
+ end
321
+
322
+ def load_from_sources(base_config, **options)
323
+ Anyway.loaders.each do |(_id, loader)|
324
+ base_config.deep_merge!(loader.call(**options))
325
+ end
326
+ base_config
327
+ end
328
+
329
+ def dig(*keys) ; values.dig(*keys); end
330
+
331
+ def to_h() ; values.deep_dup.deep_freeze; end
332
+
333
+ def dup
334
+ self.class.allocate.tap do |new_config|
335
+ %i[config_name env_prefix __trace__].each do |ivar|
336
+ new_config.instance_variable_set(:"@#{ivar}", send(ivar).dup)
337
+ end
338
+ new_config.instance_variable_set(:@values, values.deep_dup)
339
+ end
340
+ end
341
+
342
+ def resolve_config_path(name, env_prefix)
343
+ Anyway.env.fetch(env_prefix).delete("conf") || Settings.default_config_path.call(name)
344
+ end
345
+
346
+ def deconstruct_keys(keys) ; values.deconstruct_keys(keys); end
347
+
348
+ def to_source_trace() ; __trace__&.to_h; end
349
+
350
+ def inspect
351
+ "#<#{self.class}:0x#{vm_object_id.rjust(16, "0")} config_name=\"#{config_name}\" env_prefix=\"#{env_prefix}\" " \
352
+ "values=#{values.inspect}>"
353
+ end
354
+
355
+ def pretty_print(q)
356
+ q.object_group self do
357
+ q.nest(1) do
358
+ q.breakable
359
+ q.text "config_name=#{config_name.inspect}"
360
+ q.breakable
361
+ q.text "env_prefix=#{env_prefix.inspect}"
362
+ q.breakable
363
+ q.text "values:"
364
+ q.pp __trace__
365
+ end
366
+ end
367
+ end
368
+
369
+ private
370
+
371
+ attr_reader :values, :__trace__
372
+
373
+ def validate_required_attributes!
374
+ self.class.required_attributes.select do |name|
375
+ values[name].nil? || (values[name].is_a?(String) && values[name].empty?)
376
+ end.then do |missing|
377
+ next if missing.empty?
378
+ raise_validation_error "The following config parameters are missing or empty: #{missing.join(", ")}"
379
+ end
380
+ end
381
+
382
+ def write_config_attr(key, val)
383
+ key = key.to_sym
384
+ return unless self.class.config_attributes.include?(key)
385
+
386
+ public_send(:"#{key}=", val)
387
+ end
388
+
389
+ def raise_validation_error(msg)
390
+ raise ValidationError, msg
391
+ end
392
+ end
393
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anyway
4
+ using RubyNext
5
+
6
+ module Loaders
7
+ class Registry
8
+ attr_reader :registry
9
+
10
+ def initialize
11
+ @registry = []
12
+ end
13
+
14
+ def prepend(id, handler = nil, &block)
15
+ handler ||= block
16
+ insert_at(0, id, handler)
17
+ end
18
+
19
+ def append(id, handler = nil, &block)
20
+ handler ||= block
21
+ insert_at(registry.size, id, handler)
22
+ end
23
+
24
+ def insert_before(another_id, id, handler = nil, &block)
25
+ ind = registry.find_index { |(hid, _)| hid == another_id }
26
+ raise ArgumentError, "Loader with ID #{another_id} hasn't been registered" if ind.nil?
27
+
28
+ handler ||= block
29
+ insert_at(ind, id, handler)
30
+ end
31
+
32
+ def insert_after(another_id, id, handler = nil, &block)
33
+ ind = registry.find_index { |(hid, _)| hid == another_id }
34
+ raise ArgumentError, "Loader with ID #{another_id} hasn't been registered" if ind.nil?
35
+
36
+ handler ||= block
37
+ insert_at(ind + 1, id, handler)
38
+ end
39
+
40
+ def override(id, handler)
41
+ find(id).then do |id_to_handler|
42
+ raise ArgumentError, "Loader with ID #{id} hasn't been registered" if id_to_handler.nil?
43
+ id_to_handler[1] = handler
44
+ end
45
+ end
46
+
47
+ def delete(id)
48
+ find(id).then do |id_to_handler|
49
+ raise ArgumentError, "Loader with ID #{id} hasn't been registered" if id_to_handler.nil?
50
+ registry.delete id_to_handler
51
+ end
52
+ end
53
+
54
+ def each(&block)
55
+ registry.each(&block)
56
+ end
57
+
58
+ def freeze() ; registry.freeze; end
59
+
60
+ private
61
+
62
+ def insert_at(index, id, handler)
63
+ raise ArgumentError, "Loader with ID #{id} has been already registered" unless find(id).nil?
64
+
65
+ registry.insert(index, [id, handler])
66
+ end
67
+
68
+ def find(id)
69
+ registry.find { |(hid, _)| hid == id }
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ require "anyway/loaders/base"
76
+ require "anyway/loaders/yaml"
77
+ require "anyway/loaders/env"
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anyway
4
+ module Loaders
5
+ class Base
6
+ include Tracing
7
+
8
+ class << self
9
+ def call(local: Anyway::Settings.use_local_files, **opts)
10
+ new(local: local).call(**opts)
11
+ end
12
+ end
13
+
14
+ def initialize(local:)
15
+ @local = local
16
+ end
17
+
18
+ def use_local?() ; @local == true; end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Anyway
4
+ # Provides method to trace values association
5
+ module Tracing
6
+ using Anyway::Ext::DeepDup
7
+
8
+ using(Module.new do
9
+ refine Hash do
10
+ def inspect
11
+ "{#{map { |k, v| "#{k}: #{v.inspect}" }.join(", ")}}"
12
+ end
13
+ end
14
+
15
+ refine Thread::Backtrace::Location do
16
+ def path_lineno() ; "#{path}:#{lineno}"; end
17
+ end
18
+ end)
19
+
20
+ class Trace
21
+ UNDEF = Object.new
22
+
23
+ attr_reader :type, :value, :source
24
+
25
+ def initialize(type = :trace, value = UNDEF, **source)
26
+ @type = type
27
+ @source = source
28
+ @value = value == UNDEF ? Hash.new { |h, k| h[k] = Trace.new(:trace) } : value
29
+ end
30
+
31
+ def dig(...)
32
+ value.dig(...)
33
+ end
34
+
35
+ def record_value(val, *path, key, **opts)
36
+ trace = if val.is_a?(Hash)
37
+ Trace.new.tap { _1.merge_values(val, **opts) }
38
+ else
39
+ Trace.new(:value, val, **opts)
40
+ end
41
+
42
+ target_trace = path.empty? ? self : value.dig(*path)
43
+ target_trace.value[key.to_s] = trace
44
+
45
+ val
46
+ end
47
+
48
+ def merge_values(hash, **opts)
49
+ return hash unless hash
50
+
51
+ hash.each do |key, val|
52
+ if val.is_a?(Hash)
53
+ value[key.to_s].merge_values(val, **opts)
54
+ else
55
+ value[key.to_s] = Trace.new(:value, val, **opts)
56
+ end
57
+ end
58
+
59
+ hash
60
+ end
61
+
62
+ def merge!(another_trace)
63
+ raise ArgumentError, "You can only merge into a :trace type, and this is :#{type}" unless trace?
64
+ raise ArgumentError, "You can only merge a :trace type, but trying :#{type}" unless another_trace.trace?
65
+
66
+ another_trace.value.each do |key, sub_trace|
67
+ if sub_trace.trace?
68
+ value[key].merge! sub_trace
69
+ else
70
+ value[key] = sub_trace
71
+ end
72
+ end
73
+ end
74
+
75
+ def keep_if(...)
76
+ raise ArgumentError, "You can only filter :trace type, and this is :#{type}" unless trace?
77
+ value.keep_if(...)
78
+ end
79
+
80
+ def clear() ; value.clear; end
81
+
82
+ def trace?() ; type == :trace; end
83
+
84
+ def to_h
85
+ if trace?
86
+ value.transform_values(&:to_h).tap { _1.default_proc = nil }
87
+ else
88
+ {value: value, source: source}
89
+ end
90
+ end
91
+
92
+ def dup() ; self.class.new(type, value.dup, source); end
93
+
94
+ def pretty_print(q)
95
+ if trace?
96
+ q.nest(2) do
97
+ q.breakable ""
98
+ q.seplist(value, nil, :each) do |k, v|
99
+ q.group do
100
+ q.text k
101
+ q.text " =>"
102
+ q.breakable " " unless v.trace?
103
+ q.pp v
104
+ end
105
+ end
106
+ end
107
+ else
108
+ q.pp value
109
+ q.group(0, " (", ")") do
110
+ q.seplist(source, lambda { q.breakable " " }, :each) do |k, v|
111
+ q.group do
112
+ q.text k.to_s
113
+ q.text "="
114
+ q.text v.to_s
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ class << self
123
+ def capture
124
+ unless Settings.tracing_enabled
125
+ yield
126
+ return
127
+ end
128
+
129
+ trace = Trace.new
130
+ trace_stack.push trace
131
+ yield
132
+ trace_stack.last
133
+ ensure
134
+ trace_stack.pop
135
+ end
136
+
137
+ def trace_stack
138
+ (Thread.current[:__anyway__trace_stack__] ||= [])
139
+ end
140
+
141
+ def current_trace() ; trace_stack.last; end
142
+
143
+ alias tracing? current_trace
144
+
145
+ def source_stack
146
+ (Thread.current[:__anyway__trace_source_stack__] ||= [])
147
+ end
148
+
149
+ def current_trace_source
150
+ source_stack.last || accessor_source(caller_locations(2, 1).first)
151
+ end
152
+
153
+ def with_trace_source(src)
154
+ source_stack << src
155
+ yield
156
+ ensure
157
+ source_stack.pop
158
+ end
159
+
160
+ private
161
+
162
+ def accessor_source(location)
163
+ {type: :accessor, called_from: location.path_lineno}
164
+ end
165
+ end
166
+
167
+ module_function
168
+
169
+ def trace!(type, *path, **opts)
170
+ return yield unless Tracing.tracing?
171
+ source = {type: type}.merge(opts)
172
+ val = yield
173
+ if val.is_a?(Hash)
174
+ Tracing.current_trace.merge_values(val, **source)
175
+ else
176
+ Tracing.current_trace.record_value(val, *path, **source)
177
+ end
178
+ val
179
+ end
180
+ end
181
+ end
@@ -11,9 +11,7 @@ module Anyway # :nodoc:
11
11
 
12
12
  using(Module.new do
13
13
  refine Object do
14
- def vm_object_id
15
- (object_id << 1).to_s(16)
16
- end
14
+ def vm_object_id() = (object_id << 1).to_s(16)
17
15
  end
18
16
  end)
19
17
 
@@ -72,9 +70,7 @@ module Anyway # :nodoc:
72
70
  @name = name
73
71
  end
74
72
 
75
- def apply_to(config)
76
- config.send(name)
77
- end
73
+ def apply_to(config) = config.send(name)
78
74
  end
79
75
 
80
76
  class << self
@@ -110,23 +106,21 @@ module Anyway # :nodoc:
110
106
  def defaults
111
107
  return @defaults if instance_variable_defined?(:@defaults)
112
108
 
113
- @defaults =
114
- if superclass < Anyway::Config
115
- superclass.defaults.deep_dup
116
- else
117
- new_empty_config
118
- end
109
+ if superclass < Anyway::Config
110
+ superclass.defaults.deep_dup
111
+ else
112
+ new_empty_config
113
+ end => @defaults
119
114
  end
120
115
 
121
116
  def config_attributes
122
117
  return @config_attributes if instance_variable_defined?(:@config_attributes)
123
118
 
124
- @config_attributes =
125
- if superclass < Anyway::Config
126
- superclass.config_attributes.dup
127
- else
128
- []
129
- end
119
+ if superclass < Anyway::Config
120
+ superclass.config_attributes.dup
121
+ else
122
+ []
123
+ end => @config_attributes
130
124
  end
131
125
 
132
126
  def required(*names)
@@ -140,12 +134,11 @@ module Anyway # :nodoc:
140
134
  def required_attributes
141
135
  return @required_attributes if instance_variable_defined?(:@required_attributes)
142
136
 
143
- @required_attributes =
144
- if superclass < Anyway::Config
145
- superclass.required_attributes.dup
146
- else
147
- []
148
- end
137
+ if superclass < Anyway::Config
138
+ superclass.required_attributes.dup
139
+ else
140
+ []
141
+ end => @required_attributes
149
142
  end
150
143
 
151
144
  def on_load(*names, &block)
@@ -161,12 +154,11 @@ module Anyway # :nodoc:
161
154
  def load_callbacks
162
155
  return @load_callbacks if instance_variable_defined?(:@load_callbacks)
163
156
 
164
- @load_callbacks =
165
- if superclass <= Anyway::Config
166
- superclass.load_callbacks.dup
167
- else
168
- []
169
- end
157
+ if superclass <= Anyway::Config
158
+ superclass.load_callbacks.dup
159
+ else
160
+ []
161
+ end => @load_callbacks
170
162
  end
171
163
 
172
164
  def config_name(val = nil)
@@ -186,26 +178,21 @@ module Anyway # :nodoc:
186
178
  end
187
179
  end
188
180
 
189
- def explicit_config_name?
190
- !explicit_config_name.nil?
191
- end
181
+ def explicit_config_name?() = !explicit_config_name.nil?
192
182
 
193
183
  def env_prefix(val = nil)
194
184
  return (@env_prefix = val.to_s.upcase) unless val.nil?
195
185
 
196
186
  return @env_prefix if instance_variable_defined?(:@env_prefix)
197
187
 
198
- @env_prefix =
199
- if superclass < Anyway::Config && superclass.explicit_config_name?
200
- superclass.env_prefix
201
- else
202
- config_name.upcase
203
- end
188
+ if superclass < Anyway::Config && superclass.explicit_config_name?
189
+ superclass.env_prefix
190
+ else
191
+ config_name.upcase
192
+ end => @env_prefix
204
193
  end
205
194
 
206
- def new_empty_config
207
- {}
208
- end
195
+ def new_empty_config() = {}
209
196
 
210
197
  private
211
198
 
@@ -228,9 +215,9 @@ module Anyway # :nodoc:
228
215
  def accessors_module
229
216
  return @accessors_module if instance_variable_defined?(:@accessors_module)
230
217
 
231
- @accessors_module = Module.new.tap do |mod|
218
+ Module.new.tap do |mod|
232
219
  include mod
233
- end
220
+ end => @accessors_module
234
221
  end
235
222
 
236
223
  def build_config_name
@@ -298,7 +285,7 @@ module Anyway # :nodoc:
298
285
  def load(overrides = nil)
299
286
  base_config = self.class.defaults.deep_dup
300
287
 
301
- trace = Tracing.capture do
288
+ Tracing.capture do
302
289
  Tracing.trace!(:defaults) { base_config }
303
290
 
304
291
  load_from_sources(
@@ -313,7 +300,7 @@ module Anyway # :nodoc:
313
300
 
314
301
  base_config.deep_merge!(overrides)
315
302
  end
316
- end
303
+ end => trace
317
304
 
318
305
  base_config.each do |key, val|
319
306
  write_config_attr(key.to_sym, val)
@@ -339,13 +326,9 @@ module Anyway # :nodoc:
339
326
  base_config
340
327
  end
341
328
 
342
- def dig(*keys)
343
- values.dig(*keys)
344
- end
329
+ def dig(*keys) = values.dig(*keys)
345
330
 
346
- def to_h
347
- values.deep_dup.deep_freeze
348
- end
331
+ def to_h() = values.deep_dup.deep_freeze
349
332
 
350
333
  def dup
351
334
  self.class.allocate.tap do |new_config|
@@ -360,13 +343,9 @@ module Anyway # :nodoc:
360
343
  Anyway.env.fetch(env_prefix).delete("conf") || Settings.default_config_path.call(name)
361
344
  end
362
345
 
363
- def deconstruct_keys(keys)
364
- values.deconstruct_keys(keys)
365
- end
346
+ def deconstruct_keys(keys) = values.deconstruct_keys(keys)
366
347
 
367
- def to_source_trace
368
- __trace__&.to_h
369
- end
348
+ def to_source_trace() = __trace__&.to_h
370
349
 
371
350
  def inspect
372
351
  "#<#{self.class}:0x#{vm_object_id.rjust(16, "0")} config_name=\"#{config_name}\" env_prefix=\"#{env_prefix}\" " \
@@ -55,9 +55,7 @@ module Anyway
55
55
  registry.each(&block)
56
56
  end
57
57
 
58
- def freeze
59
- registry.freeze
60
- end
58
+ def freeze() = registry.freeze
61
59
 
62
60
  private
63
61
 
@@ -15,9 +15,7 @@ module Anyway
15
15
  @local = local
16
16
  end
17
17
 
18
- def use_local?
19
- @local == true
20
- end
18
+ def use_local?() = @local == true
21
19
  end
22
20
  end
23
21
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "anyway/testing/helpers"
4
4
 
5
- if defined?(RSpec)
5
+ if defined?(RSpec::Core)
6
6
  RSpec.configure do |config|
7
7
  config.include(
8
8
  Anyway::Testing::Helpers,
@@ -13,9 +13,7 @@ module Anyway
13
13
  end
14
14
 
15
15
  refine Thread::Backtrace::Location do
16
- def path_lineno
17
- "#{path}:#{lineno}"
18
- end
16
+ def path_lineno() = "#{path}:#{lineno}"
19
17
  end
20
18
  end)
21
19
 
@@ -35,12 +33,12 @@ module Anyway
35
33
  end
36
34
 
37
35
  def record_value(val, *path, key, **opts)
38
- trace =
39
- if val.is_a?(Hash)
40
- Trace.new.tap { _1.merge_values(val, **opts) }
41
- else
42
- Trace.new(:value, val, **opts)
43
- end
36
+ if val.is_a?(Hash)
37
+ Trace.new.tap { _1.merge_values(val, **opts) }
38
+ else
39
+ Trace.new(:value, val, **opts)
40
+ end => trace
41
+
44
42
  target_trace = path.empty? ? self : value.dig(*path)
45
43
  target_trace.value[key.to_s] = trace
46
44
 
@@ -79,13 +77,9 @@ module Anyway
79
77
  value.keep_if(...)
80
78
  end
81
79
 
82
- def clear
83
- value.clear
84
- end
80
+ def clear() = value.clear
85
81
 
86
- def trace?
87
- type == :trace
88
- end
82
+ def trace?() = type == :trace
89
83
 
90
84
  def to_h
91
85
  if trace?
@@ -95,9 +89,7 @@ module Anyway
95
89
  end
96
90
  end
97
91
 
98
- def dup
99
- self.class.new(type, value.dup, source)
100
- end
92
+ def dup() = self.class.new(type, value.dup, source)
101
93
 
102
94
  def pretty_print(q)
103
95
  if trace?
@@ -146,9 +138,7 @@ module Anyway
146
138
  (Thread.current[:__anyway__trace_stack__] ||= [])
147
139
  end
148
140
 
149
- def current_trace
150
- trace_stack.last
151
- end
141
+ def current_trace() = trace_stack.last
152
142
 
153
143
  alias tracing? current_trace
154
144
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anyway # :nodoc:
4
- VERSION = "2.0.2"
4
+ VERSION = "2.0.3"
5
5
  end
@@ -3,7 +3,7 @@
3
3
  require "ruby-next"
4
4
 
5
5
  require "ruby-next/language/setup"
6
- RubyNext::Language.setup_gem_load_path
6
+ RubyNext::Language.setup_gem_load_path(transpile: true)
7
7
 
8
8
  require "anyway/version"
9
9
 
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anyway_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-24 00:00:00.000000000 Z
11
+ date: 2020-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ruby-next-core
14
+ name: ruby-next
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.5.1
19
+ version: 0.7.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.5.1
26
+ version: 0.7.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: ammeter
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '0.5'
89
+ version: '0.8'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '0.5'
96
+ version: '0.8'
97
97
  description: "\n Configuration DSL for Ruby libraries and applications.\n Allows
98
98
  you to easily follow the twelve-factor application principles (https://12factor.net/config).\n
99
99
  \ "
@@ -110,6 +110,10 @@ files:
110
110
  - lib/.rbnext/2.7/anyway/config.rb
111
111
  - lib/.rbnext/2.7/anyway/option_parser_builder.rb
112
112
  - lib/.rbnext/2.7/anyway/tracing.rb
113
+ - lib/.rbnext/2.8/anyway/config.rb
114
+ - lib/.rbnext/2.8/anyway/loaders.rb
115
+ - lib/.rbnext/2.8/anyway/loaders/base.rb
116
+ - lib/.rbnext/2.8/anyway/tracing.rb
113
117
  - lib/anyway.rb
114
118
  - lib/anyway/auto_cast.rb
115
119
  - lib/anyway/config.rb