anyway_config 2.2.3 → 2.3.0

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