runger_config 4.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
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