runger_config 4.0.0 → 5.1.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/bin/release +27 -0
  4. data/lib/generators/runger/app_config/app_config_generator.rb +6 -10
  5. data/lib/generators/runger/config/config_generator.rb +44 -41
  6. data/lib/generators/runger/install/install_generator.rb +35 -37
  7. data/lib/runger/auto_cast.rb +3 -3
  8. data/lib/runger/config.rb +114 -94
  9. data/lib/runger/dynamic_config.rb +21 -23
  10. data/lib/runger/ejson_parser.rb +24 -24
  11. data/lib/runger/env.rb +50 -52
  12. data/lib/runger/ext/deep_dup.rb +33 -36
  13. data/lib/runger/ext/deep_freeze.rb +28 -32
  14. data/lib/runger/ext/flatten_names.rb +23 -27
  15. data/lib/runger/ext/hash.rb +26 -29
  16. data/lib/runger/ext/string_constantize.rb +12 -15
  17. data/lib/runger/loaders/base.rb +11 -15
  18. data/lib/runger/loaders/doppler.rb +38 -42
  19. data/lib/runger/loaders/ejson.rb +65 -63
  20. data/lib/runger/loaders/env.rb +6 -10
  21. data/lib/runger/loaders/yaml.rb +69 -66
  22. data/lib/runger/loaders.rb +69 -71
  23. data/lib/runger/option_parser_builder.rb +16 -18
  24. data/lib/runger/optparse_config.rb +11 -10
  25. data/lib/runger/rails/autoload.rb +24 -26
  26. data/lib/runger/rails/config.rb +13 -17
  27. data/lib/runger/rails/loaders/credentials.rb +53 -57
  28. data/lib/runger/rails/loaders/secrets.rb +21 -25
  29. data/lib/runger/rails/loaders/yaml.rb +1 -6
  30. data/lib/runger/rails/loaders.rb +3 -3
  31. data/lib/runger/rails/settings.rb +49 -49
  32. data/lib/runger/rails.rb +9 -11
  33. data/lib/runger/railtie.rb +3 -2
  34. data/lib/runger/rbs.rb +29 -29
  35. data/lib/runger/settings.rb +82 -84
  36. data/lib/runger/testing/helpers.rb +26 -28
  37. data/lib/runger/testing.rb +2 -2
  38. data/lib/runger/tracing.rb +143 -136
  39. data/lib/runger/type_casting.rb +16 -11
  40. data/lib/runger/utils/which.rb +10 -12
  41. data/lib/runger/version.rb +1 -1
  42. data/lib/runger.rb +1 -1
  43. data/lib/runger_config.rb +34 -27
  44. metadata +20 -19
@@ -1,48 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Runger
4
- module Ext
5
- # Extend Object through refinements
6
- module DeepDup
7
- refine ::Hash do
8
- # Based on ActiveSupport http://api.rubyonrails.org/classes/Hash.html#method-i-deep_dup
9
- def deep_dup
10
- each_with_object(dup) do |(key, value), hash|
11
- hash[key] = if value.is_a?(::Hash) || value.is_a?(::Array)
12
- value.deep_dup
13
- else
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
- refine ::Object do
34
- def deep_dup
35
- dup
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
- refine ::Module do
40
- def deep_dup
41
- self
42
- end
43
- end
32
+ refine ::Object do
33
+ def deep_dup
34
+ dup
35
+ end
36
+ end
44
37
 
45
- using self
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
- module Runger
4
- module Ext
5
- # Add #deep_freeze to hashes and arrays
6
- module DeepFreeze
7
- refine ::Hash do
8
- def deep_freeze
9
- freeze
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
- refine ::Array do
17
- def deep_freeze
18
- freeze
19
- each do |value|
20
- value.deep_freeze if value.is_a?(::Hash) || value.is_a?(::Array)
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
- begin
26
- require "active_support/core_ext/hash/indifferent_access"
27
- rescue LoadError
28
- end
23
+ begin
24
+ require 'active_support/core_ext/hash/indifferent_access'
25
+ rescue LoadError
26
+ end
29
27
 
