anyway_config 2.2.3 → 2.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e4b1e98155e34f0220746d9230e433072143638e838f8975023c79cf75a9fe1
4
- data.tar.gz: e5d8b4f78fe7f32fc2dd3068f90897a28f57a292596346f5bb368a36094cea36
3
+ metadata.gz: fe4f769be22bc9cb820fd1159b88a565b2fb71e13ad617d90aaafbcb1673f995
4
+ data.tar.gz: 175e468716722b43b6c7d163a97b6523801f6658118d1c56bb5a4a0255807ef9
5
5
  SHA512:
6
- metadata.gz: 849c9c7fb4bc1101444dfec952a84ac3b1f605f3415d65d31ea727f176d9281cddc90e8b56ff73a3b25431126d61640931cfbc2621dc607493014e9a97d4ee3a
7
- data.tar.gz: 840073b4420e4c1a792db2571b29eb7605cbc7066833bc4afe91defd94ba08153a4f32036a6cd09c6cf8f1da718f7f11d41bb46c8b9ea1ab0a0bfd2a81ab0a20
6
+ metadata.gz: 7c323f89197ca35405ca77ee1e58a8b3fbbf4b0d6b57e7ccce380311a13994d18121966428a2681cb55a5892c2eff52ec347a6e3568072ea8f85d1cf7f75aa80
7
+ data.tar.gz: 25ee0b877318a2335c2019a414684d5b15e3755ceff90e51de3a0b821ee48f86a119f9753eaddac5dfb4724e38876ec5f18b68b065db7aa4b23d20b837666929
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 2.3.0 (2022-03-11)
6
+
7
+ - Add ability to load configurations under specific environments in pure Ruby apps. ([@fargelus][]).
8
+
9
+ Before loading environment configurations you need to specify variable `Anyway::Settings.current_environment`. In Rails apps this variable is same as `Rails.env` value.
10
+ After adding yaml loader will try to load params under this environment.
11
+
12
+ Also required env option was added to `Anyway::Config`.
13
+
5
14
  ## 2.2.3 (2022-01-21)
6
15
 
7
16
  - Fix Ruby 3.1 compatibility. ([@palkan][])
@@ -449,3 +458,4 @@ No we're dependency-free!
449
458
  [@envek]: https://github.com/Envek
450
459
  [@progapandist]: https://github.com/progapandist
451
460
  [@skryukov]: https://github.com/skryukov
461
+ [@fargelus]: https://github.com/fargelus
data/README.md CHANGED
@@ -297,6 +297,24 @@ end
297
297
  MyConfig.new(api_secret: "") #=> raises Anyway::Config::ValidationError
298
298
  ```
299
299
 
300
+ `Required` method supports additional `env` parameter which indicates necessity to run validations under specified
301
+ environments. `Env` parameter could be present in symbol, string, array or hash formats:
302
+
303
+ ```ruby
304
+ class EnvConfig < Anyway::Config
305
+ required :password, env: "production"
306
+ required :maps_api_key, env: :production
307
+ required :smtp_host, env: %i[production staging]
308
+ required :aws_bucket, env: %w[production staging]
309
+ required :anycable_rpc_host, env: {except: :development}
310
+ required :anycable_redis_url, env: {except: %i[development test]}
311
+ required :anycable_broadcast_adapter, env: {except: %w[development test]}
312
+ end
313
+ ```
314
+
315
+ If your current `Anyway::Settings.current_environment` is mismatch keys that specified
316
+ `Anyway::Config::ValidationError` error will be raised.
317
+
300
318
  If you need more complex validation or need to manipulate with config state right after it has been loaded, you can use _on load callbacks_ and `#raise_validation_error` method:
301
319
 
