anyway_config 2.0.5 → 2.2.1
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 +4 -4
- data/CHANGELOG.md +241 -181
- data/README.md +238 -13
- data/lib/.rbnext/1995.next/anyway/config.rb +438 -0
- data/lib/.rbnext/1995.next/anyway/dynamic_config.rb +31 -0
- data/lib/.rbnext/1995.next/anyway/env.rb +56 -0
- data/lib/.rbnext/1995.next/anyway/loaders/base.rb +21 -0
- data/lib/.rbnext/1995.next/anyway/tracing.rb +181 -0
- data/lib/.rbnext/2.7/anyway/auto_cast.rb +39 -19
- data/lib/.rbnext/2.7/anyway/config.rb +61 -16
- data/lib/.rbnext/2.7/anyway/rails/loaders/yaml.rb +30 -0
- data/lib/.rbnext/2.7/anyway/rbs.rb +92 -0
- data/lib/.rbnext/2.7/anyway/settings.rb +79 -0
- data/lib/.rbnext/2.7/anyway/tracing.rb +6 -6
- data/lib/.rbnext/2.7/anyway/type_casting.rb +143 -0
- data/lib/.rbnext/3.0/anyway/auto_cast.rb +53 -0
- data/lib/.rbnext/{2.8 → 3.0}/anyway/config.rb +61 -16
- data/lib/.rbnext/{2.8 → 3.0}/anyway/loaders/base.rb +0 -0
- data/lib/.rbnext/{2.8 → 3.0}/anyway/loaders.rb +0 -0
- data/lib/.rbnext/{2.8 → 3.0}/anyway/tracing.rb +6 -6
- data/lib/anyway/auto_cast.rb +39 -19
- data/lib/anyway/config.rb +75 -30
- data/lib/anyway/dynamic_config.rb +6 -2
- data/lib/anyway/env.rb +1 -1
- data/lib/anyway/ext/deep_dup.rb +12 -0
- data/lib/anyway/ext/hash.rb +10 -12
- data/lib/anyway/loaders/base.rb +1 -1
- data/lib/anyway/loaders/env.rb +3 -1
- data/lib/anyway/loaders/yaml.rb +9 -5
- data/lib/anyway/option_parser_builder.rb +1 -3
- data/lib/anyway/optparse_config.rb +5 -7
- data/lib/anyway/rails/loaders/credentials.rb +4 -4
- data/lib/anyway/rails/loaders/secrets.rb +6 -8
- data/lib/anyway/rails/loaders/yaml.rb +11 -0
- data/lib/anyway/rails/settings.rb +9 -2
- data/lib/anyway/rbs.rb +92 -0
- data/lib/anyway/settings.rb +52 -2
- data/lib/anyway/tracing.rb +9 -9
- data/lib/anyway/type_casting.rb +134 -0
- data/lib/anyway/utils/deep_merge.rb +21 -0
- data/lib/anyway/version.rb +1 -1
- data/lib/anyway_config.rb +4 -0
- data/sig/anyway_config.rbs +129 -0
- metadata +42 -15
- data/lib/.rbnext/2.7/anyway/option_parser_builder.rb +0 -31
@@ -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}"
|
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, **opts)
|
36
|
+
key = path.pop
|
37
|
+
trace = if val.is_a?(Hash)
|
38
|
+
Trace.new.tap { _1.merge_values(val, **opts) }
|
39
|
+
else
|
40
|
+
Trace.new(:value, val, **opts)
|
41
|
+
end
|
42
|
+
|
43
|
+
target_trace = path.empty? ? self : value.dig(*path)
|
44
|
+
target_trace.value[key.to_s] = trace
|
45
|
+
|
46
|
+
val
|
47
|
+
end
|
48
|
+
|
49
|
+
def merge_values(hash, **opts)
|
50
|
+
return hash unless hash
|
51
|
+
|
52
|
+
hash.each do |key, val|
|
53
|
+
if val.is_a?(Hash)
|
54
|
+
value[key.to_s].merge_values(val, **opts)
|
55
|
+
else
|
56
|
+
value[key.to_s] = Trace.new(:value, val, **opts)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
hash
|
61
|
+
end
|
62
|
+
|
63
|
+
def merge!(another_trace)
|
64
|
+
raise ArgumentError, "You can only merge into a :trace type, and this is :#{type}" unless trace?
|
65
|
+
raise ArgumentError, "You can only merge a :trace type, but trying :#{type}" unless another_trace.trace?
|
66
|
+
|
67
|
+
another_trace.value.each do |key, sub_trace|
|
68
|
+
if sub_trace.trace?
|
69
|
+
value[key].merge! sub_trace
|
70
|
+
else
|
71
|
+
value[key] = sub_trace
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def keep_if(...)
|
77
|
+
raise ArgumentError, "You can only filter :trace type, and this is :#{type}" unless trace?
|
78
|
+
value.keep_if(...)
|
79
|
+
end
|
80
|
+
|
81
|
+
def clear() = value.clear
|
82
|
+
|
83
|
+
def trace?() = type == :trace
|
84
|
+
|
85
|
+
def to_h
|
86
|
+
if trace?
|
87
|
+
value.transform_values(&:to_h).tap { _1.default_proc = nil }
|
88
|
+
else
|
89
|
+
{value: value, source: source}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def dup() = self.class.new(type, value.dup, **source)
|
94
|
+
|
95
|
+
def pretty_print(q)
|
96
|
+
if trace?
|
97
|
+
q.nest(2) do
|
98
|
+
q.breakable ""
|
99
|
+
q.seplist(value, nil, :each) do |k, v|
|
100
|
+
q.group do
|
101
|
+
q.text k
|
102
|
+
q.text " =>"
|
103
|
+
q.breakable " " unless v.trace?
|
104
|
+
q.pp v
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
else
|
109
|
+
q.pp value
|
110
|
+
q.group(0, " (", ")") do
|
111
|
+
q.seplist(source, lambda { q.breakable " " }, :each) do |k, v|
|
112
|
+
q.group do
|
113
|
+
q.text k.to_s
|
114
|
+
q.text "="
|
115
|
+
q.text v.to_s
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class << self
|
124
|
+
def capture
|
125
|
+
unless Settings.tracing_enabled
|
126
|
+
yield
|
127
|
+
return
|
128
|
+
end
|
129
|
+
|
130
|
+
trace = Trace.new
|
131
|
+
trace_stack.push trace
|
132
|
+
yield
|
133
|
+
trace_stack.last
|
134
|
+
ensure
|
135
|
+
trace_stack.pop
|
136
|
+
end
|
137
|
+
|
138
|
+
def trace_stack
|
139
|
+
(Thread.current[:__anyway__trace_stack__] ||= [])
|
140
|
+
end
|
141
|
+
|
142
|
+
def current_trace() = trace_stack.last
|
143
|
+
|
144
|
+
alias_method :tracing?, :current_trace
|
145
|
+
|
146
|
+
def source_stack
|
147
|
+
(Thread.current[:__anyway__trace_source_stack__] ||= [])
|
148
|
+
end
|
149
|
+
|
150
|
+
def current_trace_source
|
151
|
+
source_stack.last || accessor_source(caller_locations(2, 1).first)
|
152
|
+
end
|
153
|
+
|
154
|
+
def with_trace_source(src)
|
155
|
+
source_stack << src
|
156
|
+
yield
|
157
|
+
ensure
|
158
|
+
source_stack.pop
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def accessor_source(location)
|
164
|
+
{type: :accessor, called_from: location.path_lineno}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
module_function
|
169
|
+
|
170
|
+
def trace!(type, *path, **opts)
|
171
|
+
return yield unless Tracing.tracing?
|
172
|
+
val = yield
|
173
|
+
if val.is_a?(Hash)
|
174
|
+
Tracing.current_trace.merge_values(val, type: type, **opts)
|
175
|
+
else
|
176
|
+
Tracing.current_trace.record_value(val, *path, type: type, **opts)
|
177
|
+
end
|
178
|
+
val
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -7,27 +7,47 @@ module Anyway
|
|
7
7
|
# and doesn't start/end with quote
|
8
8
|
ARRAY_RXP = /\A[^'"].*\s*,\s*.*[^'"]\z/
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
class << self
|
11
|
+
def call(val)
|
12
|
+
return val unless val.is_a?(::Hash) || val.is_a?(::String)
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
14
|
+
case val
|
15
|
+
when Hash
|
16
|
+
val.transform_values { |_1| call(_1) }
|
17
|
+
when ARRAY_RXP
|
18
|
+
val.split(/\s*,\s*/).map { |_1| call(_1) }
|
19
|
+
when /\A(true|t|yes|y)\z/i
|
20
|
+
true
|
21
|
+
when /\A(false|f|no|n)\z/i
|
22
|
+
false
|
23
|
+
when /\A(nil|null)\z/i
|
24
|
+
nil
|
25
|
+
when /\A\d+\z/
|
26
|
+
val.to_i
|
27
|
+
when /\A\d*\.\d+\z/
|
28
|
+
val.to_f
|
29
|
+
when /\A['"].*['"]\z/
|
30
|
+
val.gsub(/(\A['"]|['"]\z)/, "")
|
31
|
+
else
|
32
|
+
val
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def cast_hash(obj)
|
37
|
+
obj.transform_values do |val|
|
38
|
+
val.is_a?(::Hash) ? cast_hash(val) : call(val)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def coerce(_key, val)
|
43
|
+
call(val)
|
30
44
|
end
|
31
45
|
end
|
32
46
|
end
|
47
|
+
|
48
|
+
module NoCast
|
49
|
+
def self.call(val) ; val; end
|
50
|
+
|
51
|
+
def self.coerce(_key, val) ; val; end
|
52
|
+
end
|
33
53
|
end
|
@@ -19,7 +19,7 @@ module Anyway # :nodoc:
|
|
19
19
|
# Provides `attr_config` method to describe
|
20
20
|
# configuration parameters and set defaults
|
21
21
|
class Config
|
22
|
-
PARAM_NAME = /^[a-z_](
|
22
|
+
PARAM_NAME = /^[a-z_](\w+)?$/
|
23
23
|
|
24
24
|
# List of names that couldn't be used as config names
|
25
25
|
# (the class instance methods we use)
|
@@ -40,12 +40,15 @@ module Anyway # :nodoc:
|
|
40
40
|
raise_validation_error
|
41
41
|
reload
|
42
42
|
resolve_config_path
|
43
|
+
tap
|
43
44
|
to_h
|
44
45
|
to_source_trace
|
45
46
|
write_config_attr
|
47
|
+
__type_caster__
|
46
48
|
].freeze
|
47
49
|
|
48
50
|
class Error < StandardError; end
|
51
|
+
|
49
52
|
class ValidationError < Error; end
|
50
53
|
|
51
54
|
include OptparseConfig
|
@@ -142,9 +145,9 @@ module Anyway # :nodoc:
|
|
142
145
|
end
|
143
146
|
|
144
147
|
def on_load(*names, &block)
|
145
|
-
raise ArgumentError, "Either methods or block should be specified, not both" if
|
148
|
+
raise ArgumentError, "Either methods or block should be specified, not both" if block && !names.empty?
|
146
149
|
|
147
|
-
if
|
150
|
+
if block
|
148
151
|
load_callbacks << BlockCallback.new(block)
|
149
152
|
else
|
150
153
|
load_callbacks.push(*names.map { |_1| NamedCallback.new(_1) })
|
@@ -194,15 +197,55 @@ module Anyway # :nodoc:
|
|
194
197
|
|
195
198
|
def new_empty_config() ; {}; end
|
196
199
|
|
200
|
+
def coerce_types(mapping)
|
201
|
+
coercion_mapping.deep_merge!(mapping)
|
202
|
+
end
|
203
|
+
|
204
|
+
def coercion_mapping
|
205
|
+
return @coercion_mapping if instance_variable_defined?(:@coercion_mapping)
|
206
|
+
|
207
|
+
@coercion_mapping = if superclass < Anyway::Config
|
208
|
+
superclass.coercion_mapping.deep_dup
|
209
|
+
else
|
210
|
+
{}
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def type_caster(val = nil)
|
215
|
+
return @type_caster unless val.nil?
|
216
|
+
|
217
|
+
@type_caster ||=
|
218
|
+
if coercion_mapping.empty?
|
219
|
+
fallback_type_caster
|
220
|
+
else
|
221
|
+
::Anyway::TypeCaster.new(coercion_mapping, fallback: fallback_type_caster)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def fallback_type_caster(val = nil)
|
226
|
+
return (@fallback_type_caster = val) unless val.nil?
|
227
|
+
|
228
|
+
return @fallback_type_caster if instance_variable_defined?(:@fallback_type_caster)
|
229
|
+
|
230
|
+
@fallback_type_caster = if superclass < Anyway::Config
|
231
|
+
superclass.fallback_type_caster.deep_dup
|
232
|
+
else
|
233
|
+
::Anyway::AutoCast
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def disable_auto_cast!
|
238
|
+
@fallback_type_caster = ::Anyway::NoCast
|
239
|
+
end
|
240
|
+
|
197
241
|
private
|
198
242
|
|
199
243
|
def define_config_accessor(*names)
|
200
244
|
names.each do |name|
|
201
245
|
accessors_module.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
202
246
|
def #{name}=(val)
|
203
|
-
__trace__&.record_value(val, \"#{name}\", Tracing.current_trace_source)
|
204
|
-
|
205
|
-
@#{name} = values[:#{name}] = val
|
247
|
+
__trace__&.record_value(val, \"#{name}\", **Tracing.current_trace_source)
|
248
|
+
values[:#{name}] = val
|
206
249
|
end
|
207
250
|
|
208
251
|
def #{name}
|
@@ -229,7 +272,7 @@ module Anyway # :nodoc:
|
|
229
272
|
# handle two cases:
|
230
273
|
# - SomeModule::Config => "some_module"
|
231
274
|
# - SomeConfig => "some"
|
232
|
-
unless name =~ /^(\w+)(
|
275
|
+
unless name =~ /^(\w+)(::)?Config$/
|
233
276
|
raise "Couldn't infer config name, please, specify it explicitly" \
|
234
277
|
"via `config_name :my_config`"
|
235
278
|
end
|
@@ -288,17 +331,14 @@ module Anyway # :nodoc:
|
|
288
331
|
trace = Tracing.capture do
|
289
332
|
Tracing.trace!(:defaults) { base_config }
|
290
333
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
env_prefix: env_prefix,
|
295
|
-
config_path: resolve_config_path(config_name, env_prefix)
|
296
|
-
)
|
334
|
+
config_path = resolve_config_path(config_name, env_prefix)
|
335
|
+
|
336
|
+
load_from_sources(base_config, name: config_name, env_prefix: env_prefix, config_path: config_path)
|
297
337
|
|
298
338
|
if overrides
|
299
339
|
Tracing.trace!(:load) { overrides }
|
300
340
|
|
301
|
-
|
341
|
+
Utils.deep_merge!(base_config, overrides)
|
302
342
|
end
|
303
343
|
end
|
304
344
|
|
@@ -321,7 +361,7 @@ module Anyway # :nodoc:
|
|
321
361
|
|
322
362
|
def load_from_sources(base_config, **options)
|
323
363
|
Anyway.loaders.each do |(_id, loader)|
|
324
|
-
|
364
|
+
Utils.deep_merge!(base_config, loader.call(**options))
|
325
365
|
end
|
326
366
|
base_config
|
327
367
|
end
|
@@ -375,7 +415,7 @@ module Anyway # :nodoc:
|
|
375
415
|
values[name].nil? || (values[name].is_a?(String) && values[name].empty?)
|
376
416
|
end.then do |missing|
|
377
417
|
next if missing.empty?
|
378
|
-
raise_validation_error "The following config parameters are missing or empty: #{missing.join(", ")}"
|
418
|
+
raise_validation_error "The following config parameters for `#{self.class.name}(config_name: #{self.class.config_name})` are missing or empty: #{missing.join(", ")}"
|
379
419
|
end
|
380
420
|
end
|
381
421
|
|
@@ -383,11 +423,16 @@ module Anyway # :nodoc:
|
|
383
423
|
key = key.to_sym
|
384
424
|
return unless self.class.config_attributes.include?(key)
|
385
425
|
|
426
|
+
val = __type_caster__.coerce(key, val)
|
386
427
|
public_send(:"#{key}=", val)
|
387
428
|
end
|
388
429
|
|
389
430
|
def raise_validation_error(msg)
|
390
431
|
raise ValidationError, msg
|
391
432
|
end
|
433
|
+
|
434
|
+
def __type_caster__
|
435
|
+
self.class.type_caster
|
436
|
+
end
|
392
437
|
end
|
393
438
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyway
|
4
|
+
module Rails
|
5
|
+
module Loaders
|
6
|
+
class YAML < Anyway::Loaders::YAML
|
7
|
+
def load_base_yml(*)
|
8
|
+
parsed_yml = super
|
9
|
+
return parsed_yml unless environmental?(parsed_yml)
|
10
|
+
|
11
|
+
super[::Rails.env] || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def environmental?(parsed_yml)
|
17
|
+
return true unless Settings.future.unwrap_known_environments
|
18
|
+
# likely
|
19
|
+
return true if parsed_yml.key?(::Rails.env)
|
20
|
+
# less likely
|
21
|
+
::Rails.application.config.anyway_config.known_environments.any? { |_1| parsed_yml.key?(_1) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def relative_config_path(path)
|
25
|
+
Pathname.new(path).relative_path_from(::Rails.root)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
using RubyNext;
|
3
|
+
module Anyway
|
4
|
+
module RBSGenerator
|
5
|
+
TYPE_TO_CLASS = {
|
6
|
+
string: "String",
|
7
|
+
integer: "Integer",
|
8
|
+
float: "Float",
|
9
|
+
date: "Date",
|
10
|
+
datetime: "DateTime",
|
11
|
+
uri: "URI",
|
12
|
+
boolean: "bool"
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
# Generate RBS signature from a config class
|
16
|
+
def to_rbs
|
17
|
+
*namespace, class_name = name.split("::")
|
18
|
+
|
19
|
+
buf = []
|
20
|
+
indent = 0
|
21
|
+
interface_name = "_Config"
|
22
|
+
|
23
|
+
if namespace.empty?
|
24
|
+
interface_name = "_#{class_name}"
|
25
|
+
else
|
26
|
+
buf << "module #{namespace.join("::")}"
|
27
|
+
indent += 1
|
28
|
+
end
|
29
|
+
|
30
|
+
# Using interface emulates a module we include to provide getters and setters
|
31
|
+
# (thus making `super` possible)
|
32
|
+
buf << "#{" " * indent}interface #{interface_name}"
|
33
|
+
indent += 1
|
34
|
+
|
35
|
+
# Generating setters and getters for config attributes
|
36
|
+
config_attributes.each do |param|
|
37
|
+
type = coercion_mapping[param] || defaults[param.to_s]
|
38
|
+
|
39
|
+
type =
|
40
|
+
case; when ((__m__ = type)) && false
|
41
|
+
when (NilClass === __m__)
|
42
|
+
"untyped"
|
43
|
+
when (Symbol === __m__)
|
44
|
+
TYPE_TO_CLASS.fetch(type) { defaults[param] ? "Symbol" : "untyped" }
|
45
|
+
when (Array === __m__)
|
46
|
+
"Array[untyped]"
|
47
|
+
when ((__m__.respond_to?(:deconstruct_keys) && (((__m_hash__src__ = __m__.deconstruct_keys(nil)) || true) && (Hash === __m_hash__src__ || Kernel.raise(TypeError, "#deconstruct_keys must return Hash"))) && (__m_hash__ = __m_hash__src__.dup)) && ((__m_hash__.key?(:array) && __m_hash__.key?(:type)) && (((array = __m_hash__.delete(:array)) || true) && (((type = __m_hash__.delete(:type)) || true) && __m_hash__.empty?))))
|
48
|
+
"Array[#{TYPE_TO_CLASS.fetch(type, "untyped")}]"
|
49
|
+
when (Hash === __m__)
|
50
|
+
"Hash[string,untyped]"
|
51
|
+
when ((TrueClass === __m__) || (FalseClass === __m__))
|
52
|
+
"bool"
|
53
|
+
else
|
54
|
+
type.class.to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
getter_type = type
|
58
|
+
getter_type = "#{type}?" unless required_attributes.include?(param)
|
59
|
+
|
60
|
+
buf << "#{" " * indent}def #{param}: () -> #{getter_type}"
|
61
|
+
buf << "#{" " * indent}def #{param}=: (#{type}) -> void"
|
62
|
+
|
63
|
+
if type == "bool" || type == "bool?"
|
64
|
+
buf << "#{" " * indent}def #{param}?: () -> #{getter_type}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
indent -= 1
|
69
|
+
buf << "#{" " * indent}end"
|
70
|
+
|
71
|
+
buf << ""
|
72
|
+
|
73
|
+
buf << "#{" " * indent}class #{class_name} < #{superclass.name}"
|
74
|
+
indent += 1
|
75
|
+
|
76
|
+
buf << "#{" " * indent}include #{interface_name}"
|
77
|
+
|
78
|
+
indent -= 1
|
79
|
+
buf << "#{" " * indent}end"
|
80
|
+
|
81
|
+
unless namespace.empty?
|
82
|
+
buf << "end"
|
83
|
+
end
|
84
|
+
|
85
|
+
buf << ""
|
86
|
+
|
87
|
+
buf.join("\n")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Config.extend RBSGenerator
|
92
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyway
|
4
|
+
# Use Settings name to not confuse with Config.
|
5
|
+
#
|
6
|
+
# Settings contain the library-wide configuration.
|
7
|
+
class Settings
|
8
|
+
# Future encapsulates settings that will be introduced in the upcoming version
|
9
|
+
# with the default values, which could break compatibility
|
10
|
+
class Future
|
11
|
+
class << self
|
12
|
+
def setting(name, default_value)
|
13
|
+
settings[name] = default_value
|
14
|
+
|
15
|
+
define_method(name) do
|
16
|
+
store[name]
|
17
|
+
end
|
18
|
+
|
19
|
+
define_method(:"#{name}=") do |val|
|
20
|
+
store[name] = val
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def settings
|
25
|
+
@settings ||= {}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@store = {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def use(*names)
|
34
|
+
store.clear
|
35
|
+
names.each { |_1| store[_1] = self.class.settings[_1] }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :store
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
# Define whether to load data from
|
45
|
+
# *.yml.local (or credentials/local.yml.enc)
|
46
|
+
attr_accessor :use_local_files
|
47
|
+
|
48
|
+
# A proc returning a path to YML config file given the config name
|
49
|
+
attr_reader :default_config_path
|
50
|
+
|
51
|
+
def default_config_path=(val)
|
52
|
+
if val.is_a?(Proc)
|
53
|
+
@default_config_path = val
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
val = val.to_s
|
58
|
+
|
59
|
+
@default_config_path = ->(name) { File.join(val, "#{name}.yml") }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Enable source tracing
|
63
|
+
attr_accessor :tracing_enabled
|
64
|
+
|
65
|
+
def future
|
66
|
+
@future ||= Future.new
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# By default, use local files only in development (that's the purpose if the local files)
|
71
|
+
self.use_local_files = (ENV["RACK_ENV"] == "development" || ENV["RAILS_ENV"] == "development")
|
72
|
+
|
73
|
+
# By default, consider configs are stored in the ./config folder
|
74
|
+
self.default_config_path = ->(name) { "./config/#{name}.yml" }
|
75
|
+
|
76
|
+
# Tracing is enabled by default
|
77
|
+
self.tracing_enabled = true
|
78
|
+
end
|
79
|
+
end
|
@@ -32,7 +32,8 @@ module Anyway
|
|
32
32
|
value.dig(*__rest__, &__block__)
|
33
33
|
end
|
34
34
|
|
35
|
-
def record_value(val, *path,
|
35
|
+
def record_value(val, *path, **opts)
|
36
|
+
key = path.pop
|
36
37
|
trace = if val.is_a?(Hash)
|
37
38
|
Trace.new.tap { |_1| _1.merge_values(val, **opts) }
|
38
39
|
else
|
@@ -89,7 +90,7 @@ module Anyway
|
|
89
90
|
end
|
90
91
|
end
|
91
92
|
|
92
|
-
def dup() ; self.class.new(type, value.dup, source); end
|
93
|
+
def dup() ; self.class.new(type, value.dup, **source); end
|
93
94
|
|
94
95
|
def pretty_print(q)
|
95
96
|
if trace?
|
@@ -140,7 +141,7 @@ module Anyway
|
|
140
141
|
|
141
142
|
def current_trace() ; trace_stack.last; end
|
142
143
|
|
143
|
-
|
144
|
+
alias_method :tracing?, :current_trace
|
144
145
|
|
145
146
|
def source_stack
|
146
147
|
(Thread.current[:__anyway__trace_source_stack__] ||= [])
|
@@ -168,12 +169,11 @@ module Anyway
|
|
168
169
|
|
169
170
|
def trace!(type, *path, **opts)
|
170
171
|
return yield unless Tracing.tracing?
|
171
|
-
source = {type: type}.merge(opts)
|
172
172
|
val = yield
|
173
173
|
if val.is_a?(Hash)
|
174
|
-
Tracing.current_trace.merge_values(val, **
|
174
|
+
Tracing.current_trace.merge_values(val, type: type, **opts)
|
175
175
|
else
|
176
|
-
Tracing.current_trace.record_value(val, *path, **
|
176
|
+
Tracing.current_trace.record_value(val, *path, type: type, **opts)
|
177
177
|
end
|
178
178
|
val
|
179
179
|
end
|