30
- if defined?(::ActiveSupport::HashWithIndifferentAccess)
31
- refine ::ActiveSupport::HashWithIndifferentAccess do
32
- def deep_freeze
33
- freeze
34
- each_value do |value|
35
- value.deep_freeze if value.is_a?(::Hash) || value.is_a?(::Array)
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
- module Runger
4
- module Ext
5
- # Convert Hash with mixed array and hash values to an
6
- # array of paths.
7
- module FlattenNames
8
- refine ::Array do
9
- def flatten_names(prefix, buf)
10
- if empty?
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
- refine ::Hash do
26
- def flatten_names(prefix = nil, buf = [])
27
- each_with_object(buf) do |(k, v), acc|
28
- parent = prefix ? "#{prefix}.#{k}" : k
29
- v.flatten_names(parent, acc)
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
- using self
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
@@ -1,40 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Runger
4
- module Ext
5
- # Extend Hash through refinements
6
- module Hash
7
- refine ::Hash do
8
- def stringify_keys!
9
- keys.each do |key|
10
- value = delete(key)
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
- def bury(val, *path)
18
- raise ArgumentError, "No path specified" if path.empty?
19
- raise ArgumentError, "Path cannot contain nil" if path.compact.size != path.size
12
+ self
13
+ end
20
14
 
21
- last_key = path.pop
22
- hash = path.reduce(self) do |hash, k|
23
- hash[k] = {} unless hash.key?(k) && hash[k].is_a?(::Hash)
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
- hash[last_key] = val
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
- def deep_transform_keys(&block)
31
- each_with_object({}) do |(key, value), result|
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
- using self
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
- module Runger
4
- module Ext
5
- # Add simple safe_constantize method to String
6
- module StringConstantize
7
- refine String do
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
- return nil if names.empty?
9
+ return nil if names.empty?
12
10
 
13
- # Remove the first blank element in case of '::ClassName' notation.
14
- names.shift if names.size > 1 && names.first.empty?
11
+ # Remove the first blank element in case of '::ClassName' notation.
12
+ names.shift if names.size > 1 && names.first.empty?
15
13
 
16
- names.inject(Object) do |constant, name|
17
- break if constant.nil?
18
- constant.const_get(name, false) if constant.const_defined?(name, false)
19
- end
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
@@ -1,21 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Runger
4
- module Loaders
5
- class Base
6
- include Tracing
3
+ class Runger::Loaders::Base
4
+ include ::Runger::Tracing
7
5
 
8
- class << self
9
- def call(local: Runger::Settings.use_local_files, **)
10
- new(local:).call(**)
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
@@ -1,61 +1,57 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "uri"
4
- require "net/http"
5
- require "json"
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
6
 
7
- module Runger
8
- module Loaders
9
- class Doppler < Base
10
- class RequestError < StandardError; end
7
+ class Runger::Loaders::Doppler < Runger::Loaders::Base
8
+ class RequestError < StandardError; end
11
9
 
12
- class << self
13
- attr_accessor :download_url
14
- attr_writer :token
10
+ class << self
11
+ attr_accessor :download_url
12
+ attr_writer :token
15
13
 
16
- def token
17
- @token || ENV["DOPPLER_TOKEN"]
18
- end
19
- end
14
+ def token
15
+ @token || ENV.fetch('DOPPLER_TOKEN', nil)
16
+ end
17
+ end
20
18
 
21
- self.download_url = "https://api.doppler.com/v3/configs/config/secrets/download"
19
+ self.download_url = 'https://api.doppler.com/v3/configs/config/secrets/download'
22
20
 
23
- def call(env_prefix:, **_options)
24
- env_payload = parse_doppler_response(url: Doppler.download_url, token: Doppler.token)
21
+ def call(env_prefix:, **_options)
22
+ env_payload = parse_doppler_response(url: Runger::Loaders::Doppler.download_url, token: Runger::Loaders::Doppler.token)
25
23
 
26
- env = ::Runger::Env.new(type_cast: ::Runger::NoCast, env_container: env_payload)
24
+ env = ::Runger::Env.new(type_cast: ::Runger::NoCast, env_container: env_payload)
27
25
 