302
320
  ```ruby
@@ -529,7 +547,22 @@ The default data loading mechanism for non-Rails applications is the following (
529
547
 
530
548
  1) **YAML configuration files**: `./config/<config-name>.yml`.
531
549
 
532
- In pure Ruby apps, we do not know about _environments_ (`test`, `development`, `production`, etc.); thus, we assume that the YAML contains values for a single environment:
550
+ In pure Ruby apps, we also can load data under specific _environments_ (`test`, `development`, `production`, etc.).
551
+ If you want to enable this feature you must specify `Anyway::Settings.current_environment` variable for load config under specific environment.
552
+
553
+ ```ruby
554
+ Anyway::Settings.current_environment = "development"
555
+ ```
556
+
557
+ YAML files should be in this format:
558
+
559
+ ```yml
560
+ development:
561
+ host: localhost
562
+ port: 3000
563
+ ```
564
+
565
+ If `Anyway::Settings.current_environment` is missed we assume that the YAML contains values for a single environment:
533
566
 
534
567
  ```yml
535
568
  host: localhost
@@ -47,6 +47,8 @@ module Anyway # :nodoc:
47
47
  __type_caster__
48
48
  ].freeze
49
49
 
50
+ ENV_OPTION_EXCLUDE_KEY = :except
51
+
50
52
  class Error < StandardError; end
51
53
 
52
54
  class ValidationError < Error; end
@@ -126,14 +128,36 @@ module Anyway # :nodoc:
126
128
  end
127
129
  end
128
130
 
129
- def required(*names)
130
- unless (unknown_names = (names - config_attributes)).empty?
131
- raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}"
132
- end
131
+ def required(*names, env: nil)
132
+ unknown_names = names - config_attributes
133
+ raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}" if unknown_names.any?
133
134
 
135
+ names = filter_by_env(names, env)
134
136
  required_attributes.push(*names)
135
137
  end
136
138
 
139
+ def filter_by_env(names, env)
140
+ return names if env.nil? || env.to_s == current_env
141
+
142
+ filtered_names = if env.is_a?(Hash)
143
+ names_with_exclude_env_option(names, env)
144
+ elsif env.is_a?(Array)
145
+ names if env.flat_map(&:to_s).include?(current_env)
146
+ end
147
+
148
+ filtered_names || []
149
+ end
150
+
151
+ def current_env
152
+ Settings.current_environment.to_s
153
+ end
154
+
155
+ def names_with_exclude_env_option(names, env)
156
+ envs = env[ENV_OPTION_EXCLUDE_KEY]
157
+ excluded_envs = [envs].flat_map(&:to_s)
158
+ names if excluded_envs.none?(current_env)
159
+ end
160
+
137
161
  def required_attributes
138
162
  return @required_attributes if instance_variable_defined?(:@required_attributes)
139
163
 
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "anyway/ext/hash"
5
+
6
+ using RubyNext
7
+ using Anyway::Ext::Hash
8
+
9
+ module Anyway
10
+ module Loaders
11
+ class YAML < Base
12
+ def call(config_path:, **_options)
13
+ rel_config_path = relative_config_path(config_path).to_s
14
+ base_config = trace!(:yml, path: rel_config_path) do
15
+ config = load_base_yml(config_path)
16
+ environmental?(config) ? config_with_env(config) : config
17
+ end
18
+
19
+ return base_config unless use_local?
20
+
21
+ local_path = local_config_path(config_path)
22
+ local_config = trace!(:yml, path: relative_config_path(local_path).to_s) { load_local_yml(local_path) }
23
+ Utils.deep_merge!(base_config, local_config)
24
+ end
25
+
26
+ private
27
+
28
+ def environmental?(parsed_yml)
29
+ # strange, but still possible
30
+ return true if Settings.default_environmental_key? && parsed_yml.key?(Settings.default_environmental_key)
31
+ # possible
32
+ return true if !Settings.future.unwrap_known_environments && Settings.current_environment
33
+ # for other environments
34
+ return true if Settings.known_environments&.any? { |_1| parsed_yml.key?(_1) }
35
+ # preferred
36
+ parsed_yml.key?(Settings.current_environment)
37
+ end
38
+
39
+ def config_with_env(config)
40
+ env_config = config[Settings.current_environment] || {}
41
+ return env_config unless Settings.default_environmental_key?
42
+
43
+ default_config = config[Settings.default_environmental_key] || {}
44
+ Utils.deep_merge!(default_config, env_config)
45
+ end
46
+
47
+ def parse_yml(path)
48
+ return {} unless File.file?(path)
49
+ require "yaml" unless defined?(::YAML)
50
+
51
+ # By default, YAML load will return `false` when the yaml document is
52
+ # empty. When this occurs, we return an empty hash instead, to match
53
+ # the interface when no config file is present.
54
+ begin
55
+ if defined?(ERB)
56
+ ::YAML.load(ERB.new(File.read(path)).result, aliases: true) || {} # rubocop:disable Security/YAMLLoad
57
+ else
58
+ ::YAML.load_file(path, aliases: true) || {}
59
+ end
60
+ rescue ArgumentError
61
+ if defined?(ERB)
62
+ ::YAML.load(ERB.new(File.read(path)).result) || {} # rubocop:disable Security/YAMLLoad
63
+ else
64
+ ::YAML.load_file(path) || {}
65
+ end
66
+ end
67
+ end
68
+
69
+ alias_method :load_base_yml, :parse_yml
70
+ alias_method :load_local_yml, :parse_yml
71
+
72
+ def local_config_path(path)
73
+ path.sub(/\.yml/, ".local.yml")
74
+ end
75
+
76
+ def relative_config_path(path)
77
+ Pathname.new(path).then do |path|
78
+ return path if path.relative?
79
+ path.relative_path_from(Settings.app_root)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pathname"
4
+
3
5
  module Anyway
