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
@@ -1,31 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
module
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
options[:config_path] ||= config.resolve_config_path(name, options[:env_prefix])
|
3
|
+
# Adds ability to generate anonymous (class-less) config dynamicly
|
4
|
+
# (like Rails.application.config_for but using more data sources).
|
5
|
+
module Runger::DynamicConfig
|
6
|
+
module ClassMethods
|
7
|
+
# Load config as Hash by any name
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
#
|
11
|
+
# my_config = Runger::Config.for(:my_app)
|
12
|
+
# # will load data from config/my_app.yml, secrets.my_app, ENV["MY_APP_*"]
|
13
|
+
#
|
14
|
+
def for(name, auto_cast: true, **options)
|
15
|
+
config = allocate
|
16
|
+
options[:env_prefix] ||= name.to_s.upcase
|
17
|
+
options[:config_path] ||= config.resolve_config_path(name, options[:env_prefix])
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
raw_config = config.load_from_sources(new_empty_config, name:, **options)
|
20
|
+
return raw_config unless auto_cast
|
22
21
|
|
23
|
-
|
24
|
-
end
|
22
|
+
::Runger::AutoCast.call(raw_config)
|
25
23
|
end
|
24
|
+
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
26
|
+
def self.included(base)
|
27
|
+
base.extend(ClassMethods)
|
30
28
|
end
|
31
29
|
end
|
data/lib/runger/ejson_parser.rb
CHANGED
@@ -1,39 +1,39 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'open3'
|
4
|
+
require 'runger/ext/hash'
|
5
5
|
|
6
6
|
using Runger::Ext::Hash
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
attr_reader :bin_path
|
8
|
+
class Runger::EJSONParser
|
9
|
+
attr_reader :bin_path
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
def initialize(bin_path = 'ejson')
|
12
|
+
@bin_path = bin_path
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
15
|
+
def call(file_path)
|
16
|
+
return unless File.exist?(file_path)
|
18
17
|
|
19
|
-
|
18
|
+
raw_content = nil
|
20
19
|
|
21
|
-
|
20
|
+
stdout, stderr, status = Open3.capture3("#{bin_path} decrypt #{file_path}")
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
if status.success?
|
23
|
+
raw_content = JSON.parse(stdout.chomp)
|
24
|
+
else
|
25
|
+
Kernel.warn("Failed to decrypt #{file_path}: #{stderr}")
|
26
|
+
end
|
28
27
|
|
29
|
-
|
28
|
+
return unless raw_content
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
raw_content.deep_transform_keys do |key|
|
31
|
+
if key[0] == '_'
|
32
|
+
# rubocop:disable Performance/ArraySemiInfiniteRangeSlice
|
33
|
+
key[1..]
|
34
|
+
# rubocop:enable Performance/ArraySemiInfiniteRangeSlice
|
35
|
+
else
|
36
|
+
key
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/lib/runger/env.rb
CHANGED
@@ -1,72 +1,70 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
memo[prefix_with_key] = value.to_s
|
19
|
-
end
|
3
|
+
# Parses environment variables and provides
|
4
|
+
# method-like access
|
5
|
+
class Runger::Env
|
6
|
+
using Runger::Ext::DeepDup
|
7
|
+
using Runger::Ext::Hash
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def from_hash(hash, prefix: nil, memo: {})
|
11
|
+
hash.each do |key, value|
|
12
|
+
prefix_with_key = (prefix && !prefix.empty?) ? "#{prefix}_#{key.to_s.upcase}" : key.to_s.upcase
|
13
|
+
|
14
|
+
if value.is_a?(Hash)
|
15
|
+
from_hash(value, prefix: "#{prefix_with_key}_", memo:)
|
16
|
+
else
|
17
|
+
memo[prefix_with_key] = value.to_s
|
20
18
|
end
|
21
|
-
|
22
|
-
memo
|
23
19
|
end
|
20
|
+
|
21
|
+
memo
|
24
22
|
end
|
23
|
+
end
|
25
24
|
|
26
|
-
|
25
|
+
include ::Runger::Tracing
|
27
26
|
|
28
|
-
|
27
|
+
attr_reader :data, :traces, :type_cast, :env_container
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
def clear
|
38
|
-
data.clear
|
39
|
-
traces.clear
|
40
|
-
end
|
29
|
+
def initialize(type_cast: ::Runger::AutoCast, env_container: ENV)
|
30
|
+
@type_cast = type_cast
|
31
|
+
@data = {}
|
32
|
+
@traces = {}
|
33
|
+
@env_container = env_container
|
34
|
+
end
|
41
35
|
|
42
|
-
|
43
|
-
|
36
|
+
def clear
|
37
|
+
data.clear
|
38
|
+
traces.clear
|
39
|
+
end
|
44
40
|
|
45
|
-
|
46
|
-
|
47
|
-
end.then do |trace|
|
48
|
-
traces[prefix] = trace
|
49
|
-
end
|
41
|
+
def fetch(prefix)
|
42
|
+
return data[prefix].deep_dup if data.key?(prefix)
|
50
43
|
|
51
|
-
|
44
|
+
::Runger::Tracing.capture do
|
45
|
+
data[prefix] = parse_env(prefix)
|
46
|
+
end.then do |trace|
|
47
|
+
traces[prefix] = trace
|
52
48
|
end
|
53
49
|
|
54
|
-
|
55
|
-
|
56
|
-
end
|
50
|
+
data[prefix].deep_dup
|
51
|
+
end
|
57
52
|
|
58
|
-
|
53
|
+
def fetch_with_trace(prefix)
|
54
|
+
[fetch(prefix), traces[prefix]]
|
55
|
+
end
|
59
56
|
|
60
|
-
|
61
|
-
match_prefix = prefix.empty? ? prefix : "#{prefix}_"
|
62
|
-
env_container.each_pair.with_object({}) do |(key, val), data|
|
63
|
-
next unless key.start_with?(match_prefix)
|
57
|
+
private
|
64
58
|
|
65
|
-
|
59
|
+
def parse_env(prefix)
|
60
|
+
match_prefix = prefix.empty? ? prefix : "#{prefix}_"
|
61
|
+
env_container.each_pair.with_object({}) do |(key, val), data|
|
62
|
+
next unless key.start_with?(match_prefix)
|
66
63
|
|
67
|
-
|
68
|
-
|
69
|
-
|
64
|
+
path = key.sub(/^#{match_prefix}/, '').downcase
|
65
|
+
|
66
|
+
paths = path.split('__')
|
67
|
+
trace!(:env, *paths, key:) { data.bury(type_cast.call(val), *paths) }
|
70
68
|
end
|
71
69
|
end
|
72
70
|
end
|
data/lib/runger/ext/deep_dup.rb
CHANGED
@@ -1,48 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
value
|
15
|
-
end
|
3
|
+
# Extend Object through refinements
|
4
|
+
module Runger::Ext::DeepDup
|
5
|
+
refine ::Hash do
|
6
|
+
# Based on ActiveSupport http://api.rubyonrails.org/classes/Hash.html#method-i-deep_dup
|
7
|
+
def deep_dup
|
8
|
+
each_with_object(dup) do |(key, value), hash|
|
9
|
+
hash[key] =
|
10
|
+
if value.is_a?(::Hash) || value.is_a?(::Array)
|
11
|
+
value.deep_dup
|
12
|
+
else
|
13
|
+
value
|
16
14
|
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
refine ::Array do
|
21
|
-
# From ActiveSupport http://api.rubyonrails.org/classes/Array.html#method-i-deep_dup
|
22
|
-
def deep_dup
|
23
|
-
map do |value|
|
24
|
-
if value.is_a?(::Hash) || value.is_a?(::Array)
|
25
|
-
value.deep_dup
|
26
|
-
else
|
27
|
-
value
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
15
|
end
|
16
|
+
end
|
17
|
+
end
|
32
18
|
|
33
|
-
|
34
|
-
|
35
|
-
|
19
|
+
refine ::Array do
|
20
|
+
# From ActiveSupport http://api.rubyonrails.org/classes/Array.html#method-i-deep_dup
|
21
|
+
def deep_dup
|
22
|
+
map do |value|
|
23
|
+
if value.is_a?(::Hash) || value.is_a?(::Array)
|
24
|
+
value.deep_dup
|
25
|
+
else
|
26
|
+
value
|
36
27
|
end
|
37
28
|
end
|
29
|
+
end
|
30
|
+
end
|
38
31
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
32
|
+
refine ::Object do
|
33
|
+
def deep_dup
|
34
|
+
dup
|
35
|
+
end
|
36
|
+
end
|
44
37
|
|
45
|
-
|
38
|
+
refine ::Module do
|
39
|
+
def deep_dup
|
40
|
+
self
|
46
41
|
end
|
47
42
|
end
|
43
|
+
|
44
|
+
using self
|
48
45
|
end
|
@@ -1,44 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
each_value do |value|
|
11
|
-
value.deep_freeze if value.is_a?(::Hash) || value.is_a?(::Array)
|
12
|
-
end
|
13
|
-
end
|
3
|
+
# Add #deep_freeze to hashes and arrays
|
4
|
+
module Runger::Ext::DeepFreeze
|
5
|
+
refine ::Hash do
|
6
|
+
def deep_freeze
|
7
|
+
freeze
|
8
|
+
each_value do |value|
|
9
|
+
value.deep_freeze if value.is_a?(::Hash) || value.is_a?(::Array)
|
14
10
|
end
|
11
|
+
end
|
12
|
+
end
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
14
|
+
refine ::Array do
|
15
|
+
def deep_freeze
|
16
|
+
freeze
|
17
|
+
each do |value|
|
18
|
+
value.deep_freeze if value.is_a?(::Hash) || value.is_a?(::Array)
|
23
19
|
end
|
20
|
+
end
|
21
|
+
end
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
begin
|
24
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
25
|
+
rescue LoadError
|
26
|
+
end
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
end
|
28
|
+
if defined?(::ActiveSupport::HashWithIndifferentAccess)
|
29
|
+
refine ::ActiveSupport::HashWithIndifferentAccess do
|
30
|
+
def deep_freeze
|
31
|
+
freeze
|
32
|
+
each_value do |value|
|
33
|
+
value.deep_freeze if value.is_a?(::Hash) || value.is_a?(::Array)
|
38
34
|
end
|
39
35
|
end
|
40
|
-
|
41
|
-
using self
|
42
36
|
end
|
43
37
|
end
|
38
|
+
|
39
|
+
using self
|
44
40
|
end
|
@@ -1,37 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
buf << :"#{prefix}"
|
12
|
-
return buf
|
13
|
-
end
|
14
|
-
|
15
|
-
each_with_object(buf) do |name, acc|
|
16
|
-
if name.is_a?(::Symbol)
|
17
|
-
acc << :"#{prefix}.#{name}"
|
18
|
-
else
|
19
|
-
name.flatten_names(prefix, acc)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
3
|
+
# Convert Hash with mixed array and hash values to an
|
4
|
+
# array of paths.
|
5
|
+
module Runger::Ext::FlattenNames
|
6
|
+
refine ::Array do
|
7
|
+
def flatten_names(prefix, buf)
|
8
|
+
if empty?
|
9
|
+
buf << :"#{prefix}"
|
10
|
+
return buf
|
23
11
|
end
|
24
12
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
13
|
+
each_with_object(buf) do |name, acc|
|
14
|
+
if name.is_a?(::Symbol)
|
15
|
+
acc << :"#{prefix}.#{name}"
|
16
|
+
else
|
17
|
+
name.flatten_names(prefix, acc)
|
31
18
|
end
|
32
19
|
end
|
20
|
+
end
|
21
|
+
end
|
33
22
|
|
34
|
-
|
23
|
+
refine ::Hash do
|
24
|
+
def flatten_names(prefix = nil, buf = [])
|
25
|
+
each_with_object(buf) do |(k, v), acc|
|
26
|
+
parent = prefix ? "#{prefix}.#{k}" : k
|
27
|
+
v.flatten_names(parent, acc)
|
28
|
+
end
|
35
29
|
end
|
36
30
|
end
|
31
|
+
|
32
|
+
using self
|
37
33
|
end
|
data/lib/runger/ext/hash.rb
CHANGED
@@ -1,40 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
self[key.to_s] = value
|
12
|
-
end
|
13
|
-
|
14
|
-
self
|
15
|
-
end
|
3
|
+
# Extend Hash through refinements
|
4
|
+
module Runger::Ext::Hash
|
5
|
+
refine ::Hash do
|
6
|
+
def stringify_keys!
|
7
|
+
keys.each do |key|
|
8
|
+
value = delete(key)
|
9
|
+
self[key.to_s] = value
|
10
|
+
end
|
16
11
|
|
17
|
-
|
18
|
-
|
19
|
-
raise ArgumentError, "Path cannot contain nil" if path.compact.size != path.size
|
12
|
+
self
|
13
|
+
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
hash[k]
|
25
|
-
end
|
15
|
+
def bury(val, *path)
|
16
|
+
raise(ArgumentError, 'No path specified') if path.empty?
|
17
|
+
raise(ArgumentError, 'Path cannot contain nil') if path.compact.size != path.size
|
26
18
|
|
27
|
-
|
19
|
+
last_key = path.pop
|
20
|
+
hash =
|
21
|
+
path.reduce(self) do |hash, k|
|
22
|
+
hash[k] = {} unless hash.key?(k) && hash[k].is_a?(::Hash)
|
23
|
+
hash[k]
|
28
24
|
end
|
29
25
|
|
30
|
-
|
31
|
-
|
32
|
-
result[yield(key)] = value.is_a?(::Hash) ? value.deep_transform_keys(&block) : value
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
26
|
+
hash[last_key] = val
|
27
|
+
end
|
36
28
|
|
37
|
-
|
29
|
+
def deep_transform_keys(&block)
|
30
|
+
each_with_object({}) do |(key, value), result|
|
31
|
+
result[yield(key)] = value.is_a?(::Hash) ? value.deep_transform_keys(&block) : value
|
32
|
+
end
|
38
33
|
end
|
39
34
|
end
|
35
|
+
|
36
|
+
using self
|
40
37
|
end
|
@@ -1,23 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def safe_constantize
|
9
|
-
names = split("::")
|
3
|
+
# Add simple safe_constantize method to String
|
4
|
+
module Runger::Ext::StringConstantize
|
5
|
+
refine String do
|
6
|
+
def safe_constantize
|
7
|
+
names = split('::')
|
10
8
|
|
11
|
-
|
9
|
+
return nil if names.empty?
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
12
|
+
names.shift if names.size > 1 && names.first.empty?
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
14
|
+
names.inject(Object) do |constant, name|
|
15
|
+
break if constant.nil?
|
16
|
+
|
17
|
+
constant.const_get(name, false) if constant.const_defined?(name, false)
|
21
18
|
end
|
22
19
|
end
|
23
20
|
end
|
data/lib/runger/loaders/base.rb
CHANGED
@@ -1,21 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class Base
|
6
|
-
include Tracing
|
3
|
+
class Runger::Loaders::Base
|
4
|
+
include ::Runger::Tracing
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(local:)
|
15
|
-
@local = local
|
16
|
-
end
|
17
|
-
|
18
|
-
def use_local? = @local == true
|
6
|
+
class << self
|
7
|
+
def call(local: Runger::Settings.use_local_files, **options)
|
8
|
+
new(local:).call(**options)
|
19
9
|
end
|
20
10
|
end
|
11
|
+
|
12
|
+
def initialize(local:)
|
13
|
+
@local = local
|
14
|
+
end
|
15
|
+
|
16
|
+
def use_local? = @local == true
|
21
17
|
end
|