28
- env.fetch_with_trace(env_prefix).then do |(conf, trace)|
29
- Tracing.current_trace&.merge!(trace)
30
- conf
31
- end
32
- end
26
+ env.fetch_with_trace(env_prefix).then do |(conf, trace)|
27
+ ::Runger::Tracing.current_trace&.merge!(trace)
28
+ conf
29
+ end
30
+ end
33
31
 
34
- private
32
+ private
35
33
 
36
- def parse_doppler_response(url:, token:)
37
- response = fetch_doppler_config(url, token)
34
+ def parse_doppler_response(url:, token:)
35
+ response = fetch_doppler_config(url, token)
38
36
 
39
- unless response.is_a?(Net::HTTPSuccess)
40
- raise RequestError, "#{response.code} #{response.message}"
41
- end
37
+ unless response.is_a?(Net::HTTPSuccess)
38
+ raise(RequestError, "#{response.code} #{response.message}")
39
+ end
42
40
 
43
- JSON.parse(response.read_body)
44
- end
41
+ JSON.parse(response.read_body)
42
+ end
45
43
 
46
- def fetch_doppler_config(url, token)
47
- uri = URI.parse(url)
48
- raise "Doppler token is required to load configuration from Doppler" if token.nil?
44
+ def fetch_doppler_config(url, token)
45
+ uri = URI.parse(url)
46
+ raise('Doppler token is required to load configuration from Doppler') if token.nil?
49
47
 
50
- http = Net::HTTP.new(uri.host, uri.port)
51
- http.use_ssl = true if uri.scheme == "https"
48
+ http = Net::HTTP.new(uri.host, uri.port)
49
+ http.use_ssl = true if uri.scheme == 'https'
52
50
 
53
- request = Net::HTTP::Get.new(uri)
54
- request["Accept"] = "application/json"
55
- request["Authorization"] = "Bearer #{token}"
51
+ request = Net::HTTP::Get.new(uri)
52
+ request['Accept'] = 'application/json'
53
+ request['Authorization'] = "Bearer #{token}"
56
54
 
57
- http.request(request)
58
- end
59
- end
55
+ http.request(request)
60
56
  end
61
57
  end
@@ -1,89 +1,91 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "runger/ejson_parser"
3
+ require 'runger/ejson_parser'
4
4
 
5
- module Runger
6
- module Loaders
7
- class EJSON < Base
8
- class << self
9
- attr_accessor :bin_path
10
- end
11
-
12
- self.bin_path = "ejson"
13
-
14
- def call(name:, ejson_namespace: name, ejson_parser: Runger::EJSONParser.new(EJSON.bin_path), **_options)
15
- configs = []
5
+ class Runger::Loaders::EJSON < Runger::Loaders::Base
6
+ class << self
7
+ attr_accessor :bin_path
8
+ end
16
9
 
17
- rel_config_paths.each do |rel_config_path|
18
- secrets_hash, rel_path =
19
- extract_hash_from_rel_config_path(
20
- ejson_parser: ejson_parser,
21
- rel_config_path: rel_config_path
22
- )
10
+ self.bin_path = 'ejson'
23
11
 
24
- next unless secrets_hash
12
+ def call(
13
+ name:,
14
+ ejson_namespace: name,
15
+ ejson_parser: Runger::EJSONParser.new(Runger::Loaders::EJSON.bin_path),
16
+ **_options
17
+ )
18
+ configs = []
25
19
 
26
- config_hash = if ejson_namespace
27
- secrets_hash[ejson_namespace]
28
- else
29
- secrets_hash.except("_public_key")
30
- end
20
+ rel_config_paths.each do |rel_config_path|
21
+ secrets_hash, rel_path =
22
+ extract_hash_from_rel_config_path(
23
+ ejson_parser:,
24
+ rel_config_path:,
25
+ )
31
26
 
32
- next unless config_hash.is_a?(Hash)
27
+ next unless secrets_hash
33
28
 