4
6
  # Use Settings name to not confuse with Config.
5
7
  #
@@ -35,6 +37,8 @@ module Anyway
35
37
  names.each { |_1| store[_1] = self.class.settings[_1] }
36
38
  end
37
39
 
40
+ setting :unwrap_known_environments, true
41
+
38
42
  private
39
43
 
40
44
  attr_reader :store
@@ -43,7 +47,10 @@ module Anyway
43
47
  class << self
44
48
  # Define whether to load data from
45
49
  # *.yml.local (or credentials/local.yml.enc)
46
- attr_accessor :use_local_files
50
+ attr_accessor :use_local_files,
51
+ :current_environment,
52
+ :default_environmental_key,
53
+ :known_environments
47
54
 
48
55
  # A proc returning a path to YML config file given the config name
49
56
  attr_reader :default_config_path
@@ -65,6 +72,14 @@ module Anyway
65
72
  def future
66
73
  @future ||= Future.new
67
74
  end
75
+
76
+ def app_root
77
+ Pathname.new(Dir.pwd)
78
+ end
79
+
80
+ def default_environmental_key?
81
+ !default_environmental_key.nil?
82
+ end
68
83
  end
69
84
 
70
85
  # By default, use local files only in development (that's the purpose if the local files)
@@ -6,12 +6,6 @@ module Anyway
6
6
  using Anyway::Ext::DeepDup
7
7
 
8
8
  using(Module.new do
9
- refine Hash do
10
- def inspect
11
- "{#{map { |k, v| "#{k}: #{v.inspect}" }.join(", ")}}"
12
- end
13
- end
14
-
15
9
  refine Thread::Backtrace::Location do
16
10
  def path_lineno() ; "#{path}:#{lineno}"; end
17
11
  end
@@ -100,8 +94,15 @@ module Anyway
100
94
  q.group do
101
95
  q.text k
102
96
  q.text " =>"
103
- q.breakable " " unless v.trace?
104
- q.pp v
97
+ if v.trace?
98
+ q.text " { "
99
+ q.pp v
100
+ q.breakable " "
101
+ q.text "}"
102
+ else
103
+ q.breakable " "
104
+ q.pp v
105
+ end
105
106
  end
106
107
  end
107
108
  end
@@ -47,6 +47,8 @@ module Anyway # :nodoc:
47
47
  __type_caster__
48
48
  ].freeze
49
49
 
50
+ ENV_OPTION_EXCLUDE_KEY = :except
51
+
50
52
  class Error < StandardError; end
51
53
 
52
54
  class ValidationError < Error; end
@@ -126,14 +128,36 @@ module Anyway # :nodoc:
126
128
  end
127
129
  end
128
130
 
129
- def required(*names)
130
- unless (unknown_names = (names - config_attributes)).empty?
131
- raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}"
132
- end
131
+ def required(*names, env: nil)
132
+ unknown_names = names - config_attributes
133
+ raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}" if unknown_names.any?
133
134
 
