anyway_config 2.8.1 → 2.9.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 +22 -0
- data/README.md +61 -2
- data/lib/.rbnext/2.7/anyway/loaders/yaml.rb +2 -0
- data/lib/.rbnext/2.7/anyway/settings.rb +12 -0
- data/lib/.rbnext/3.0/anyway/config.rb +51 -3
- data/lib/.rbnext/3.0/anyway/loaders/base.rb +5 -1
- data/lib/.rbnext/3.0/anyway/loaders/ejson.rb +94 -0
- data/lib/.rbnext/3.0/anyway/loaders/yaml.rb +2 -0
- data/lib/.rbnext/3.0/anyway/rails/loaders/credentials.rb +64 -0
- data/lib/.rbnext/3.0/anyway/rails/loaders/secrets.rb +42 -0
- data/lib/.rbnext/3.1/anyway/config.rb +51 -3
- data/lib/.rbnext/3.1/anyway/loaders/base.rb +5 -1
- data/lib/.rbnext/3.2/anyway/config.rb +51 -3
- data/lib/.rbnext/3.2/anyway/loaders/base.rb +5 -1
- data/lib/.rbnext/3.4/anyway/config.rb +51 -3
- data/lib/anyway/config.rb +51 -3
- data/lib/anyway/loaders/base.rb +5 -1
- data/lib/anyway/loaders/ejson.rb +6 -1
- data/lib/anyway/loaders/yaml.rb +2 -0
- data/lib/anyway/rails/loaders/credentials.rb +2 -0
- data/lib/anyway/rails/loaders/secrets.rb +2 -0
- data/lib/anyway/rails.rb +1 -1
- data/lib/anyway/settings.rb +12 -0
- data/lib/anyway/version.rb +1 -1
- data/sig/anyway_config.rbs +12 -1
- data/skills/anyway-config/SKILL.md +223 -0
- data/skills/anyway-config/references/docs.md +30 -0
- data/skills/anyway-config/references/organizing.md +341 -0
- data/skills/anyway-config/references/testing.md +139 -0
- metadata +11 -2
|
@@ -33,6 +33,7 @@ module Anyway # :nodoc:
|
|
|
33
33
|
deconstruct_keys
|
|
34
34
|
dig
|
|
35
35
|
dup
|
|
36
|
+
format_unknown_attribute
|
|
36
37
|
initialize
|
|
37
38
|
load
|
|
38
39
|
load_from_sources
|
|
@@ -52,6 +53,8 @@ module Anyway # :nodoc:
|
|
|
52
53
|
|
|
53
54
|
class ValidationError < Error; end
|
|
54
55
|
|
|
56
|
+
class UnknownAttributesError < ValidationError; end
|
|
57
|
+
|
|
55
58
|
include OptparseConfig
|
|
56
59
|
include DynamicConfig
|
|
57
60
|
|
|
@@ -374,6 +377,8 @@ module Anyway # :nodoc:
|
|
|
374
377
|
)
|
|
375
378
|
|
|
376
379
|
if overrides
|
|
380
|
+
reject_unknown_config_attributes!(overrides, source: :overrides, strict: Settings.future.reject_unknown_overrides == true)
|
|
381
|
+
|
|
377
382
|
Tracing.trace!(:load) { overrides }
|
|
378
383
|
|
|
379
384
|
Utils.deep_merge!(base_config, overrides)
|
|
@@ -400,10 +405,16 @@ module Anyway # :nodoc:
|
|
|
400
405
|
def load_from_sources(base_config, **opts)
|
|
401
406
|
source_filter = self.class.configuration_sources
|
|
402
407
|
|
|
403
|
-
Anyway.loaders.each do |(id,
|
|
408
|
+
Anyway.loaders.each do |(id, loader_or_proc)|
|
|
404
409
|
next if source_filter && !source_filter.include?(id)
|
|
405
|
-
|
|
410
|
+
|
|
411
|
+
loader = (loader_or_proc.is_a?(Class) && loader_or_proc <= Loaders::Base) ? loader_or_proc.new(**opts) : loader_or_proc
|
|
412
|
+
loader_data = loader.call(**opts)
|
|
413
|
+
reject_unknown_config_attributes!(loader_data, source: id) if loader.is_a?(Loaders::Base) && loader.schemaful?
|
|
414
|
+
|
|
415
|
+
Utils.deep_merge!(base_config, loader_data)
|
|
406
416
|
end
|
|
417
|
+
|
|
407
418
|
base_config
|
|
408
419
|
end
|
|
409
420
|
|
|
@@ -460,13 +471,50 @@ module Anyway # :nodoc:
|
|
|
460
471
|
|
|
461
472
|
self.class.required_attributes.select do |name|
|
|
462
473
|
val = values.dig(*name.to_s.split(".").map(&:to_sym))
|
|
463
|
-
val.nil? || (val.
|
|
474
|
+
val.nil? || (val.respond_to?(:to_s) && val.to_s.empty?)
|
|
464
475
|
end.then do |missing|
|
|
465
476
|
next if missing.empty?
|
|
466
477
|
raise_validation_error "The following config parameters for `#{self.class.name}(config_name: #{self.class.config_name})` are missing or empty: #{missing.join(", ")}"
|
|
467
478
|
end
|
|
468
479
|
end
|
|
469
480
|
|
|
481
|
+
def reject_unknown_config_attributes!(data, source:, strict: false)
|
|
482
|
+
return if data.nil? || data.empty?
|
|
483
|
+
|
|
484
|
+
mode = strict || Settings.enforce_config_schema
|
|
485
|
+
return unless mode
|
|
486
|
+
|
|
487
|
+
known = self.class.config_attributes.map(&:to_s)
|
|
488
|
+
unknown = data.keys.map(&:to_s) - known
|
|
489
|
+
|
|
490
|
+
unless strict
|
|
491
|
+
rescuer = Settings.rescue_unknown_attributes_with
|
|
492
|
+
unknown.reject! { |it| rescuer.call(self, it) } if rescuer
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
return if unknown.empty?
|
|
496
|
+
|
|
497
|
+
msg = "Unknown config attributes for `#{self.class.name || "<anonymous>"}(config_name: #{config_name})` " \
|
|
498
|
+
"provided by #{source}: #{unknown.map { |it| format_unknown_attribute(it, known) }.join(", ")}"
|
|
499
|
+
|
|
500
|
+
if strict
|
|
501
|
+
raise ArgumentError, msg
|
|
502
|
+
elsif mode == :warn
|
|
503
|
+
Kernel.warn msg
|
|
504
|
+
else
|
|
505
|
+
raise UnknownAttributesError, msg
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def format_unknown_attribute(key, known)
|
|
510
|
+
return key unless defined?(::DidYouMean::SpellChecker)
|
|
511
|
+
|
|
512
|
+
suggestions = ::DidYouMean::SpellChecker.new(dictionary: known).correct(key)
|
|
513
|
+
return key if suggestions.empty?
|
|
514
|
+
|
|
515
|
+
"#{key} (did you mean: #{suggestions.join(", ")}?)"
|
|
516
|
+
end
|
|
517
|
+
|
|
470
518
|
def write_config_attr(key, val)
|
|
471
519
|
key = key.to_sym
|
|
472
520
|
return unless self.class.config_attributes.include?(key)
|
|
@@ -11,11 +11,15 @@ module Anyway
|
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def initialize(local:)
|
|
14
|
+
def initialize(local: Anyway::Settings.use_local_files, **__kwrest__)
|
|
15
15
|
@local = local
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def use_local?() = @local == true
|
|
19
|
+
|
|
20
|
+
# Whether this loader supports strict schema (so we can warn or raise on
|
|
21
|
+
# unknown attributes)
|
|
22
|
+
def schemaful?() = false
|
|
19
23
|
end
|
|
20
24
|
end
|
|
21
25
|
end
|
|
@@ -33,6 +33,7 @@ module Anyway # :nodoc:
|
|
|
33
33
|
deconstruct_keys
|
|
34
34
|
dig
|
|
35
35
|
dup
|
|
36
|
+
format_unknown_attribute
|
|
36
37
|
initialize
|
|
37
38
|
load
|
|
38
39
|
load_from_sources
|
|
@@ -52,6 +53,8 @@ module Anyway # :nodoc:
|
|
|
52
53
|
|
|
53
54
|
class ValidationError < Error; end
|
|
54
55
|
|
|
56
|
+
class UnknownAttributesError < ValidationError; end
|
|
57
|
+
|
|
55
58
|
include OptparseConfig
|
|
56
59
|
include DynamicConfig
|
|
57
60
|
|
|
@@ -374,6 +377,8 @@ module Anyway # :nodoc:
|
|
|
374
377
|
)
|
|
375
378
|
|
|
376
379
|
if overrides
|
|
380
|
+
reject_unknown_config_attributes!(overrides, source: :overrides, strict: Settings.future.reject_unknown_overrides == true)
|
|
381
|
+
|
|
377
382
|
Tracing.trace!(:load) { overrides }
|
|
378
383
|
|
|
379
384
|
Utils.deep_merge!(base_config, overrides)
|
|
@@ -400,10 +405,16 @@ module Anyway # :nodoc:
|
|
|
400
405
|
def load_from_sources(base_config, **opts)
|
|
401
406
|
source_filter = self.class.configuration_sources
|
|
402
407
|
|
|
403
|
-
Anyway.loaders.each do |(id,
|
|
408
|
+
Anyway.loaders.each do |(id, loader_or_proc)|
|
|
404
409
|
next if source_filter && !source_filter.include?(id)
|
|
405
|
-
|
|
410
|
+
|
|
411
|
+
loader = (loader_or_proc.is_a?(Class) && loader_or_proc <= Loaders::Base) ? loader_or_proc.new(**opts) : loader_or_proc
|
|
412
|
+
loader_data = loader.call(**opts)
|
|
413
|
+
reject_unknown_config_attributes!(loader_data, source: id) if loader.is_a?(Loaders::Base) && loader.schemaful?
|
|
414
|
+
|
|
415
|
+
Utils.deep_merge!(base_config, loader_data)
|
|
406
416
|
end
|
|
417
|
+
|
|
407
418
|
base_config
|
|
408
419
|
end
|
|
409
420
|
|
|
@@ -460,13 +471,50 @@ module Anyway # :nodoc:
|
|
|
460
471
|
|
|
461
472
|
self.class.required_attributes.select do |name|
|
|
462
473
|
val = values.dig(*name.to_s.split(".").map(&:to_sym))
|
|
463
|
-
val.nil? || (val.
|
|
474
|
+
val.nil? || (val.respond_to?(:to_s) && val.to_s.empty?)
|
|
464
475
|
end.then do |missing|
|
|
465
476
|
next if missing.empty?
|
|
466
477
|
raise_validation_error "The following config parameters for `#{self.class.name}(config_name: #{self.class.config_name})` are missing or empty: #{missing.join(", ")}"
|
|
467
478
|
end
|
|
468
479
|
end
|
|
469
480
|
|
|
481
|
+
def reject_unknown_config_attributes!(data, source:, strict: false)
|
|
482
|
+
return if data.nil? || data.empty?
|
|
483
|
+
|
|
484
|
+
mode = strict || Settings.enforce_config_schema
|
|
485
|
+
return unless mode
|
|
486
|
+
|
|
487
|
+
known = self.class.config_attributes.map(&:to_s)
|
|
488
|
+
unknown = data.keys.map(&:to_s) - known
|
|
489
|
+
|
|
490
|
+
unless strict
|
|
491
|
+
rescuer = Settings.rescue_unknown_attributes_with
|
|
492
|
+
unknown.reject! { |it| rescuer.call(self, it) } if rescuer
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
return if unknown.empty?
|
|
496
|
+
|
|
497
|
+
msg = "Unknown config attributes for `#{self.class.name || "<anonymous>"}(config_name: #{config_name})` " \
|
|
498
|
+
"provided by #{source}: #{unknown.map { |it| format_unknown_attribute(it, known) }.join(", ")}"
|
|
499
|
+
|
|
500
|
+
if strict
|
|
501
|
+
raise ArgumentError, msg
|
|
502
|
+
elsif mode == :warn
|
|
503
|
+
Kernel.warn msg
|
|
504
|
+
else
|
|
505
|
+
raise UnknownAttributesError, msg
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def format_unknown_attribute(key, known)
|
|
510
|
+
return key unless defined?(::DidYouMean::SpellChecker)
|
|
511
|
+
|
|
512
|
+
suggestions = ::DidYouMean::SpellChecker.new(dictionary: known).correct(key)
|
|
513
|
+
return key if suggestions.empty?
|
|
514
|
+
|
|
515
|
+
"#{key} (did you mean: #{suggestions.join(", ")}?)"
|
|
516
|
+
end
|
|
517
|
+
|
|
470
518
|
def write_config_attr(key, val)
|
|
471
519
|
key = key.to_sym
|
|
472
520
|
return unless self.class.config_attributes.include?(key)
|
data/lib/anyway/config.rb
CHANGED
|
@@ -33,6 +33,7 @@ module Anyway # :nodoc:
|
|
|
33
33
|
deconstruct_keys
|
|
34
34
|
dig
|
|
35
35
|
dup
|
|
36
|
+
format_unknown_attribute
|
|
36
37
|
initialize
|
|
37
38
|
load
|
|
38
39
|
load_from_sources
|
|
@@ -52,6 +53,8 @@ module Anyway # :nodoc:
|
|
|
52
53
|
|
|
53
54
|
class ValidationError < Error; end
|
|
54
55
|
|
|
56
|
+
class UnknownAttributesError < ValidationError; end
|
|
57
|
+
|
|
55
58
|
include OptparseConfig
|
|
56
59
|
include DynamicConfig
|
|
57
60
|
|
|
@@ -374,6 +377,8 @@ module Anyway # :nodoc:
|
|
|
374
377
|
)
|
|
375
378
|
|
|
376
379
|
if overrides
|
|
380
|
+
reject_unknown_config_attributes!(overrides, source: :overrides, strict: Settings.future.reject_unknown_overrides == true)
|
|
381
|
+
|
|
377
382
|
Tracing.trace!(:load) { overrides }
|
|
378
383
|
|
|
379
384
|
Utils.deep_merge!(base_config, overrides)
|
|
@@ -400,10 +405,16 @@ module Anyway # :nodoc:
|
|
|
400
405
|
def load_from_sources(base_config, **opts)
|
|
401
406
|
source_filter = self.class.configuration_sources
|
|
402
407
|
|
|
403
|
-
Anyway.loaders.each do |(id,
|
|
408
|
+
Anyway.loaders.each do |(id, loader_or_proc)|
|
|
404
409
|
next if source_filter && !source_filter.include?(id)
|
|
405
|
-
|
|
410
|
+
|
|
411
|
+
loader = (loader_or_proc.is_a?(Class) && loader_or_proc <= Loaders::Base) ? loader_or_proc.new(**opts) : loader_or_proc
|
|
412
|
+
loader_data = loader.call(**opts)
|
|
413
|
+
reject_unknown_config_attributes!(loader_data, source: id) if loader.is_a?(Loaders::Base) && loader.schemaful?
|
|
414
|
+
|
|
415
|
+
Utils.deep_merge!(base_config, loader_data)
|
|
406
416
|
end
|
|
417
|
+
|
|
407
418
|
base_config
|
|
408
419
|
end
|
|
409
420
|
|
|
@@ -460,13 +471,50 @@ module Anyway # :nodoc:
|
|
|
460
471
|
|
|
461
472
|
self.class.required_attributes.select do |name|
|
|
462
473
|
val = values.dig(*name.to_s.split(".").map(&:to_sym))
|
|
463
|
-
val.nil? || (val.
|
|
474
|
+
val.nil? || (val.respond_to?(:to_s) && val.to_s.empty?)
|
|
464
475
|
end.then do |missing|
|
|
465
476
|
next if missing.empty?
|
|
466
477
|
raise_validation_error "The following config parameters for `#{self.class.name}(config_name: #{self.class.config_name})` are missing or empty: #{missing.join(", ")}"
|
|
467
478
|
end
|
|
468
479
|
end
|
|
469
480
|
|
|
481
|
+
def reject_unknown_config_attributes!(data, source:, strict: false)
|
|
482
|
+
return if data.nil? || data.empty?
|
|
483
|
+
|
|
484
|
+
mode = strict || Settings.enforce_config_schema
|
|
485
|
+
return unless mode
|
|
486
|
+
|
|
487
|
+
known = self.class.config_attributes.map(&:to_s)
|
|
488
|
+
unknown = data.keys.map(&:to_s) - known
|
|
489
|
+
|
|
490
|
+
unless strict
|
|
491
|
+
rescuer = Settings.rescue_unknown_attributes_with
|
|
492
|
+
unknown.reject! { rescuer.call(self, it) } if rescuer
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
return if unknown.empty?
|
|
496
|
+
|
|
497
|
+
msg = "Unknown config attributes for `#{self.class.name || "<anonymous>"}(config_name: #{config_name})` " \
|
|
498
|
+
"provided by #{source}: #{unknown.map { format_unknown_attribute(it, known) }.join(", ")}"
|
|
499
|
+
|
|
500
|
+
if strict
|
|
501
|
+
raise ArgumentError, msg
|
|
502
|
+
elsif mode == :warn
|
|
503
|
+
Kernel.warn msg
|
|
504
|
+
else
|
|
505
|
+
raise UnknownAttributesError, msg
|
|
506
|
+
end
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def format_unknown_attribute(key, known)
|
|
510
|
+
return key unless defined?(::DidYouMean::SpellChecker)
|
|
511
|
+
|
|
512
|
+
suggestions = ::DidYouMean::SpellChecker.new(dictionary: known).correct(key)
|
|
513
|
+
return key if suggestions.empty?
|
|
514
|
+
|
|
515
|
+
"#{key} (did you mean: #{suggestions.join(", ")}?)"
|
|
516
|
+
end
|
|
517
|
+
|
|
470
518
|
def write_config_attr(key, val)
|
|
471
519
|
key = key.to_sym
|
|
472
520
|
return unless self.class.config_attributes.include?(key)
|
data/lib/anyway/loaders/base.rb
CHANGED
|
@@ -11,11 +11,15 @@ module Anyway
|
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def initialize(local:)
|
|
14
|
+
def initialize(local: Anyway::Settings.use_local_files, **)
|
|
15
15
|
@local = local
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def use_local?() = @local == true
|
|
19
|
+
|
|
20
|
+
# Whether this loader supports strict schema (so we can warn or raise on
|
|
21
|
+
# unknown attributes)
|
|
22
|
+
def schemaful?() = false
|
|
19
23
|
end
|
|
20
24
|
end
|
|
21
25
|
end
|
data/lib/anyway/loaders/ejson.rb
CHANGED
|
@@ -26,11 +26,14 @@ module Anyway
|
|
|
26
26
|
config_hash = if ejson_namespace
|
|
27
27
|
secrets_hash[ejson_namespace]
|
|
28
28
|
else
|
|
29
|
-
secrets_hash
|
|
29
|
+
secrets_hash
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
next unless config_hash.is_a?(Hash)
|
|
33
33
|
|
|
34
|
+
# Underscore-prefixed keys are not encrypted (e.g., _public_key)
|
|
35
|
+
config_hash = config_hash.reject { |key, _| key.start_with?("_") }
|
|
36
|
+
|
|
34
37
|
configs <<
|
|
35
38
|
trace!(:ejson, path: rel_path) do
|
|
36
39
|
config_hash
|
|
@@ -44,6 +47,8 @@ module Anyway
|
|
|
44
47
|
end
|
|
45
48
|
end
|
|
46
49
|
|
|
50
|
+
def schemaful?() = true
|
|
51
|
+
|
|
47
52
|
private
|
|
48
53
|
|
|
49
54
|
def rel_config_paths
|
data/lib/anyway/loaders/yaml.rb
CHANGED
data/lib/anyway/rails.rb
CHANGED
|
@@ -12,7 +12,7 @@ require "anyway/rails/loaders"
|
|
|
12
12
|
# Configure Rails loaders
|
|
13
13
|
Anyway.loaders.override :yml, Anyway::Rails::Loaders::YAML
|
|
14
14
|
|
|
15
|
-
if Rails
|
|
15
|
+
if Gem::Version.new(Rails.version) >= Gem::Version.new("7.1")
|
|
16
16
|
Anyway.loaders.insert_after :yml, :credentials, Anyway::Rails::Loaders::Credentials
|
|
17
17
|
else
|
|
18
18
|
Anyway.loaders.insert_after :yml, :secrets, Anyway::Rails::Loaders::Secrets
|
data/lib/anyway/settings.rb
CHANGED
|
@@ -38,6 +38,7 @@ module Anyway
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
setting :unwrap_known_environments, true
|
|
41
|
+
setting :reject_unknown_overrides, true
|
|
41
42
|
|
|
42
43
|
private
|
|
43
44
|
|
|
@@ -55,6 +56,14 @@ module Anyway
|
|
|
55
56
|
# Suppress required validations for CI/CD pipelines
|
|
56
57
|
attr_accessor :suppress_required_validations
|
|
57
58
|
|
|
59
|
+
# Whether to check for unknown attributes in schemaful (key-based) sources:
|
|
60
|
+
# false — ignore unknown attributes, true — raise, :warn — print a warning
|
|
61
|
+
attr_accessor :enforce_config_schema
|
|
62
|
+
|
|
63
|
+
# A callable (config, key) -> bool to ignore specific unknown attributes
|
|
64
|
+
# (e.g., when the same source is shared by multiple configs)
|
|
65
|
+
attr_accessor :rescue_unknown_attributes_with
|
|
66
|
+
|
|
58
67
|
# A proc returning a path to YML config file given the config name
|
|
59
68
|
attr_reader :default_config_path
|
|
60
69
|
|
|
@@ -113,5 +122,8 @@ module Anyway
|
|
|
113
122
|
|
|
114
123
|
# By default, use ANYWAY_SUPPRESS_VALIDATIONS
|
|
115
124
|
self.suppress_required_validations = %w[1 t true y yes].include?(ENV["ANYWAY_SUPPRESS_VALIDATIONS"])
|
|
125
|
+
|
|
126
|
+
# Unknown attributes are ignored by default
|
|
127
|
+
self.enforce_config_schema = false
|
|
116
128
|
end
|
|
117
129
|
end
|
data/lib/anyway/version.rb
CHANGED
data/sig/anyway_config.rbs
CHANGED
|
@@ -9,6 +9,10 @@ module Anyway
|
|
|
9
9
|
def self.default_environmental_key: -> String?
|
|
10
10
|
def self.suppress_required_validations: -> bool
|
|
11
11
|
def self.known_environments: -> Array[String]?
|
|
12
|
+
def self.enforce_config_schema: -> (bool | :warn)
|
|
13
|
+
def self.enforce_config_schema=: (bool | :warn) -> void
|
|
14
|
+
def self.rescue_unknown_attributes_with: -> (^(Config, String) -> boolish)?
|
|
15
|
+
def self.rescue_unknown_attributes_with=: ((^(Config, String) -> boolish)?) -> void
|
|
12
16
|
|
|
13
17
|
class Future
|
|
14
18
|
def self.setting: (untyped name, untyped default_value) -> untyped
|
|
@@ -107,6 +111,8 @@ module Anyway
|
|
|
107
111
|
private
|
|
108
112
|
attr_reader values: Hash[untyped, untyped]
|
|
109
113
|
def raise_validation_error: (String msg) -> void
|
|
114
|
+
def reject_unknown_config_attributes!: (Hash[untyped, untyped]? data, source: Symbol, ?strict: bool) -> void
|
|
115
|
+
def format_unknown_attribute: (String key, Array[String] known) -> String
|
|
110
116
|
def flatten_hash: (Hash[untyped, untyped], String, Hash[String, String]) -> Hash[String, String]
|
|
111
117
|
|
|
112
118
|
class Error < StandardError
|
|
@@ -114,6 +120,9 @@ module Anyway
|
|
|
114
120
|
|
|
115
121
|
class ValidationError < Error
|
|
116
122
|
end
|
|
123
|
+
|
|
124
|
+
class UnknownAttributesError < ValidationError
|
|
125
|
+
end
|
|
117
126
|
end
|
|
118
127
|
|
|
119
128
|
class Env
|
|
@@ -127,8 +136,10 @@ module Anyway
|
|
|
127
136
|
include Tracing
|
|
128
137
|
|
|
129
138
|
def self.call: (?local: bool, **untyped) -> untyped
|
|
130
|
-
def initialize: (local: bool) -> void
|
|
139
|
+
def initialize: (?local: bool, **untyped) -> void
|
|
140
|
+
def call: (name: String, env_prefix: String, config_path: String | Pathname, **untyped) -> Hash[untyped, untyped]
|
|
131
141
|
def use_local?: -> bool
|
|
142
|
+
def schemaful?: -> bool
|
|
132
143
|
end
|
|
133
144
|
|
|
134
145
|
interface _Loader
|