34
- configs <<
35
- trace!(:ejson, path: rel_path) do
36
- config_hash
37
- end
29
+ config_hash =
30
+ if ejson_namespace
31
+ secrets_hash[ejson_namespace]
32
+ else
33
+ secrets_hash.except('_public_key')
38
34
  end
39
35
 
40
- return {} if configs.empty?
36
+ next unless config_hash.is_a?(Hash)
41
37
 
42
- configs.inject do |result_config, next_config|
43
- Utils.deep_merge!(result_config, next_config)
38
+ configs <<
39
+ trace!(:ejson, path: rel_path) do
40
+ config_hash
44
41
  end
45
- end
42
+ end
46
43
 
47
- private
44
+ return {} if configs.empty?
48
45
 
49
- def rel_config_paths
50
- chain = [environmental_rel_config_path]
46
+ configs.inject do |result_config, next_config|
47
+ ::Runger::Utils.deep_merge!(result_config, next_config)
48
+ end
49
+ end
51
50
 
52
- chain << "secrets.local.ejson" if use_local?
51
+ private
53
52
 
54
- chain
55
- end
53
+ def rel_config_paths
54
+ chain = [environmental_rel_config_path]
56
55
 
57
- def environmental_rel_config_path
58
- if Settings.current_environment
59
- # if environment file is absent, then take data from the default one
60
- [
61
- "#{Settings.current_environment}/secrets.ejson",
62
- default_rel_config_path
63
- ]
64
- else
65
- default_rel_config_path
66
- end
67
- end
56
+ chain << 'secrets.local.ejson' if use_local?
57
+
58
+ chain
59
+ end
68
60
 
69
- def default_rel_config_path
70
- "secrets.ejson"
71
- end
61
+ def environmental_rel_config_path
62
+ if ::Runger::Settings.current_environment
63
+ # if environment file is absent, then take data from the default one
64
+ [
65
+ "#{::Runger::Settings.current_environment}/secrets.ejson",
66
+ default_rel_config_path,
67
+ ]
68
+ else
69
+ default_rel_config_path
70
+ end
71
+ end
72
72
 
73
- def extract_hash_from_rel_config_path(ejson_parser:, rel_config_path:)
74
- rel_config_path = [rel_config_path] unless rel_config_path.is_a?(Array)
73
+ def default_rel_config_path
74
+ 'secrets.ejson'
75
+ end
75
76
 
76
- rel_config_path.each do |rel_conf_path|
77
- rel_path = "config/#{rel_conf_path}"
78
- abs_path = "#{Settings.app_root}/#{rel_path}"
77
+ def extract_hash_from_rel_config_path(ejson_parser:, rel_config_path:)
78
+ rel_config_path = Array(rel_config_path)
79
79
 
80
- result = ejson_parser.call(abs_path)
80
+ rel_config_path.each do |rel_conf_path|
81
+ rel_path = "config/#{rel_conf_path}"
82
+ abs_path = "#{::Runger::Settings.app_root}/#{rel_path}"
81
83
 
82
- return [result, rel_path] if result
83
- end
84
+ result = ejson_parser.call(abs_path)
84
85
 
85
- nil
86
- end
86
+ return [result, rel_path] if result
87
87
  end
88
+
89
+ nil
88
90
  end
89
91
  end
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Runger
4
- module Loaders
5
- class Env < Base
6
- def call(env_prefix:, **_options)
7
- env = ::Runger::Env.new(type_cast: ::Runger::NoCast)
3
+ class Runger::Loaders::Env < Runger::Loaders::Base
4
+ def call(env_prefix:, **_options)
5
+ env = ::Runger::Env.new(type_cast: ::Runger::NoCast)
8
6
 
9
- env.fetch_with_trace(env_prefix).then do |(conf, trace)|
10
- Tracing.current_trace&.merge!(trace)
11
- conf
12
- end
13
- end
7
+ env.fetch_with_trace(env_prefix).then do |(conf, trace)|
8
+ ::Runger::Tracing.current_trace&.merge!(trace)
9
+ conf
14
10
  end
15
11
  end
16
12
  end