135
+ names = filter_by_env(names, env)
134
136
  required_attributes.push(*names)
135
137
  end
136
138
 
139
+ def filter_by_env(names, env)
140
+ return names if env.nil? || env.to_s == current_env
141
+
142
+ filtered_names = if env.is_a?(Hash)
143
+ names_with_exclude_env_option(names, env)
144
+ elsif env.is_a?(Array)
145
+ names if env.flat_map(&:to_s).include?(current_env)
146
+ end
147
+
148
+ filtered_names || []
149
+ end
150
+
151
+ def current_env
152
+ Settings.current_environment.to_s
153
+ end
154
+
155
+ def names_with_exclude_env_option(names, env)
156
+ envs = env[ENV_OPTION_EXCLUDE_KEY]
157
+ excluded_envs = [envs].flat_map(&:to_s)
158
+ names if excluded_envs.none?(current_env)
159
+ end
160
+
137
161
  def required_attributes
138
162
  return @required_attributes if instance_variable_defined?(:@required_attributes)
139
163
 
@@ -6,12 +6,6 @@ module Anyway
6
6
  using Anyway::Ext::DeepDup
7
7
 
8
8
  using(Module.new do
9
- refine Hash do
10
- def inspect
11
- "{#{map { |k, v| "#{k}: #{v.inspect}" }.join(", ")}}"
12
- end
13
- end
14
-
15
9
  refine Thread::Backtrace::Location do
16
10
  def path_lineno() ; "#{path}:#{lineno}"; end
17
11
  end
@@ -100,8 +94,15 @@ module Anyway
100
94
  q.group do
101
95
  q.text k
102
96
  q.text " =>"
103
- q.breakable " " unless v.trace?
104
- q.pp v
97
+ if v.trace?
98
+ q.text " { "
99
+ q.pp v
100
+ q.breakable " "
101
+ q.text "}"
102
+ else
103
+ q.breakable " "
104
+ q.pp v
105
+ end
105
106
  end
106
107
  end
107
108
  end
@@ -47,6 +47,8 @@ module Anyway # :nodoc:
47
47
  __type_caster__
48
48
  ].freeze
49
49
 
50
+ ENV_OPTION_EXCLUDE_KEY = :except
51
+
50
52
  class Error < StandardError; end
51
53
 
52
54
  class ValidationError < Error; end
@@ -126,14 +128,36 @@ module Anyway # :nodoc:
126
128
  end
127
129
  end
128
130
 
129
- def required(*names)
130
- unless (unknown_names = (names - config_attributes)).empty?
131
- raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}"
132
- end
131
+ def required(*names, env: nil)
132
+ unknown_names = names - config_attributes
133
+ raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}" if unknown_names.any?
133
134
 
135
+ names = filter_by_env(names, env)
134
136
  required_attributes.push(*names)
135
137
  end
136
138
 
139
+ def filter_by_env(names, env)
140
+ return names if env.nil? || env.to_s == current_env
141
+
142
+ filtered_names = if env.is_a?(Hash)
143
+ names_with_exclude_env_option(names, env)
144
+ elsif env.is_a?(Array)
145
+ names if env.flat_map(&:to_s).include?(current_env)
146
+ end
147
+
148
+ filtered_names || []
149
+ end
150
+
151
+ def current_env
152
+ Settings.current_environment.to_s
153
+ end
154
+
155
+ def names_with_exclude_env_option(names, env)
156
+ envs = env[ENV_OPTION_EXCLUDE_KEY]
157
+ excluded_envs = [envs].flat_map(&:to_s)
158
+ names if excluded_envs.none?(current_env)
159
+ end
160
+
137
161
  def required_attributes
138
162
  return @required_attributes if instance_variable_defined?(:@required_attributes)
139
163
 
@@ -6,12 +6,6 @@ module Anyway
6
6
  using Anyway::Ext::DeepDup
7
7
 
