runger_config 4.0.0 → 5.0.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 +4 -0
- data/lib/generators/runger/app_config/app_config_generator.rb +6 -10
- data/lib/generators/runger/config/config_generator.rb +44 -41
- data/lib/generators/runger/install/install_generator.rb +35 -37
- data/lib/runger/auto_cast.rb +3 -3
- data/lib/runger/config.rb +114 -94
- data/lib/runger/dynamic_config.rb +21 -23
- data/lib/runger/ejson_parser.rb +24 -24
- data/lib/runger/env.rb +50 -52
- data/lib/runger/ext/deep_dup.rb +33 -36
- data/lib/runger/ext/deep_freeze.rb +28 -32
- data/lib/runger/ext/flatten_names.rb +23 -27
- data/lib/runger/ext/hash.rb +26 -29
- data/lib/runger/ext/string_constantize.rb +12 -15
- data/lib/runger/loaders/base.rb +11 -15
- data/lib/runger/loaders/doppler.rb +38 -42
- data/lib/runger/loaders/ejson.rb +65 -63
- data/lib/runger/loaders/env.rb +6 -10
- data/lib/runger/loaders/yaml.rb +69 -66
- data/lib/runger/loaders.rb +69 -71
- data/lib/runger/option_parser_builder.rb +16 -18
- data/lib/runger/optparse_config.rb +11 -10
- data/lib/runger/rails/autoload.rb +24 -26
- data/lib/runger/rails/config.rb +13 -17
- data/lib/runger/rails/loaders/credentials.rb +53 -57
- data/lib/runger/rails/loaders/secrets.rb +21 -25
- data/lib/runger/rails/loaders/yaml.rb +1 -6
- data/lib/runger/rails/loaders.rb +3 -3
- data/lib/runger/rails/settings.rb +49 -49
- data/lib/runger/rails.rb +9 -11
- data/lib/runger/railtie.rb +3 -2
- data/lib/runger/rbs.rb +29 -29
- data/lib/runger/settings.rb +82 -84
- data/lib/runger/testing/helpers.rb +26 -28
- data/lib/runger/testing.rb +2 -2
- data/lib/runger/tracing.rb +143 -136
- data/lib/runger/type_casting.rb +16 -11
- data/lib/runger/utils/which.rb +10 -12
- data/lib/runger/version.rb +1 -1
- data/lib/runger.rb +1 -1
- data/lib/runger_config.rb +34 -27
- metadata +18 -18
data/lib/runger/settings.rb
CHANGED
@@ -1,111 +1,109 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
class
|
13
|
-
|
14
|
-
|
15
|
-
settings[name] = default_value
|
16
|
-
|
17
|
-
define_method(name) do
|
18
|
-
store[name]
|
19
|
-
end
|
20
|
-
|
21
|
-
define_method(:"#{name}=") do |val|
|
22
|
-
store[name] = val
|
23
|
-
end
|
24
|
-
end
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
# Use Settings name to not confuse with Config.
|
6
|
+
#
|
7
|
+
# Settings contain the library-wide configuration.
|
8
|
+
class Runger::Settings
|
9
|
+
# Future encapsulates settings that will be introduced in the upcoming version
|
10
|
+
# with the default values, which could break compatibility
|
11
|
+
class Future
|
12
|
+
class << self
|
13
|
+
def setting(name, default_value)
|
14
|
+
settings[name] = default_value
|
25
15
|
|
26
|
-
|
27
|
-
|
16
|
+
define_method(name) do
|
17
|
+
store[name]
|
28
18
|
end
|
29
|
-
end
|
30
19
|
|
31
|
-
|
32
|
-
|
20
|
+
define_method(:"#{name}=") do |val|
|
21
|
+
store[name] = val
|
22
|
+
end
|
33
23
|
end
|
34
24
|
|
35
|
-
def
|
36
|
-
|
37
|
-
names.each { store[_1] = self.class.settings[_1] }
|
25
|
+
def settings
|
26
|
+
@settings ||= {}
|
38
27
|
end
|
28
|
+
end
|
39
29
|
|
40
|
-
|
41
|
-
|
42
|
-
|
30
|
+
def initialize
|
31
|
+
@store = {}
|
32
|
+
end
|
43
33
|
|
44
|
-
|
34
|
+
def use(*names)
|
35
|
+
store.clear
|
36
|
+
names.each { store[_1] = self.class.settings[_1] }
|
45
37
|
end
|
46
38
|
|
47
|
-
|
48
|
-
# Define whether to load data from
|
49
|
-
# *.yml.local (or credentials/local.yml.enc)
|
50
|
-
attr_accessor :use_local_files,
|
51
|
-
:current_environment,
|
52
|
-
:default_environmental_key,
|
53
|
-
:known_environments
|
54
|
-
|
55
|
-
# A proc returning a path to YML config file given the config name
|
56
|
-
attr_reader :default_config_path
|
57
|
-
|
58
|
-
def default_config_path=(val)
|
59
|
-
if val.is_a?(Proc)
|
60
|
-
@default_config_path = val
|
61
|
-
return
|
62
|
-
end
|
39
|
+
setting :unwrap_known_environments, true
|
63
40
|
|
64
|
-
|
41
|
+
private
|
65
42
|
|
66
|
-
|
43
|
+
attr_reader :store
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
# Define whether to load data from
|
48
|
+
# *.yml.local (or credentials/local.yml.enc)
|
49
|
+
attr_accessor :use_local_files,
|
50
|
+
:current_environment,
|
51
|
+
:default_environmental_key,
|
52
|
+
:known_environments
|
53
|
+
|
54
|
+
# A proc returning a path to YML config file given the config name
|
55
|
+
attr_reader :default_config_path
|
56
|
+
|
57
|
+
def default_config_path=(val)
|
58
|
+
if val.is_a?(Proc)
|
59
|
+
@default_config_path = val
|
60
|
+
return
|
67
61
|
end
|
68
62
|
|
69
|
-
|
70
|
-
attr_accessor :tracing_enabled
|
63
|
+
val = val.to_s
|
71
64
|
|
72
|
-
|
73
|
-
|
74
|
-
end
|
65
|
+
@default_config_path = ->(name) { File.join(val, "#{name}.yml") }
|
66
|
+
end
|
75
67
|
|
76
|
-
|
77
|
-
|
78
|
-
end
|
68
|
+
# Enable source tracing
|
69
|
+
attr_accessor :tracing_enabled
|
79
70
|
|
80
|
-
|
81
|
-
|
82
|
-
|
71
|
+
def future
|
72
|
+
@future ||= Future.new
|
73
|
+
end
|
83
74
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
75
|
+
def app_root
|
76
|
+
Pathname.new(Dir.pwd)
|
77
|
+
end
|
78
|
+
|
79
|
+
def default_environmental_key?
|
80
|
+
!default_environmental_key.nil?
|
81
|
+
end
|
82
|
+
|
83
|
+
def matching_env?(env)
|
84
|
+
return true if env.nil? || env.to_s == current_environment
|
85
|
+
|
86
|
+
if env.is_a?(::Hash)
|
87
|
+
envs = env[:except]
|
88
|
+
excluded_envs = [envs].flat_map(&:to_s)
|
89
|
+
excluded_envs.none?(current_environment)
|
90
|
+
elsif env.is_a?(::Array)
|
91
|
+
env.flat_map(&:to_s).include?(current_environment)
|
92
|
+
else
|
93
|
+
false
|
96
94
|
end
|
97
95
|
end
|
96
|
+
end
|
98
97
|
|
99
|
-
|
100
|
-
|
98
|
+
# By default, use RUNGER_ENV
|
99
|
+
self.current_environment = ENV.fetch('RUNGER_ENV', nil)
|
101
100
|
|
102
|
-
|
103
|
-
|
101
|
+
# By default, use local files only in development (that's the purpose if the local files)
|
102
|
+
self.use_local_files = (ENV['RUNGER_ENV'] == 'development' || ENV['RACK_ENV'] == 'development' || ENV['RAILS_ENV'] == 'development' || (defined?(Rails) && Rails.env.development?))
|
104
103
|
|
105
|
-
|
106
|
-
|
104
|
+
# By default, consider configs are stored in the ./config folder
|
105
|
+
self.default_config_path = ->(name) { "./config/#{name}.yml" }
|
107
106
|
|
108
|
-
|
109
|
-
|
110
|
-
end
|
107
|
+
# Tracing is enabled by default
|
108
|
+
self.tracing_enabled = true
|
111
109
|
end
|
@@ -1,36 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Runger
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def with_env(data)
|
14
|
-
was_values = []
|
3
|
+
module Runger::Testing::Helpers
|
4
|
+
# Sets the ENV variables to the provided
|
5
|
+
# values and restore outside the block
|
6
|
+
#
|
7
|
+
# Also resets Runger.env before and after calling the block
|
8
|
+
# to make sure that the values are not cached.
|
9
|
+
#
|
10
|
+
# NOTE: to remove the env value, pass `nil` as the value
|
11
|
+
def with_env(data)
|
12
|
+
was_values = []
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
ENV[key] = val
|
20
|
-
end
|
14
|
+
data.each do |key, val|
|
15
|
+
was_values << [key, ENV.fetch(key, nil)]
|
16
|
+
next ENV.delete(key) if val.nil?
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
18
|
+
ENV[key] = val
|
19
|
+
end
|
20
|
+
|
21
|
+
# clear cached env values
|
22
|
+
Runger.env.clear
|
23
|
+
yield
|
24
|
+
ensure
|
25
|
+
was_values.each do |(key, val)|
|
26
|
+
next ENV.delete(key) if val.nil?
|
30
27
|
|
31
|
-
|
32
|
-
Runger.env.clear
|
33
|
-
end
|
28
|
+
ENV[key] = val
|
34
29
|
end
|
30
|
+
|
31
|
+
# clear cache again
|
32
|
+
Runger.env.clear
|
35
33
|
end
|
36
34
|
end
|
data/lib/runger/testing.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'runger/testing/helpers'
|
4
4
|
|
5
5
|
if defined?(RSpec::Core) && RSpec.respond_to?(:configure)
|
6
6
|
RSpec.configure do |config|
|
7
7
|
config.include(
|
8
8
|
Runger::Testing::Helpers,
|
9
9
|
type: :config,
|
10
|
-
file_path: %r{spec/configs}
|
10
|
+
file_path: %r{spec/configs},
|
11
11
|
)
|
12
12
|
end
|
13
13
|
end
|
data/lib/runger/tracing.rb
CHANGED
@@ -1,188 +1,195 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
using Runger::Ext::DeepDup
|
7
|
-
|
8
|
-
using(Module.new do
|
9
|
-
refine Thread::Backtrace::Location do
|
10
|
-
def path_lineno = "#{path}:#{lineno}"
|
11
|
-
end
|
12
|
-
end)
|
3
|
+
# Provides method to trace values association
|
4
|
+
module Runger::Tracing
|
5
|
+
using Runger::Ext::DeepDup
|
13
6
|
|
14
|
-
|
15
|
-
|
7
|
+
using(Module.new do
|
8
|
+
refine Thread::Backtrace::Location do
|
9
|
+
def path_lineno = "#{path}:#{lineno}"
|
10
|
+
end
|
11
|
+
end)
|
16
12
|
|
17
|
-
|
13
|
+
class Trace
|
14
|
+
UNDEF = Object.new
|
18
15
|
|
19
|
-
|
20
|
-
@type = type
|
21
|
-
@source = source
|
22
|
-
@value = (value == UNDEF) ? Hash.new { |h, k| h[k] = Trace.new(:trace) } : value
|
23
|
-
end
|
16
|
+
attr_reader :type, :value, :source
|
24
17
|
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
def initialize(type = :trace, value = UNDEF, **source)
|
19
|
+
@type = type
|
20
|
+
@source = source
|
21
|
+
@value = (value == UNDEF) ? Hash.new { |h, k| h[k] = Trace.new(:trace) } : value
|
22
|
+
end
|
23
|
+
|
24
|
+
def dig(...)
|
25
|
+
value.dig(...)
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
def record_value(val, *path, **options)
|
29
|
+
key = path.pop
|
30
|
+
trace =
|
31
|
+
if val.is_a?(Hash)
|
32
|
+
Trace.new.tap { _1.merge_values(val, **options) }
|
33
33
|
else
|
34
|
-
Trace.new(:value, val, **)
|
34
|
+
Trace.new(:value, val, **options)
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
37
|
+
target_trace = path.empty? ? self : value.dig(*path)
|
38
|
+
target_trace.record_key(key.to_s, trace)
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
val
|
41
|
+
end
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
def merge_values(hash, **options)
|
44
|
+
return hash unless hash
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
46
|
+
hash.each do |key, val|
|
47
|
+
if val.is_a?(Hash)
|
48
|
+
value[key.to_s].merge_values(val, **options)
|
49
|
+
else
|
50
|
+
value[key.to_s] = Trace.new(:value, val, **options)
|
52
51
|
end
|
53
|
-
|
54
|
-
hash
|
55
52
|
end
|
56
53
|
|
57
|
-
|
58
|
-
|
54
|
+
hash
|
55
|
+
end
|
59
56
|
|
60
|
-
|
61
|
-
|
57
|
+
def record_key(key, key_trace)
|
58
|
+
@value = Hash.new { |h, k| h[k] = Trace.new(:trace) } unless value.is_a?(::Hash)
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
raise ArgumentError, "You can only merge a :trace type, but trying :#{type}" unless another_trace.trace?
|
60
|
+
value[key] = key_trace
|
61
|
+
end
|
66
62
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
63
|
+
def merge!(another_trace)
|
64
|
+
unless trace?
|
65
|
+
raise(ArgumentError,
|
66
|
+
"You can only merge into a :trace type, and this is :#{type}")
|
67
|
+
end
|
68
|
+
unless another_trace.trace?
|
69
|
+
raise(ArgumentError,
|
70
|
+
"You can only merge a :trace type, but trying :#{type}")
|
74
71
|
end
|
75
72
|
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
another_trace.value.each do |key, sub_trace|
|
74
|
+
if sub_trace.trace?
|
75
|
+
value[key].merge!(sub_trace)
|
76
|
+
else
|
77
|
+
value[key] = sub_trace
|
78
|
+
end
|
79
79
|
end
|
80
|
+
end
|
80
81
|
|
81
|
-
|
82
|
+
def keep_if(...)
|
83
|
+
raise(ArgumentError, "You can only filter :trace type, and this is :#{type}") unless trace?
|
82
84
|
|
83
|
-
|
85
|
+
value.keep_if(...)
|
86
|
+
end
|
84
87
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
def clear = value.clear
|
89
|
+
|
90
|
+
def trace? = type == :trace
|
91
|
+
|
92
|
+
def to_h
|
93
|
+
if trace?
|
94
|
+
value.transform_values(&:to_h).tap { _1.default_proc = nil }
|
95
|
+
else
|
96
|
+
{ value:, source: }
|
91
97
|
end
|
98
|
+
end
|
92
99
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
100
|
+
def dup = self.class.new(type, value.dup, **source)
|
101
|
+
|
102
|
+
def pretty_print(q)
|
103
|
+
if trace?
|
104
|
+
q.nest(2) do
|
105
|
+
q.breakable('')
|
106
|
+
q.seplist(value, nil, :each) do |k, v|
|
107
|
+
q.group do
|
108
|
+
q.text k
|
109
|
+
q.text ' =>'
|
110
|
+
if v.trace?
|
111
|
+
q.text ' { '
|
112
|
+
q.pp(v)
|
113
|
+
q.breakable(' ')
|
114
|
+
q.text '}'
|
115
|
+
else
|
116
|
+
q.breakable(' ')
|
117
|
+
q.pp(v)
|
112
118
|
end
|
113
119
|
end
|
114
120
|
end
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
121
|
+
end
|
122
|
+
else
|
123
|
+
q.pp(value)
|
124
|
+
q.group(0, ' (', ')') do
|
125
|
+
q.seplist(source, lambda { q.breakable(' ') }, :each) do |k, v|
|
126
|
+
q.group do
|
127
|
+
q.text k.to_s
|
128
|
+
q.text '='
|
129
|
+
q.text v.to_s
|
124
130
|
end
|
125
131
|
end
|
126
132
|
end
|
127
133
|
end
|
128
134
|
end
|
135
|
+
end
|
129
136
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
yield
|
134
|
-
return
|
135
|
-
end
|
136
|
-
|
137
|
-
trace = Trace.new
|
138
|
-
trace_stack.push trace
|
137
|
+
class << self
|
138
|
+
def capture
|
139
|
+
unless ::Runger::Settings.tracing_enabled
|
139
140
|
yield
|
140
|
-
|
141
|
-
ensure
|
142
|
-
trace_stack.pop
|
141
|
+
return
|
143
142
|
end
|
144
143
|
|
145
|
-
|
146
|
-
|
147
|
-
|
144
|
+
trace = Trace.new
|
145
|
+
trace_stack.push(trace)
|
146
|
+
yield
|
147
|
+
trace_stack.last
|
148
|
+
ensure
|
149
|
+
trace_stack.pop
|
150
|
+
end
|
148
151
|
|
149
|
-
|
152
|
+
def trace_stack
|
153
|
+
(Thread.current[:__runger__trace_stack__] ||= [])
|
154
|
+
end
|
150
155
|
|
151
|
-
|
156
|
+
def current_trace = trace_stack.last
|
152
157
|
|
153
|
-
|
154
|
-
(Thread.current[:__runger__trace_source_stack__] ||= [])
|
155
|
-
end
|
158
|
+
alias tracing? current_trace
|
156
159
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
+
def source_stack
|
161
|
+
(Thread.current[:__runger__trace_source_stack__] ||= [])
|
162
|
+
end
|
160
163
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
164
|
+
def current_trace_source
|
165
|
+
source_stack.last || accessor_source(caller_locations(2, 1).first)
|
166
|
+
end
|
167
|
+
|
168
|
+
def with_trace_source(src)
|
169
|
+
source_stack << src
|
170
|
+
yield
|
171
|
+
ensure
|
172
|
+
source_stack.pop
|
173
|
+
end
|
167
174
|
|
168
|
-
|
175
|
+
private
|
169
176
|
|
170
|
-
|
171
|
-
|
172
|
-
end
|
177
|
+
def accessor_source(location)
|
178
|
+
{ type: :accessor, called_from: location.path_lineno }
|
173
179
|
end
|
180
|
+
end
|
174
181
|
|
175
|
-
|
182
|
+
module_function
|
176
183
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
val
|
184
|
+
def trace!(type, *path, **options)
|
185
|
+
return yield unless ::Runger::Tracing.tracing?
|
186
|
+
|
187
|
+
val = yield
|
188
|
+
if val.is_a?(Hash)
|
189
|
+
::Runger::Tracing.current_trace.merge_values(val, type:, **options)
|
190
|
+
elsif !path.empty?
|
191
|
+
::Runger::Tracing.current_trace.record_value(val, *path, type:, **options)
|
186
192
|
end
|
193
|
+
val
|
187
194
|
end
|
188
195
|
end
|