anyway_config 1.4.4 → 2.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +187 -51
- data/lib/anyway.rb +22 -2
- data/lib/anyway/config.rb +116 -98
- data/lib/anyway/dynamic_config.rb +27 -0
- data/lib/anyway/env.rb +2 -5
- data/lib/anyway/ext/deep_dup.rb +4 -4
- data/lib/anyway/ext/deep_freeze.rb +5 -0
- data/lib/anyway/ext/jruby.rb +9 -4
- data/lib/anyway/ext/string_serialize.rb +1 -7
- data/{spec/dummy/config.ru → lib/anyway/loaders/env_loader.rb} +0 -0
- data/lib/anyway/loaders/secrets_loader.rb +0 -0
- data/lib/anyway/loaders/yaml_loader.rb +0 -0
- data/lib/anyway/option_parser_builder.rb +2 -2
- data/lib/anyway/optparse_config.rb +90 -0
- data/lib/anyway/rails/config.rb +76 -24
- data/lib/anyway/railtie.rb +11 -0
- data/lib/anyway/testing.rb +13 -0
- data/lib/anyway/testing/helpers.rb +36 -0
- data/lib/anyway/version.rb +1 -1
- metadata +46 -48
- data/.gem_release.yml +0 -3
- data/.gitignore +0 -40
- data/.rubocop.yml +0 -50
- data/.travis.yml +0 -30
- data/CHANGELOG.md +0 -112
- data/Gemfile +0 -21
- data/Rakefile +0 -23
- data/anyway_config.gemspec +0 -29
- data/config/cool.yml +0 -5
- data/gemfiles/jruby.gemfile +0 -7
- data/gemfiles/rails42.gemfile +0 -6
- data/gemfiles/rails5.gemfile +0 -6
- data/gemfiles/railsmaster.gemfile +0 -7
- data/spec/anyway.yml +0 -2
- data/spec/config_spec.rb +0 -337
- data/spec/config_spec_norails.rb +0 -86
- data/spec/dummy/config/application.rb +0 -13
- data/spec/dummy/config/boot.rb +0 -5
- data/spec/dummy/config/cool.yml +0 -5
- data/spec/dummy/config/cool_custom.yml +0 -2
- data/spec/dummy/config/database.yml +0 -25
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/test.rb +0 -2
- data/spec/dummy/config/routes.rb +0 -2
- data/spec/dummy/config/secrets.yml +0 -30
- data/spec/env_spec.rb +0 -50
- data/spec/ext/deep_dup_spec.rb +0 -38
- data/spec/ext/deep_freeze_spec.rb +0 -32
- data/spec/ext/hash_spec.rb +0 -39
- data/spec/ext/string_serialize_spec.rb +0 -32
- data/spec/spec_helper.rb +0 -31
- data/spec/spec_norails_helper.rb +0 -26
- data/spec/support/cool_config.rb +0 -10
- data/spec/support/print_warning_matcher.rb +0 -34
- data/spec/support/small_config.rb +0 -7
- data/spec/support/test_config.rb +0 -16
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyway
|
4
|
+
# Adds ability to generate anonymous (class-less) config dynamicly
|
5
|
+
# (like Rails.application.config_for but using more data sources).
|
6
|
+
module DynamicConfig
|
7
|
+
module ClassMethods
|
8
|
+
# Load config as Hash by any name
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# my_config = Anyway::Config.for(:my_app)
|
13
|
+
# # will load data from config/my_app.yml, secrets.my_app, ENV["MY_APP_*"]
|
14
|
+
#
|
15
|
+
def for(name, **options)
|
16
|
+
config = allocate
|
17
|
+
options[:env_prefix] ||= name.to_s.upcase
|
18
|
+
options[:config_path] ||= config.resolve_config_path(name, options[:env_prefix])
|
19
|
+
config.load_from_sources(name: name, **options)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.included(base)
|
24
|
+
base.extend ClassMethods
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/anyway/env.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'anyway/ext/deep_dup'
|
4
|
-
require 'anyway/ext/string_serialize'
|
5
|
-
|
6
3
|
module Anyway
|
7
4
|
# Parses environment variables and provides
|
8
5
|
# method-like access
|
@@ -19,7 +16,7 @@ module Anyway
|
|
19
16
|
end
|
20
17
|
|
21
18
|
def fetch(prefix)
|
22
|
-
@data[prefix] ||= parse_env(prefix
|
19
|
+
@data[prefix] ||= parse_env(prefix)
|
23
20
|
@data[prefix].deep_dup
|
24
21
|
end
|
25
22
|
|
@@ -29,7 +26,7 @@ module Anyway
|
|
29
26
|
ENV.each_pair.with_object({}) do |(key, val), data|
|
30
27
|
next unless key.start_with?(prefix)
|
31
28
|
|
32
|
-
path = key.sub(/^#{prefix}_/,
|
29
|
+
path = key.sub(/^#{prefix}_/, "").downcase
|
33
30
|
set_by_path(data, path, val.serialize)
|
34
31
|
end
|
35
32
|
end
|
data/lib/anyway/ext/deep_dup.rb
CHANGED
@@ -22,6 +22,11 @@ module Anyway
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
begin
|
26
|
+
require "active_support/core_ext/hash/indifferent_access"
|
27
|
+
rescue LoadError
|
28
|
+
end
|
29
|
+
|
25
30
|
if defined?(::ActiveSupport::HashWithIndifferentAccess)
|
26
31
|
refine ::ActiveSupport::HashWithIndifferentAccess do
|
27
32
|
def deep_freeze
|
data/lib/anyway/ext/jruby.rb
CHANGED
@@ -13,10 +13,10 @@ module Anyway
|
|
13
13
|
def deep_dup
|
14
14
|
each_with_object(dup) do |(key, value), hash|
|
15
15
|
hash[key] = if value.is_a?(::Hash) || value.is_a?(::Array)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
value.deep_dup
|
17
|
+
else
|
18
|
+
value
|
19
|
+
end
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -74,6 +74,11 @@ module Anyway
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
begin
|
78
|
+
require "active_support/core_ext/hash/indifferent_access"
|
79
|
+
rescue LoadError
|
80
|
+
end
|
81
|
+
|
77
82
|
if defined?(::ActiveSupport::HashWithIndifferentAccess)
|
78
83
|
refine ::ActiveSupport::HashWithIndifferentAccess do
|
79
84
|
def deep_freeze
|
@@ -10,14 +10,10 @@ module Anyway
|
|
10
10
|
ARRAY_RXP = /\A[^'"].*\s*,\s*.*[^'"]\z/
|
11
11
|
|
12
12
|
refine ::String do
|
13
|
-
# rubocop:disable Metrics/MethodLength
|
14
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
15
13
|
def serialize
|
16
14
|
case self
|
17
15
|
when ARRAY_RXP
|
18
|
-
# rubocop:disable Style/SymbolProc
|
19
16
|
split(/\s*,\s*/).map { |word| word.serialize }
|
20
|
-
# rubocop:enable Style/SymbolProc
|
21
17
|
when /\A(true|t|yes|y)\z/i
|
22
18
|
true
|
23
19
|
when /\A(false|f|no|n)\z/i
|
@@ -29,13 +25,11 @@ module Anyway
|
|
29
25
|
when /\A\d*\.\d+\z/
|
30
26
|
to_f
|
31
27
|
when /\A['"].*['"]\z/
|
32
|
-
gsub(/(\A['"]|['"]\z)/,
|
28
|
+
gsub(/(\A['"]|['"]\z)/, "")
|
33
29
|
else
|
34
30
|
self
|
35
31
|
end
|
36
32
|
end
|
37
|
-
# rubocop:enable Metrics/MethodLength
|
38
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
39
33
|
end
|
40
34
|
|
41
35
|
using self
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "optparse"
|
4
4
|
|
5
5
|
module Anyway # :nodoc:
|
6
6
|
# Initializes the OptionParser instance using the given configuration
|
@@ -19,7 +19,7 @@ module Anyway # :nodoc:
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def option_parser_on_args(key, flag: false, desc: nil)
|
22
|
-
on_args = ["--#{key.to_s.tr(
|
22
|
+
on_args = ["--#{key.to_s.tr("_", "-")}#{flag ? "" : " VALUE"}"]
|
23
23
|
on_args << desc unless desc.nil?
|
24
24
|
on_args
|
25
25
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "anyway/option_parser_builder"
|
4
|
+
|
5
|
+
require "anyway/ext/deep_dup"
|
6
|
+
require "anyway/ext/string_serialize"
|
7
|
+
|
8
|
+
module Anyway
|
9
|
+
using Anyway::Ext::DeepDup
|
10
|
+
using Anyway::Ext::StringSerialize
|
11
|
+
|
12
|
+
# Adds ability to use script options as the source
|
13
|
+
# of configuration (via optparse)
|
14
|
+
module OptparseConfig
|
15
|
+
module ClassMethods
|
16
|
+
def ignore_options(*args)
|
17
|
+
args.each do |name|
|
18
|
+
option_parser_descriptors[name.to_s][:ignore] = true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def describe_options(**hargs)
|
23
|
+
hargs.each do |name, desc|
|
24
|
+
option_parser_descriptors[name.to_s][:desc] = desc
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def flag_options(*args)
|
29
|
+
args.each do |name|
|
30
|
+
option_parser_descriptors[name.to_s][:flag] = true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def extend_options(&block)
|
35
|
+
option_parser_extensions << block
|
36
|
+
end
|
37
|
+
|
38
|
+
def option_parser_options
|
39
|
+
config_attributes.each_with_object({}) do |key, result|
|
40
|
+
descriptor = option_parser_descriptors[key.to_s]
|
41
|
+
next if descriptor[:ignore] == true
|
42
|
+
|
43
|
+
result[key] = descriptor
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def option_parser_extensions
|
48
|
+
return @option_parser_extensions if instance_variable_defined?(:@option_parser_extensions)
|
49
|
+
|
50
|
+
@option_parser_extensions =
|
51
|
+
if superclass < Anyway::Config
|
52
|
+
superclass.option_parser_extensions.dup
|
53
|
+
else
|
54
|
+
[]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def option_parser_descriptors
|
59
|
+
return @option_parser_descriptors if instance_variable_defined?(:@option_parser_descriptors)
|
60
|
+
|
61
|
+
@option_parser_descriptors =
|
62
|
+
if superclass < Anyway::Config
|
63
|
+
superclass.option_parser_descriptors.deep_dup
|
64
|
+
else
|
65
|
+
Hash.new { |h, k| h[k] = {} }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def option_parser
|
71
|
+
@option_parser ||= begin
|
72
|
+
OptionParserBuilder.call(self.class.option_parser_options) do |key, arg|
|
73
|
+
set_value(key, arg.is_a?(String) ? arg.serialize : arg)
|
74
|
+
end.tap do |parser|
|
75
|
+
self.class.option_parser_extensions.map do |extension|
|
76
|
+
extension.call(parser, self)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def parse_options!(options)
|
83
|
+
option_parser.parse!(options)
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.included(base)
|
87
|
+
base.extend ClassMethods
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/anyway/rails/config.rb
CHANGED
@@ -1,38 +1,90 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
4
|
+
|
3
5
|
module Anyway
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
module Rails
|
7
|
+
# Enhance config to be more Railsy-like:
|
8
|
+
# – accept hashes with indeferent access
|
9
|
+
# - load data from secrets
|
10
|
+
# - recognize Rails env when loading from YML
|
11
|
+
module Config
|
12
|
+
module ClassMethods
|
13
|
+
# Make defaults to be a Hash with indifferent access
|
14
|
+
def defaults
|
15
|
+
return @defaults if instance_variable_defined?(:@defaults)
|
8
16
|
|
9
|
-
|
17
|
+
@defaults = super.with_indifferent_access
|
18
|
+
end
|
10
19
|
end
|
11
|
-
end
|
12
20
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
21
|
+
def load_from_sources(**options)
|
22
|
+
base_config = {}.with_indifferent_access
|
23
|
+
each_source(options) do |config|
|
24
|
+
base_config.deep_merge!(config) if config
|
25
|
+
end
|
26
|
+
base_config
|
27
|
+
end
|
19
28
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
29
|
+
def each_source(options)
|
30
|
+
yield load_from_file(options)
|
31
|
+
yield load_from_secrets(options)
|
32
|
+
yield load_from_credentials(options)
|
33
|
+
yield load_from_env(options)
|
34
|
+
end
|
24
35
|
|
25
|
-
|
26
|
-
|
27
|
-
|
36
|
+
def load_from_file(name:, config_path:, env_prefix:, **_options)
|
37
|
+
file_config = load_from_yml(config_path)[::Rails.env] || {}
|
38
|
+
|
39
|
+
if Anyway::Settings.use_local_files
|
40
|
+
local_config_path = config_path.sub(/\.yml/, ".local.yml")
|
41
|
+
file_config.deep_merge!(load_from_yml(local_config_path) || {})
|
42
|
+
end
|
43
|
+
|
44
|
+
file_config
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_from_secrets(name:, **_options)
|
48
|
+
return unless ::Rails.application.respond_to?(:secrets)
|
49
|
+
|
50
|
+
::Rails.application.secrets.public_send(name)
|
28
51
|
end
|
29
|
-
config
|
30
|
-
end
|
31
52
|
|
32
|
-
|
53
|
+
def load_from_credentials(name:, **_options)
|
54
|
+
# do not load from credentials if we're in the context
|
55
|
+
# of the `credentials:edit` command
|
56
|
+
return if defined?(::Rails::Command::CredentialsCommand)
|
33
57
|
|
34
|
-
|
35
|
-
|
58
|
+
return unless ::Rails.application.respond_to?(:credentials)
|
59
|
+
|
60
|
+
# Create a new hash cause credentials are mutable!
|
61
|
+
creds_config = {}
|
62
|
+
|
63
|
+
creds_config.deep_merge!(::Rails.application.credentials.public_send(name) || {})
|
64
|
+
|
65
|
+
creds_config.deep_merge!(load_from_local_credentials(name: name)) if Anyway::Settings.use_local_files
|
66
|
+
creds_config
|
67
|
+
end
|
68
|
+
|
69
|
+
def load_from_local_credentials(name:)
|
70
|
+
local_creds_path = ::Rails.root.join("config/credentials/local.yml.enc").to_s
|
71
|
+
|
72
|
+
return unless File.file?(local_creds_path)
|
73
|
+
|
74
|
+
creds = ::Rails.application.encrypted(
|
75
|
+
local_creds_path,
|
76
|
+
key_path: ::Rails.root.join("config/credentials/local.key")
|
77
|
+
)
|
78
|
+
|
79
|
+
creds.public_send(name) || {}
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_config_path(name)
|
83
|
+
::Rails.root.join("config", "#{name}.yml")
|
84
|
+
end
|
36
85
|
end
|
37
86
|
end
|
38
87
|
end
|
88
|
+
|
89
|
+
Anyway::Config.prepend Anyway::Rails::Config
|
90
|
+
Anyway::Config.singleton_class.prepend Anyway::Rails::Config::ClassMethods
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyway # :nodoc:
|
4
|
+
class Railtie < ::Rails::Railtie # :nodoc:
|
5
|
+
# Add settings to Rails config
|
6
|
+
config.anyway_config = Anyway::Settings
|
7
|
+
|
8
|
+
# Allow autoloading of app/configs in configuration files
|
9
|
+
ActiveSupport::Dependencies.autoload_paths << "app/configs"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Anyway
|
4
|
+
module Testing
|
5
|
+
module Helpers
|
6
|
+
# Sets the ENV variables to the provided
|
7
|
+
# values and restore outside the block
|
8
|
+
#
|
9
|
+
# Also resets Anyway.env before and after calling the block
|
10
|
+
# to make sure that the values are not cached.
|
11
|
+
#
|
12
|
+
# NOTE: to remove the env value, pass `nil` as the value
|
13
|
+
def with_env(data)
|
14
|
+
was_values = []
|
15
|
+
|
16
|
+
data.each do |key, val|
|
17
|
+
was_values << [key, ENV[key]]
|
18
|
+
next ENV.delete(key) if val.nil?
|
19
|
+
ENV[key] = val
|
20
|
+
end
|
21
|
+
|
22
|
+
# clear cached env values
|
23
|
+
Anyway.env.clear
|
24
|
+
yield
|
25
|
+
ensure
|
26
|
+
was_values.each do |(key, val)|
|
27
|
+
next ENV.delete(key) if val.nil?
|
28
|
+
ENV[key] = val
|
29
|
+
end
|
30
|
+
|
31
|
+
# clear cache again
|
32
|
+
Anyway.env.clear
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/anyway/version.rb
CHANGED