8
8
  using(Module.new do
9
- refine Hash do
10
- def inspect
11
- "{#{map { |k, v| "#{k}: #{v.inspect}" }.join(", ")}}"
12
- end
13
- end
14
-
15
9
  refine Thread::Backtrace::Location do
16
10
  def path_lineno() = "#{path}:#{lineno}"
17
11
  end
@@ -100,8 +94,15 @@ module Anyway
100
94
  q.group do
101
95
  q.text k
102
96
  q.text " =>"
103
- q.breakable " " unless v.trace?
104
- q.pp v
97
+ if v.trace?
98
+ q.text " { "
99
+ q.pp v
100
+ q.breakable " "
101
+ q.text "}"
102
+ else
103
+ q.breakable " "
104
+ q.pp v
105
+ end
105
106
  end
106
107
  end
107
108
  end
data/lib/anyway/config.rb CHANGED
@@ -47,6 +47,8 @@ module Anyway # :nodoc:
47
47
  __type_caster__
48
48
  ].freeze
49
49
 
50
+ ENV_OPTION_EXCLUDE_KEY = :except
51
+
50
52
  class Error < StandardError; end
51
53
 
52
54
  class ValidationError < Error; end
@@ -126,14 +128,36 @@ module Anyway # :nodoc:
126
128
  end
127
129
  end
128
130
 
129
- def required(*names)
130
- unless (unknown_names = (names - config_attributes)).empty?
131
- raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}"
132
- end
131
+ def required(*names, env: nil)
132
+ unknown_names = names - config_attributes
133
+ raise ArgumentError, "Unknown config param: #{unknown_names.join(",")}" if unknown_names.any?
133
134
 
135
+ names = filter_by_env(names, env)
134
136
  required_attributes.push(*names)
135
137
  end
136
138
 
139
+ def filter_by_env(names, env)
140
+ return names if env.nil? || env.to_s == current_env
141
+
142
+ filtered_names = if env.is_a?(Hash)
143
+ names_with_exclude_env_option(names, env)
144
+ elsif env.is_a?(Array)
145
+ names if env.flat_map(&:to_s).include?(current_env)
146
+ end
147
+
148
+ filtered_names || []
149
+ end
150
+
151
+ def current_env
152
+ Settings.current_environment.to_s
153
+ end
154
+
155
+ def names_with_exclude_env_option(names, env)
156
+ envs = env[ENV_OPTION_EXCLUDE_KEY]
157
+ excluded_envs = [envs].flat_map(&:to_s)
158
+ names if excluded_envs.none?(current_env)
159
+ end
160
+
137
161
  def required_attributes
138
162
  return @required_attributes if instance_variable_defined?(:@required_attributes)
139
163
 
@@ -10,18 +10,40 @@ module Anyway
10
10
  module Loaders
11
11
  class YAML < Base
12
12
  def call(config_path:, **_options)
13
- base_config = trace!(:yml, path: relative_config_path(config_path).to_s) { load_base_yml(config_path) }
13
+ rel_config_path = relative_config_path(config_path).to_s
14
+ base_config = trace!(:yml, path: rel_config_path) do
15
+ config = load_base_yml(config_path)
16
+ environmental?(config) ? config_with_env(config) : config
17
+ end
14
18
 
15
19
  return base_config unless use_local?
16
20
 
17
21
  local_path = local_config_path(config_path)
18
22
  local_config = trace!(:yml, path: relative_config_path(local_path).to_s) { load_local_yml(local_path) }
19
-
20
23
  Utils.deep_merge!(base_config, local_config)
21
24
  end
22
25
 
23
26
  private
24
27
 
28
+ def environmental?(parsed_yml)
29
+ # strange, but still possible
30
+ return true if Settings.default_environmental_key? && parsed_yml.key?(Settings.default_environmental_key)
31
+ # possible
32
+ return true if !Settings.future.unwrap_known_environments && Settings.current_environment
33
+ # for other environments
34
+ return true if Settings.known_environments&.any? { parsed_yml.key?(_1) }
35
+ # preferred
36
+ parsed_yml.key?(Settings.current_environment)
37
+ end
38
+
39
+ def config_with_env(config)
40
+ env_config = config[Settings.current_environment] || {}
41
+ return env_config unless Settings.default_environmental_key?
42
+
43
+ default_config = config[Settings.default_environmental_key] || {}
44
+ Utils.deep_merge!(default_config, env_config)
45
+ end
46
+
25
47
  def parse_yml(path)
