anyway_config 2.1.0 → 2.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/README.md +162 -4
- data/lib/.rbnext/1995.next/anyway/config.rb +48 -1
- data/lib/.rbnext/1995.next/anyway/dynamic_config.rb +6 -2
- data/lib/.rbnext/1995.next/anyway/tracing.rb +2 -2
- data/lib/.rbnext/2.7/anyway/auto_cast.rb +39 -19
- data/lib/.rbnext/2.7/anyway/config.rb +48 -1
- data/lib/.rbnext/2.7/anyway/rbs.rb +92 -0
- data/lib/.rbnext/2.7/anyway/tracing.rb +5 -7
- data/lib/.rbnext/2.7/anyway/type_casting.rb +130 -0
- data/lib/.rbnext/3.0/anyway/auto_cast.rb +53 -0
- data/lib/.rbnext/3.0/anyway/config.rb +48 -1
- data/lib/.rbnext/3.0/anyway/tracing.rb +5 -7
- data/lib/anyway/auto_cast.rb +39 -19
- data/lib/anyway/config.rb +48 -1
- data/lib/anyway/dynamic_config.rb +6 -2
- data/lib/anyway/ext/deep_dup.rb +6 -0
- data/lib/anyway/ext/hash.rb +10 -0
- data/lib/anyway/loaders/env.rb +3 -1
- data/lib/anyway/loaders/yaml.rb +6 -2
- data/lib/anyway/option_parser_builder.rb +1 -3
- data/lib/anyway/optparse_config.rb +5 -7
- data/lib/anyway/rails/loaders/credentials.rb +2 -2
- data/lib/anyway/rails/loaders/secrets.rb +5 -7
- data/lib/anyway/rails/settings.rb +3 -2
- data/lib/anyway/rbs.rb +92 -0
- data/lib/anyway/tracing.rb +2 -2
- data/lib/anyway/type_casting.rb +121 -0
- data/lib/anyway/version.rb +1 -1
- data/lib/anyway_config.rb +2 -0
- data/sig/anyway_config.rbs +123 -0
- metadata +28 -9
- data/lib/.rbnext/2.7/anyway/option_parser_builder.rb +0 -31
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
using RubyNext;
|
3
|
+
module Anyway
|
4
|
+
# Contains a mapping between type IDs/names and deserializers
|
5
|
+
class TypeRegistry
|
6
|
+
class << self
|
7
|
+
def default
|
8
|
+
@default ||= TypeRegistry.new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@registry = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def accept(name_or_object, &block)
|
17
|
+
if !block && !name_or_object.respond_to?(:call)
|
18
|
+
raise ArgumentError, "Please, provide a type casting block or an object implementing #call(val) method"
|
19
|
+
end
|
20
|
+
|
21
|
+
registry[name_or_object] = block || name_or_object
|
22
|
+
end
|
23
|
+
|
24
|
+
def deserialize(raw, type_id, array: false)
|
25
|
+
caster =
|
26
|
+
if type_id.is_a?(Symbol)
|
27
|
+
registry.fetch(type_id) { raise ArgumentError, "Unknown type: #{type_id}" }
|
28
|
+
else
|
29
|
+
raise ArgumentError, "Type must implement #call(val): #{type_id}" unless type_id.respond_to?(:call)
|
30
|
+
type_id
|
31
|
+
end
|
32
|
+
|
33
|
+
if array
|
34
|
+
raw_arr = raw.is_a?(Array) ? raw : raw.split(/\s*,\s*/)
|
35
|
+
raw_arr.map { |_1| caster.call(_1) }
|
36
|
+
else
|
37
|
+
caster.call(raw)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def dup
|
42
|
+
new_obj = self.class.allocate
|
43
|
+
new_obj.instance_variable_set(:@registry, registry.dup)
|
44
|
+
new_obj
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
attr_reader :registry
|
50
|
+
end
|
51
|
+
|
52
|
+
TypeRegistry.default.tap do |obj|
|
53
|
+
obj.accept(:string, &:to_s)
|
54
|
+
obj.accept(:integer, &:to_i)
|
55
|
+
obj.accept(:float, &:to_f)
|
56
|
+
|
57
|
+
obj.accept(:date) do |_1|
|
58
|
+
require "date" unless defined?(::Date)
|
59
|
+
|
60
|
+
Date.parse(_1)
|
61
|
+
end
|
62
|
+
|
63
|
+
obj.accept(:datetime) do |_1|
|
64
|
+
require "date" unless defined?(::Date)
|
65
|
+
|
66
|
+
DateTime.parse(_1)
|
67
|
+
end
|
68
|
+
|
69
|
+
obj.accept(:uri) do |_1|
|
70
|
+
require "uri" unless defined?(::URI)
|
71
|
+
|
72
|
+
URI.parse(_1)
|
73
|
+
end
|
74
|
+
|
75
|
+
obj.accept(:boolean) do |_1|
|
76
|
+
_1.match?(/\A(true|t|yes|y|1)\z/i)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# TypeCaster is an object responsible for type-casting.
|
81
|
+
# It uses a provided types registry and mapping, and also
|
82
|
+
# accepts a fallback typecaster.
|
83
|
+
class TypeCaster
|
84
|
+
using Ext::DeepDup
|
85
|
+
using Ext::Hash
|
86
|
+
|
87
|
+
def initialize(mapping, registry: TypeRegistry.default, fallback: ::Anyway::AutoCast)
|
88
|
+
@mapping = mapping.deep_dup
|
89
|
+
@registry = registry
|
90
|
+
@fallback = fallback
|
91
|
+
end
|
92
|
+
|
93
|
+
def coerce(key, val, config: mapping)
|
94
|
+
caster_config = config[key.to_sym]
|
95
|
+
|
96
|
+
return fallback.coerce(key, val) unless caster_config
|
97
|
+
|
98
|
+
case; when ((__m__ = caster_config)) && false
|
99
|
+
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?))))
|
100
|
+
registry.deserialize(val, type, array: array)
|
101
|
+
when (Hash === __m__)
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
return val unless val.is_a?(Hash)
|
112
|
+
|
113
|
+
caster_config.each do |k, v|
|
114
|
+
ks = k.to_s
|
115
|
+
next unless val.key?(ks)
|
116
|
+
|
117
|
+
val[ks] = coerce(k, val[ks], config: caster_config)
|
118
|
+
end
|
119
|
+
|
120
|
+
val
|
121
|
+
else
|
122
|
+
registry.deserialize(val, caster_config)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
attr_reader :mapping, :registry, :fallback
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyway
|
4
|
+
module AutoCast
|
5
|
+
# Regexp to detect array values
|
6
|
+
# Array value is a values that contains at least one comma
|
7
|
+
# and doesn't start/end with quote
|
8
|
+
ARRAY_RXP = /\A[^'"].*\s*,\s*.*[^'"]\z/
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def call(val)
|
12
|
+
return val unless val.is_a?(::Hash) || val.is_a?(::String)
|
13
|
+
|
14
|
+
case val
|
15
|
+
when Hash
|
16
|
+
val.transform_values { call(_1) }
|
17
|
+
when ARRAY_RXP
|
18
|
+
val.split(/\s*,\s*/).map { 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)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module NoCast
|
49
|
+
def self.call(val) ; val; end
|
50
|
+
|
51
|
+
def self.coerce(_key, val) ; val; end
|
52
|
+
end
|
53
|
+
end
|
@@ -44,6 +44,7 @@ module Anyway # :nodoc:
|
|
44
44
|
to_h
|
45
45
|
to_source_trace
|
46
46
|
write_config_attr
|
47
|
+
__type_caster__
|
47
48
|
].freeze
|
48
49
|
|
49
50
|
class Error < StandardError; end
|
@@ -196,6 +197,47 @@ module Anyway # :nodoc:
|
|
196
197
|
|
197
198
|
def new_empty_config() ; {}; end
|
198
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
|
+
|
199
241
|
private
|
200
242
|
|
201
243
|
def define_config_accessor(*names)
|
@@ -373,7 +415,7 @@ module Anyway # :nodoc:
|
|
373
415
|
values[name].nil? || (values[name].is_a?(String) && values[name].empty?)
|
374
416
|
end.then do |missing|
|
375
417
|
next if missing.empty?
|
376
|
-
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(", ")}"
|
377
419
|
end
|
378
420
|
end
|
379
421
|
|
@@ -381,11 +423,16 @@ module Anyway # :nodoc:
|
|
381
423
|
key = key.to_sym
|
382
424
|
return unless self.class.config_attributes.include?(key)
|
383
425
|
|
426
|
+
val = __type_caster__.coerce(key, val)
|
384
427
|
public_send(:"#{key}=", val)
|
385
428
|
end
|
386
429
|
|
387
430
|
def raise_validation_error(msg)
|
388
431
|
raise ValidationError, msg
|
389
432
|
end
|
433
|
+
|
434
|
+
def __type_caster__
|
435
|
+
self.class.type_caster
|
436
|
+
end
|
390
437
|
end
|
391
438
|
end
|
@@ -34,13 +34,11 @@ module Anyway
|
|
34
34
|
|
35
35
|
def record_value(val, *path, **opts)
|
36
36
|
key = path.pop
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
Trace.new(:value, val, **opts)
|
43
|
-
end) && (((trace = __m__) || true) || Kernel.raise(NoMatchingPatternError, __m__.inspect))
|
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
|
44
42
|
|
45
43
|
target_trace = path.empty? ? self : value.dig(*path)
|
46
44
|
target_trace.value[key.to_s] = trace
|
data/lib/anyway/auto_cast.rb
CHANGED
@@ -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 { call(_1) }
|
17
|
+
when ARRAY_RXP
|
18
|
+
val.split(/\s*,\s*/).map { 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
|
50
|
+
|
51
|
+
def self.coerce(_key, val) = val
|
52
|
+
end
|
33
53
|
end
|
data/lib/anyway/config.rb
CHANGED
@@ -44,6 +44,7 @@ module Anyway # :nodoc:
|
|
44
44
|
to_h
|
45
45
|
to_source_trace
|
46
46
|
write_config_attr
|
47
|
+
__type_caster__
|
47
48
|
].freeze
|
48
49
|
|
49
50
|
class Error < StandardError; end
|
@@ -196,6 +197,47 @@ module Anyway # :nodoc:
|
|
196
197
|
|
197
198
|
def new_empty_config() = {}
|
198
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
|
+
|
199
241
|
private
|
200
242
|
|
201
243
|
def define_config_accessor(*names)
|
@@ -373,7 +415,7 @@ module Anyway # :nodoc:
|
|
373
415
|
values[name].nil? || (values[name].is_a?(String) && values[name].empty?)
|
374
416
|
end.then do |missing|
|
375
417
|
next if missing.empty?
|
376
|
-
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(", ")}"
|
377
419
|
end
|
378
420
|
end
|
379
421
|
|
@@ -381,11 +423,16 @@ module Anyway # :nodoc:
|
|
381
423
|
key = key.to_sym
|
382
424
|
return unless self.class.config_attributes.include?(key)
|
383
425
|
|
426
|
+
val = __type_caster__.coerce(key, val)
|
384
427
|
public_send(:"#{key}=", val)
|
385
428
|
end
|
386
429
|
|
387
430
|
def raise_validation_error(msg)
|
388
431
|
raise ValidationError, msg
|
389
432
|
end
|
433
|
+
|
434
|
+
def __type_caster__
|
435
|
+
self.class.type_caster
|
436
|
+
end
|
390
437
|
end
|
391
438
|
end
|
@@ -12,11 +12,15 @@ module Anyway
|
|
12
12
|
# my_config = Anyway::Config.for(:my_app)
|
13
13
|
# # will load data from config/my_app.yml, secrets.my_app, ENV["MY_APP_*"]
|
14
14
|
#
|
15
|
-
def for(name, **options)
|
15
|
+
def for(name, auto_cast: true, **options)
|
16
16
|
config = allocate
|
17
17
|
options[:env_prefix] ||= name.to_s.upcase
|
18
18
|
options[:config_path] ||= config.resolve_config_path(name, options[:env_prefix])
|
19
|
-
|
19
|
+
|
20
|
+
raw_config = config.load_from_sources(new_empty_config, name:, **options)
|
21
|
+
return raw_config unless auto_cast
|
22
|
+
|
23
|
+
AutoCast.call(raw_config)
|
20
24
|
end
|
21
25
|
end
|
22
26
|
|
data/lib/anyway/ext/deep_dup.rb
CHANGED
data/lib/anyway/ext/hash.rb
CHANGED
@@ -26,6 +26,16 @@ module Anyway
|
|
26
26
|
end
|
27
27
|
hash[last_key] = val
|
28
28
|
end
|
29
|
+
|
30
|
+
def deep_merge!(other)
|
31
|
+
other.each do |k, v|
|
32
|
+
if key?(k) && self[k].is_a?(::Hash) && v.is_a?(::Hash)
|
33
|
+
self[k].deep_merge!(v)
|
34
|
+
else
|
35
|
+
self[k] = v
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
29
39
|
end
|
30
40
|
|
31
41
|
using self
|
data/lib/anyway/loaders/env.rb
CHANGED
@@ -6,7 +6,9 @@ module Anyway
|
|
6
6
|
module Loaders
|
7
7
|
class Env < Base
|
8
8
|
def call(env_prefix:, **_options)
|
9
|
-
|
9
|
+
env = ::Anyway::Env.new(type_cast: ::Anyway::NoCast)
|
10
|
+
|
11
|
+
env.fetch_with_trace(env_prefix).then do |(conf, trace)|
|
10
12
|
Tracing.current_trace&.merge!(trace)
|
11
13
|
conf
|
12
14
|
end
|
data/lib/anyway/loaders/yaml.rb
CHANGED
@@ -25,10 +25,14 @@ module Anyway
|
|
25
25
|
def parse_yml(path)
|
26
26
|
return {} unless File.file?(path)
|
27
27
|
require "yaml" unless defined?(::YAML)
|
28
|
+
|
29
|
+
# By default, YAML load will return `false` when the yaml document is
|
30
|
+
# empty. When this occurs, we return an empty hash instead, to match
|
31
|
+
# the interface when no config file is present.
|
28
32
|
if defined?(ERB)
|
29
|
-
::YAML.load(ERB.new(File.read(path)).result) # rubocop:disable Security/YAMLLoad
|
33
|
+
::YAML.load(ERB.new(File.read(path)).result) || {} # rubocop:disable Security/YAMLLoad
|
30
34
|
else
|
31
|
-
::YAML.load_file(path)
|
35
|
+
::YAML.load_file(path) || {}
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
@@ -8,8 +8,6 @@ module Anyway # :nodoc:
|
|
8
8
|
class << self
|
9
9
|
def call(options)
|
10
10
|
OptionParser.new do |opts|
|
11
|
-
opts.accept(AutoCast) { AutoCast.call(_1) }
|
12
|
-
|
13
11
|
options.each do |key, descriptor|
|
14
12
|
opts.on(*option_parser_on_args(key, **descriptor)) do |val|
|
15
13
|
yield [key, val]
|
@@ -20,7 +18,7 @@ module Anyway # :nodoc:
|
|
20
18
|
|
21
19
|
private
|
22
20
|
|
23
|
-
def option_parser_on_args(key, flag: false, desc: nil, type:
|
21
|
+
def option_parser_on_args(key, flag: false, desc: nil, type: ::String)
|
24
22
|
on_args = ["--#{key.to_s.tr("_", "-")}#{flag ? "" : " VALUE"}"]
|
25
23
|
on_args << type unless flag
|
26
24
|
on_args << desc unless desc.nil?
|
@@ -70,13 +70,11 @@ module Anyway
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def option_parser
|
73
|
-
@option_parser ||=
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
extension.call(parser, self)
|
79
|
-
end
|
73
|
+
@option_parser ||= OptionParserBuilder.call(self.class.option_parser_options) do |key, val|
|
74
|
+
write_config_attr(key, val)
|
75
|
+
end.tap do |parser|
|
76
|
+
self.class.option_parser_extensions.map do |extension|
|
77
|
+
extension.call(parser, self)
|
80
78
|
end
|
81
79
|
end
|
82
80
|
end
|
@@ -22,7 +22,7 @@ module Anyway
|
|
22
22
|
:credentials,
|
23
23
|
store: credentials_path
|
24
24
|
) do
|
25
|
-
::Rails.application.credentials.
|
25
|
+
::Rails.application.credentials.config[name.to_sym]
|
26
26
|
end.then do |creds|
|
27
27
|
Utils.deep_merge!(config, creds) if creds
|
28
28
|
end
|
@@ -48,7 +48,7 @@ module Anyway
|
|
48
48
|
key_path: ::Rails.root.join("config/credentials/local.key")
|
49
49
|
)
|
50
50
|
|
51
|
-
creds.
|
51
|
+
creds.config[name.to_sym]
|
52
52
|
end
|
53
53
|
|
54
54
|
def credentials_path
|
@@ -24,13 +24,11 @@ module Anyway
|
|
24
24
|
private
|
25
25
|
|
26
26
|
def secrets
|
27
|
-
@secrets ||=
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
::Rails.application.remove_instance_variable(:@secrets)
|
33
|
-
end
|
27
|
+
@secrets ||= ::Rails.application.secrets.tap do |_|
|
28
|
+
# Reset secrets state if the app hasn't been initialized
|
29
|
+
# See https://github.com/palkan/anyway_config/issues/14
|
30
|
+
next if ::Rails.application.initialized?
|
31
|
+
::Rails.application.remove_instance_variable(:@secrets)
|
34
32
|
end
|
35
33
|
end
|
36
34
|
end
|
@@ -27,10 +27,11 @@ module Anyway
|
|
27
27
|
|
28
28
|
@autoload_static_config_path = val
|
29
29
|
|
30
|
-
# See https://github.com/rails/rails/blob/8ab4fd12f18203b83d0f252db96d10731485ff6a/railties/lib/rails/autoloaders.rb#L10
|
30
|
+
# See Rails 6 https://github.com/rails/rails/blob/8ab4fd12f18203b83d0f252db96d10731485ff6a/railties/lib/rails/autoloaders.rb#L10
|
31
|
+
# and Rails 7 https://github.com/rails/rails/blob/5462fbd5de1900c1b1ce1c9dc11c1a2d8cdcd809/railties/lib/rails/autoloaders.rb#L15
|
31
32
|
@autoloader = Zeitwerk::Loader.new.tap do |loader|
|
32
33
|
loader.tag = "anyway.config"
|
33
|
-
loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
|
34
|
+
loader.inflector = defined?(ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector) ? ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector : ::Rails::Autoloaders::Inflector
|
34
35
|
loader.push_dir(::Rails.root.join(val))
|
35
36
|
loader.setup
|
36
37
|
end
|