26
48
  return {} unless File.file?(path)
27
49
  require "yaml" unless defined?(::YAML)
@@ -54,7 +76,7 @@ module Anyway
54
76
  def relative_config_path(path)
55
77
  Pathname.new(path).then do |path|
56
78
  return path if path.relative?
57
- path.relative_path_from(Pathname.new(Dir.pwd))
79
+ path.relative_path_from(Settings.app_root)
58
80
  end
59
81
  end
60
82
  end
@@ -3,34 +3,7 @@
3
3
  module Anyway
4
4
  module Rails
5
5
  module Loaders
6
- class YAML < Anyway::Loaders::YAML
7
- def load_base_yml(*)
8
- parsed_yml = super
9
- return parsed_yml unless environmental?(parsed_yml)
10
-
11
- env_config = parsed_yml[::Rails.env] || {}
12
- return env_config if Anyway::Settings.default_environmental_key.blank?
13
-
14
- default_config = parsed_yml[Anyway::Settings.default_environmental_key] || {}
15
- Utils.deep_merge!(default_config, env_config)
16
- end
17
-
18
- private
19
-
20
- def environmental?(parsed_yml)
21
- return true unless Settings.future.unwrap_known_environments
22
- # likely
23
- return true if parsed_yml.key?(::Rails.env)
24
- # less likely
25
- return true if ::Rails.application.config.anyway_config.known_environments.any? { parsed_yml.key?(_1) }
26
- # strange, but still possible
27
- Anyway::Settings.default_environmental_key.present? && parsed_yml.key?(Anyway::Settings.default_environmental_key)
28
- end
29
-
30
- def relative_config_path(path)
31
- Pathname.new(path).relative_path_from(::Rails.root)
32
- end
33
- end
6
+ class YAML < Anyway::Loaders::YAML; end
34
7
  end
35
8
  end
36
9
  end
@@ -9,16 +9,8 @@ end
9
9
 
10
10
  module Anyway
11
11
  class Settings
12
- class Future
13
- setting :unwrap_known_environments, true
14
- end
15
-
16
12
  class << self
17
13
  attr_reader :autoload_static_config_path, :autoloader
18
- attr_accessor :known_environments
19
-
20
- # Define a key for environmental yaml files to read default values from
21
- attr_accessor :default_environmental_key
22
14
 
23
15
  if defined?(::Zeitwerk)
24
16
  def autoload_static_config_path=(val)
@@ -62,6 +54,14 @@ module Anyway
62
54
  :no_op
63
55
  end
64
56
  end
57
+
58
+ def current_environment
59
+ ::Rails.env.to_s
60
+ end
61
+
62
+ def app_root
63
+ ::Rails.root
64
+ end
65
65
  end
66
66
 
67
67
  self.default_config_path = ->(name) { ::Rails.root.join("config", "#{name}.yml") }
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pathname"
4
+
3
5
  module Anyway
4
6
  # Use Settings name to not confuse with Config.
5
7
  #
@@ -35,6 +37,8 @@ module Anyway
35
37
  names.each { store[_1] = self.class.settings[_1] }
36
38
  end
37
39
 
40
+ setting :unwrap_known_environments, true
41
+
38
42
  private
39
43
 
40
44
  attr_reader :store
@@ -43,7 +47,10 @@ module Anyway
43
47
  class << self
44
48
  # Define whether to load data from
45
49
  # *.yml.local (or credentials/local.yml.enc)
46
- attr_accessor :use_local_files
50
+ attr_accessor :use_local_files,
51
+ :current_environment,
52
+ :default_environmental_key,
53
+ :known_environments
47
54
 
48
55
  # A proc returning a path to YML config file given the config name
49
56
  attr_reader :default_config_path
@@ -65,6 +72,14 @@ module Anyway
65
72
  def future
66
73
  @future ||= Future.new
67
74
  end
75
+
76
+ def app_root
77
+ Pathname.new(Dir.pwd)
78
+ end
79
+
80
+ def default_environmental_key?
81
+ !default_environmental_key.nil?
82
+ end
68
83
  end
69
84
 
70
85
  # By default, use local files only in development (that's the purpose if the local files)
@@ -6,12 +6,6 @@ module Anyway
6
6
  using Anyway::Ext::DeepDup
7
7
 
8
8
  using(Module.new do
9
- refine Hash do
10
- def inspect
11
- "{#{map { |k, v| "#{k}: #{v.inspect}" }.join(", ")}}"
12
- end
13
- end
14
-
15
9
  refine Thread::Backtrace::Location do
16
10
  def path_lineno() = "#{path}:#{lineno}"
17
11
  end
@@ -100,8 +94,15 @@ module Anyway
100
94
  q.group do
101
95
  q.text k
102
96
  q.text " =>"
103
- q.breakable " " unless v.trace?
104
- q.pp v
97
+ if v.trace?
98
+ q.text " { "
99
+ q.pp v
100
+ q.breakable " "
101
+ q.text "}"
102
+ else
103
+ q.breakable " "
104
+ q.pp v
105
+ end
105
106
  end
106
107
  end
107
108
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anyway # :nodoc:
4
- VERSION = "2.2.3"
4
+ VERSION = "2.3.0"
5
5
  end
@@ -3,8 +3,11 @@ module Anyway
3
3
  def self.loaders: -> Loaders::Registry
4
4
 
5
5
  class Settings
6
- def self.default_config_path=: (^(untyped) -> String val) -> ^(untyped) -> String?
6
+ def self.default_config_path=: (String | Pathname | ^(untyped) -> String val) -> void
7
7
  def self.future: -> Future
8
+ def self.current_environment: -> String?
9
+ def self.default_environmental_key: -> String?
10
+ def self.known_environments: -> Array[String]?
8
11
 
9
12
  class Future
10
13
  def self.setting: (untyped name, untyped default_value) -> untyped
@@ -19,14 +22,14 @@ module Anyway
19
22
  end
20
23
 
21
24
  def inspect: -> String
22
- def self.capture: ?{ -> Hash[untyped, untyped] } -> nil
25
+ def self.capture: ?{ -> Hash[untyped, untyped]? } -> Trace
23
26
  def self.trace_stack: -> Array[untyped]
24
27
  def self.current_trace: -> Trace?
25
28
  def self.source_stack: -> Array[untyped]
26
- def self.current_trace_source: -> {type: :accessor, called_from: untyped}
27
- def self.with_trace_source: (untyped src) -> untyped
28
- def trace!: (Symbol, *Array[String] paths, **untyped) ?{ -> Hash[untyped, untyped]} -> Hash[untyped, untyped]
29
- def self.trace!: (Symbol, *Array[String] paths, **untyped) ?{ -> Hash[untyped, untyped]} -> Hash[untyped, untyped]
29
+ def self.current_trace_source: -> ({type: Symbol} & Hash[Symbol, untyped])
30
+ def self.with_trace_source: (untyped src) { -> void } -> untyped
31
+ def trace!: [V] (Symbol, *String paths, **untyped) ?{ -> V} -> V
32
+ def self.trace!: [V] (Symbol, *String paths, **untyped) ?{ -> V} -> V
30
33
  end
31
34
 
32
35
  module RBSGenerator
@@ -56,6 +59,7 @@ module Anyway
56
59
  type hashType = Hash[Symbol, valueType | arrayType | hashType]
57
60
 
58
61
  type mappingType = valueType | arrayType | hashType
62
+ type envType = String | Symbol | Array[String | Symbol] | {except: String | Symbol | Array[String | Symbol]}
59
63
 
60
64
  class Config
61
65
  extend RBSGenerator
@@ -67,7 +71,7 @@ module Anyway
67
71
  def self.attr_config: (*Symbol args, **untyped) -> void
68
72
  def self.defaults: -> Hash[String, untyped]
69
73
  def self.config_attributes: -> Array[Symbol]?
70
- def self.required: (*Symbol names) -> void
74
+ def self.required: (*Symbol names, ?env: envType) -> void
71
75
  def self.required_attributes: -> Array[Symbol]
72
76
  def self.on_load: (*Symbol callbacks) ?{ () -> void } -> void
73
77
  def self.config_name: (?(Symbol | String) val) -> String?
@@ -80,9 +84,11 @@ module Anyway
80
84
  attr_reader env_prefix: String
81
85
 
82
86
  def initialize: (?Hash[Symbol | String, untyped] overrides) -> void
87
+ | (NilClass) -> void
83
88
  def reload: (?Hash[Symbol | String, untyped] overrides) -> Config
84
89
  def clear: -> void
85
90
  def load: (Hash[Symbol | String, untyped] overrides) -> Config
91
+ | (NilClass) -> Config
86
92
  def dig: (*(Symbol | String) keys) -> untyped
87
93
  def to_h: -> Hash[untyped, untyped]
88
94
  def dup: -> Config
@@ -117,12 +123,21 @@ module Anyway
117
123
  def use_local?: -> bool
118
124
  end
119
125
 
126
+ interface _Loader
127
+ def call: (**untyped) -> Hash[untyped, untyped]
128
+ end
129
+
120
130
  class Registry
121
- def prepend: (Symbol id, Base loader) -> void
122
- def append: (Symbol id, Base loader) -> void
123
- def insert_before: (Symbol another_id, Symbol id, Base loader) -> void
124
- def insert_after: (Symbol another_id, Symbol id, Base loader) -> void
125
- def override: (Symbol id, Base loader) -> void
131
+ def prepend: (Symbol id, _Loader loader) -> void
132
+ | (Symbol id) { (**untyped) -> Hash[untyped, untyped] } -> void
133
+ def append: (Symbol id, _Loader loader) -> void
134
+ | (Symbol id) { (**untyped) -> Hash[untyped, untyped] } -> void
135
+ def insert_before: (Symbol another_id, Symbol id, _Loader loader) -> void
136
+ | (Symbol another_id, Symbol id) { (**untyped) -> Hash[untyped, untyped] } -> void
137
+ def insert_after: (Symbol another_id, Symbol id, _Loader loader) -> void
138
+ | (Symbol another_id, Symbol id) { (**untyped) -> Hash[untyped, untyped] } -> void
139
+ def override: (Symbol id, _Loader loader) -> void
140
+ | (Symbol id) { (**untyped) -> Hash[untyped, untyped] } -> void
126
141
  def delete: (Symbol id) -> void
127
142
  end
128
143
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anyway_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.3
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-21 00:00:00.000000000 Z
11
+ date: 2022-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-next-core
@@ -108,7 +108,7 @@ files:
108
108
  - README.md
109
109
  - lib/.rbnext/2.7/anyway/auto_cast.rb
110
110
  - lib/.rbnext/2.7/anyway/config.rb
111
- - lib/.rbnext/2.7/anyway/rails/loaders/yaml.rb
111
+ - lib/.rbnext/2.7/anyway/loaders/yaml.rb
112
112
  - lib/.rbnext/2.7/anyway/rbs.rb
113
113
  - lib/.rbnext/2.7/anyway/settings.rb
114
114
  - lib/.rbnext/2.7/anyway/tracing.rb
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Anyway
4
- module Rails
5
- module Loaders
6
- class YAML < Anyway::Loaders::YAML
7
- def load_base_yml(*)
8
- parsed_yml = super
9
- return parsed_yml unless environmental?(parsed_yml)
10
-
11
- env_config = parsed_yml[::Rails.env] || {}
12
- return env_config if Anyway::Settings.default_environmental_key.blank?
13
-
14
- default_config = parsed_yml[Anyway::Settings.default_environmental_key] || {}
15
- Utils.deep_merge!(default_config, env_config)
16
- end
17
-
18
- private
19
-
20
- def environmental?(parsed_yml)
21
- return true unless Settings.future.unwrap_known_environments
22
- # likely
23
- return true if parsed_yml.key?(::Rails.env)
24
- # less likely
25
- return true if ::Rails.application.config.anyway_config.known_environments.any? { |_1| parsed_yml.key?(_1) }
26
- # strange, but still possible
27
- Anyway::Settings.default_environmental_key.present? && parsed_yml.key?(Anyway::Settings.default_environmental_key)
28
- end
29
-
30
- def relative_config_path(path)
31
- Pathname.new(path).relative_path_from(::Rails.root)
32
- end
33
- end
34
- end
35
- end
36
- end