dry-system 0.22.0 → 0.23.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 +4 -4
- data/CHANGELOG.md +400 -0
- data/LICENSE +1 -1
- data/README.md +2 -2
- data/dry-system.gemspec +2 -2
- data/lib/dry/system/component.rb +2 -3
- data/lib/dry/system/component_dir.rb +8 -34
- data/lib/dry/system/components.rb +8 -4
- data/lib/dry/system/config/component_dir.rb +60 -16
- data/lib/dry/system/config/component_dirs.rb +23 -10
- data/lib/dry/system/config/namespace.rb +4 -6
- data/lib/dry/system/constants.rb +1 -1
- data/lib/dry/system/container.rb +264 -182
- data/lib/dry/system/errors.rb +73 -53
- data/lib/dry/system/identifier.rb +62 -20
- data/lib/dry/system/importer.rb +83 -12
- data/lib/dry/system/indirect_component.rb +1 -1
- data/lib/dry/system/loader.rb +6 -1
- data/lib/dry/system/{manual_registrar.rb → manifest_registrar.rb} +8 -5
- data/lib/dry/system/plugins/bootsnap.rb +2 -1
- data/lib/dry/system/plugins/dependency_graph/strategies.rb +37 -1
- data/lib/dry/system/plugins/dependency_graph.rb +26 -20
- data/lib/dry/system/plugins/env.rb +2 -1
- data/lib/dry/system/plugins/logging.rb +2 -2
- data/lib/dry/system/plugins/monitoring.rb +1 -1
- data/lib/dry/system/plugins/notifications.rb +1 -1
- data/lib/dry/system/plugins/zeitwerk/compat_inflector.rb +22 -0
- data/lib/dry/system/plugins/zeitwerk.rb +109 -0
- data/lib/dry/system/plugins.rb +7 -4
- data/lib/dry/system/provider/source.rb +324 -0
- data/lib/dry/system/provider/source_dsl.rb +94 -0
- data/lib/dry/system/provider.rb +262 -22
- data/lib/dry/system/provider_registrar.rb +276 -0
- data/lib/dry/system/provider_source_registry.rb +70 -0
- data/lib/dry/system/provider_sources/settings/config.rb +86 -0
- data/lib/dry/system/provider_sources/settings/loader.rb +53 -0
- data/lib/dry/system/provider_sources/settings.rb +40 -0
- data/lib/dry/system/provider_sources.rb +5 -0
- data/lib/dry/system/version.rb +1 -1
- data/lib/dry/system.rb +44 -12
- metadata +18 -18
- data/lib/dry/system/booter/component_registry.rb +0 -35
- data/lib/dry/system/booter.rb +0 -200
- data/lib/dry/system/components/bootable.rb +0 -280
- data/lib/dry/system/components/config.rb +0 -35
- data/lib/dry/system/lifecycle.rb +0 -135
- data/lib/dry/system/provider_registry.rb +0 -27
- data/lib/dry/system/settings/file_loader.rb +0 -30
- data/lib/dry/system/settings/file_parser.rb +0 -51
- data/lib/dry/system/settings.rb +0 -64
- data/lib/dry/system/system_components/settings.rb +0 -11
@@ -1,280 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "dry/system/lifecycle"
|
4
|
-
require "dry/system/settings"
|
5
|
-
require "dry/system/components/config"
|
6
|
-
require "dry/system/constants"
|
7
|
-
|
8
|
-
module Dry
|
9
|
-
module System
|
10
|
-
module Components
|
11
|
-
# Bootable components can provide one or more objects and typically depend
|
12
|
-
# on 3rd-party code. A typical bootable component can be a database library,
|
13
|
-
# or an API client.
|
14
|
-
#
|
15
|
-
# These components can be registered via `Container.boot` and external component
|
16
|
-
# providers can register their components too, which then can be used and configured
|
17
|
-
# by your system.
|
18
|
-
#
|
19
|
-
# @example simple logger
|
20
|
-
# class App < Dry::System::Container
|
21
|
-
# boot(:logger) do
|
22
|
-
# init do
|
23
|
-
# require "logger"
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# start do
|
27
|
-
# register(:logger, Logger.new($stdout))
|
28
|
-
# end
|
29
|
-
# end
|
30
|
-
# end
|
31
|
-
#
|
32
|
-
# App[:logger] # returns configured logger
|
33
|
-
#
|
34
|
-
# @example using built-in system components
|
35
|
-
# class App < Dry::System::Container
|
36
|
-
# boot(:settings, from: :system) do
|
37
|
-
# settings do
|
38
|
-
# key :database_url, Types::String.constrained(filled: true)
|
39
|
-
# key :session_secret, Types::String.constrained(filled: true)
|
40
|
-
# end
|
41
|
-
# end
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# App[:settings] # returns loaded settings
|
45
|
-
#
|
46
|
-
# @api public
|
47
|
-
class Bootable
|
48
|
-
DEFAULT_FINALIZE = proc {}
|
49
|
-
|
50
|
-
# @!attribute [r] key
|
51
|
-
# @return [Symbol] component's unique name
|
52
|
-
attr_reader :name
|
53
|
-
|
54
|
-
# @!attribute [r] options
|
55
|
-
# @return [Hash] component's options
|
56
|
-
attr_reader :options
|
57
|
-
|
58
|
-
# @!attribute [r] triggers
|
59
|
-
# @return [Hash] lifecycle step after/before callbacks
|
60
|
-
attr_reader :triggers
|
61
|
-
|
62
|
-
# @!attribute [r] namespace
|
63
|
-
# @return [Symbol,String] default namespace for the container keys
|
64
|
-
attr_reader :namespace
|
65
|
-
|
66
|
-
TRIGGER_MAP = Hash.new { |h, k| h[k] = [] }.freeze
|
67
|
-
|
68
|
-
# @api private
|
69
|
-
def initialize(name, options = {}, &block)
|
70
|
-
@config = nil
|
71
|
-
@config_block = nil
|
72
|
-
@name = name
|
73
|
-
@triggers = {before: TRIGGER_MAP.dup, after: TRIGGER_MAP.dup}
|
74
|
-
@options = block ? options.merge(block: block) : options
|
75
|
-
@namespace = options[:namespace]
|
76
|
-
finalize = options[:finalize] || DEFAULT_FINALIZE
|
77
|
-
instance_exec(&finalize)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Execute `init` step
|
81
|
-
#
|
82
|
-
# @return [Bootable]
|
83
|
-
#
|
84
|
-
# @api public
|
85
|
-
def init
|
86
|
-
trigger(:before, :init)
|
87
|
-
lifecycle.(:init)
|
88
|
-
trigger(:after, :init)
|
89
|
-
self
|
90
|
-
end
|
91
|
-
|
92
|
-
# Execute `start` step
|
93
|
-
#
|
94
|
-
# @return [Bootable]
|
95
|
-
#
|
96
|
-
# @api public
|
97
|
-
def start
|
98
|
-
trigger(:before, :start)
|
99
|
-
lifecycle.(:start)
|
100
|
-
trigger(:after, :start)
|
101
|
-
self
|
102
|
-
end
|
103
|
-
|
104
|
-
# Execute `stop` step
|
105
|
-
#
|
106
|
-
# @return [Bootable]
|
107
|
-
#
|
108
|
-
# @api public
|
109
|
-
def stop
|
110
|
-
lifecycle.(:stop)
|
111
|
-
self
|
112
|
-
end
|
113
|
-
|
114
|
-
# Specify a before callback
|
115
|
-
#
|
116
|
-
# @return [Bootable]
|
117
|
-
#
|
118
|
-
# @api public
|
119
|
-
def before(event, &block)
|
120
|
-
triggers[:before][event] << block
|
121
|
-
self
|
122
|
-
end
|
123
|
-
|
124
|
-
# Specify an after callback
|
125
|
-
#
|
126
|
-
# @return [Bootable]
|
127
|
-
#
|
128
|
-
# @api public
|
129
|
-
def after(event, &block)
|
130
|
-
triggers[:after][event] << block
|
131
|
-
self
|
132
|
-
end
|
133
|
-
|
134
|
-
# Configure a component
|
135
|
-
#
|
136
|
-
# @return [Bootable]
|
137
|
-
#
|
138
|
-
# @api public
|
139
|
-
def configure(&block)
|
140
|
-
@config_block = block
|
141
|
-
end
|
142
|
-
|
143
|
-
# Define configuration settings with keys and types
|
144
|
-
#
|
145
|
-
# @return [Bootable]
|
146
|
-
#
|
147
|
-
# @api public
|
148
|
-
def settings(&block)
|
149
|
-
if block
|
150
|
-
@settings_block = block
|
151
|
-
elsif @settings_block
|
152
|
-
@settings = Settings::DSL.new(&@settings_block).call
|
153
|
-
else
|
154
|
-
@settings
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
# Return component's configuration
|
159
|
-
#
|
160
|
-
# @return [Dry::Struct]
|
161
|
-
#
|
162
|
-
# @api public
|
163
|
-
def config
|
164
|
-
@config || configure!
|
165
|
-
end
|
166
|
-
|
167
|
-
# Return a list of lifecycle steps that were executed
|
168
|
-
#
|
169
|
-
# @return [Array<Symbol>]
|
170
|
-
#
|
171
|
-
# @api public
|
172
|
-
def statuses
|
173
|
-
lifecycle.statuses
|
174
|
-
end
|
175
|
-
|
176
|
-
# Return system's container used by this component
|
177
|
-
#
|
178
|
-
# @return [Dry::Struct]
|
179
|
-
#
|
180
|
-
# @api public
|
181
|
-
def container
|
182
|
-
options.fetch(:container)
|
183
|
-
end
|
184
|
-
|
185
|
-
# Automatically called by the booter object after starting a component
|
186
|
-
#
|
187
|
-
# @return [Bootable]
|
188
|
-
#
|
189
|
-
# @api private
|
190
|
-
def finalize
|
191
|
-
lifecycle.container.each do |key, item|
|
192
|
-
container.register(key, item) unless container.registered?(key)
|
193
|
-
end
|
194
|
-
self
|
195
|
-
end
|
196
|
-
|
197
|
-
# Trigger a callback
|
198
|
-
#
|
199
|
-
# @return [Bootable]
|
200
|
-
#
|
201
|
-
# @api private
|
202
|
-
def trigger(key, event)
|
203
|
-
triggers[key][event].each do |fn|
|
204
|
-
container.instance_exec(lifecycle.container, &fn)
|
205
|
-
end
|
206
|
-
self
|
207
|
-
end
|
208
|
-
|
209
|
-
# Return a new instance with updated name and options
|
210
|
-
#
|
211
|
-
# @return [Dry::Struct]
|
212
|
-
#
|
213
|
-
# @api private
|
214
|
-
def new(name, new_options = EMPTY_HASH)
|
215
|
-
self.class.new(name, options.merge(new_options))
|
216
|
-
end
|
217
|
-
|
218
|
-
# Return a new instance with updated options
|
219
|
-
#
|
220
|
-
# @return [Dry::Struct]
|
221
|
-
#
|
222
|
-
# @api private
|
223
|
-
def with(new_options)
|
224
|
-
self.class.new(name, options.merge(new_options))
|
225
|
-
end
|
226
|
-
|
227
|
-
private
|
228
|
-
|
229
|
-
# Return lifecycle object used for this component
|
230
|
-
#
|
231
|
-
# @return [Lifecycle]
|
232
|
-
#
|
233
|
-
# @api private
|
234
|
-
def lifecycle
|
235
|
-
@lifecycle ||= Lifecycle.new(lf_container, component: self, &block)
|
236
|
-
end
|
237
|
-
|
238
|
-
# Return configured container for the lifecycle object
|
239
|
-
#
|
240
|
-
# @return [Dry::Container]
|
241
|
-
#
|
242
|
-
# @api private
|
243
|
-
def lf_container
|
244
|
-
container = Dry::Container.new
|
245
|
-
|
246
|
-
case namespace
|
247
|
-
when String, Symbol
|
248
|
-
container.namespace(namespace) { |c| return c }
|
249
|
-
when true
|
250
|
-
container.namespace(name) { |c| return c }
|
251
|
-
when nil
|
252
|
-
container
|
253
|
-
else
|
254
|
-
raise <<-STR
|
255
|
-
+namespace+ boot option must be true, string or symbol #{namespace.inspect} given.
|
256
|
-
STR
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
# Set config object
|
261
|
-
#
|
262
|
-
# @return [Dry::Struct]
|
263
|
-
#
|
264
|
-
# @api private
|
265
|
-
def configure!
|
266
|
-
@config = settings.new(Config.new(&@config_block)) if settings
|
267
|
-
end
|
268
|
-
|
269
|
-
# Return block that will be evaluated in the lifecycle context
|
270
|
-
#
|
271
|
-
# @return [Proc]
|
272
|
-
#
|
273
|
-
# @api private
|
274
|
-
def block
|
275
|
-
options.fetch(:block)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
module System
|
5
|
-
module Components
|
6
|
-
class Config
|
7
|
-
def self.new(&block)
|
8
|
-
config = super
|
9
|
-
yield(config) if block_given?
|
10
|
-
config
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@settings = {}
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_hash
|
18
|
-
@settings
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def method_missing(meth, value = nil)
|
24
|
-
if meth.to_s.end_with?("=")
|
25
|
-
@settings[meth.to_s.gsub("=", "").to_sym] = value
|
26
|
-
elsif @settings.key?(meth)
|
27
|
-
@settings[meth]
|
28
|
-
else
|
29
|
-
super
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/lib/dry/system/lifecycle.rb
DELETED
@@ -1,135 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "concurrent/map"
|
4
|
-
|
5
|
-
require "dry/system/settings"
|
6
|
-
|
7
|
-
module Dry
|
8
|
-
module System
|
9
|
-
# Lifecycle booting DSL
|
10
|
-
#
|
11
|
-
# Lifecycle objects are used in the boot files where you can register custom
|
12
|
-
# init/start/stop triggers
|
13
|
-
#
|
14
|
-
# @see [Container.finalize]
|
15
|
-
#
|
16
|
-
# @api private
|
17
|
-
class Lifecycle < BasicObject
|
18
|
-
attr_reader :container
|
19
|
-
|
20
|
-
attr_reader :statuses
|
21
|
-
|
22
|
-
attr_reader :triggers
|
23
|
-
|
24
|
-
attr_reader :opts
|
25
|
-
|
26
|
-
# @api private
|
27
|
-
def self.new(container, opts = {}, &block)
|
28
|
-
cache.fetch_or_store([container, opts, block].hash) do
|
29
|
-
super
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# @api private
|
34
|
-
def self.cache
|
35
|
-
@cache ||= ::Concurrent::Map.new
|
36
|
-
end
|
37
|
-
|
38
|
-
# @api private
|
39
|
-
def initialize(container, opts, &block)
|
40
|
-
@container = container
|
41
|
-
@settings = nil
|
42
|
-
@statuses = []
|
43
|
-
@triggers = {}
|
44
|
-
@opts = opts
|
45
|
-
instance_exec(target, &block)
|
46
|
-
end
|
47
|
-
|
48
|
-
# @api private
|
49
|
-
def call(*triggers)
|
50
|
-
triggers.each do |trigger|
|
51
|
-
unless statuses.include?(trigger)
|
52
|
-
__send__(trigger)
|
53
|
-
statuses << trigger
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# @api private
|
59
|
-
def settings(&block)
|
60
|
-
component.settings(&block)
|
61
|
-
end
|
62
|
-
|
63
|
-
# @api private
|
64
|
-
def configure(&block)
|
65
|
-
component.configure(&block)
|
66
|
-
end
|
67
|
-
|
68
|
-
# @api private
|
69
|
-
def config
|
70
|
-
component.config
|
71
|
-
end
|
72
|
-
|
73
|
-
# @api private
|
74
|
-
def init(&block)
|
75
|
-
trigger!(:init, &block)
|
76
|
-
end
|
77
|
-
|
78
|
-
# @api private
|
79
|
-
def start(&block)
|
80
|
-
trigger!(:start, &block)
|
81
|
-
end
|
82
|
-
|
83
|
-
# @api private
|
84
|
-
def stop(&block)
|
85
|
-
trigger!(:stop, &block)
|
86
|
-
end
|
87
|
-
|
88
|
-
# @api private
|
89
|
-
def use(*names)
|
90
|
-
names.each do |name|
|
91
|
-
target.start(name)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# @api private
|
96
|
-
def register(*args, &block)
|
97
|
-
container.register(*args, &block)
|
98
|
-
end
|
99
|
-
|
100
|
-
# @api private
|
101
|
-
def component
|
102
|
-
opts[:component]
|
103
|
-
end
|
104
|
-
|
105
|
-
# @api private
|
106
|
-
def target
|
107
|
-
component.container
|
108
|
-
end
|
109
|
-
|
110
|
-
private
|
111
|
-
|
112
|
-
# @api private
|
113
|
-
def trigger!(name, &block)
|
114
|
-
if triggers.key?(name)
|
115
|
-
triggers[name].(target)
|
116
|
-
elsif block
|
117
|
-
triggers[name] = block
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# @api private
|
122
|
-
def method_missing(meth, *args, &block)
|
123
|
-
if target.registered?(meth)
|
124
|
-
target[meth]
|
125
|
-
elsif container.key?(meth)
|
126
|
-
container[meth]
|
127
|
-
elsif ::Kernel.respond_to?(meth)
|
128
|
-
::Kernel.public_send(meth, *args, &block)
|
129
|
-
else
|
130
|
-
super
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
module System
|
5
|
-
class ProviderRegistry
|
6
|
-
include Enumerable
|
7
|
-
|
8
|
-
attr_reader :items
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@items = []
|
12
|
-
end
|
13
|
-
|
14
|
-
def each(&block)
|
15
|
-
items.each(&block)
|
16
|
-
end
|
17
|
-
|
18
|
-
def register(name, options)
|
19
|
-
items << Provider.new(name, options)
|
20
|
-
end
|
21
|
-
|
22
|
-
def [](name)
|
23
|
-
detect { |provider| provider.name == name }
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "dry/system/settings/file_parser"
|
4
|
-
|
5
|
-
module Dry
|
6
|
-
module System
|
7
|
-
module Settings
|
8
|
-
class FileLoader
|
9
|
-
def call(root, env)
|
10
|
-
files(root, env).reduce({}) do |hash, file|
|
11
|
-
hash.merge(parser.(file))
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def parser
|
18
|
-
@parser ||= FileParser.new
|
19
|
-
end
|
20
|
-
|
21
|
-
def files(root, env)
|
22
|
-
[
|
23
|
-
root.join(".env"),
|
24
|
-
root.join(".env.#{env}")
|
25
|
-
].compact
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dry
|
4
|
-
module System
|
5
|
-
module Settings
|
6
|
-
class FileParser
|
7
|
-
# Regex extracted from dotenv gem
|
8
|
-
# https://github.com/bkeepers/dotenv/blob/master/lib/dotenv/parser.rb#L14
|
9
|
-
LINE = /
|
10
|
-
\A
|
11
|
-
\s*
|
12
|
-
(?:export\s+)? # optional export
|
13
|
-
([\w\.]+) # key
|
14
|
-
(?:\s*=\s*|:\s+?) # separator
|
15
|
-
( # optional value begin
|
16
|
-
'(?:\'|[^'])*' # single quoted value
|
17
|
-
| # or
|
18
|
-
"(?:\"|[^"])*" # double quoted value
|
19
|
-
| # or
|
20
|
-
[^#\n]+ # unquoted value
|
21
|
-
)? # value end
|
22
|
-
\s*
|
23
|
-
(?:\#.*)? # optional comment
|
24
|
-
\z
|
25
|
-
/x.freeze
|
26
|
-
|
27
|
-
def call(file)
|
28
|
-
File.readlines(file).each_with_object({}) do |line, hash|
|
29
|
-
parse_line(line, hash)
|
30
|
-
end
|
31
|
-
rescue Errno::ENOENT
|
32
|
-
{}
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def parse_line(line, hash)
|
38
|
-
if (match = line.match(LINE))
|
39
|
-
key, value = match.captures
|
40
|
-
hash[key] = parse_value(value || "")
|
41
|
-
end
|
42
|
-
hash
|
43
|
-
end
|
44
|
-
|
45
|
-
def parse_value(value)
|
46
|
-
value.strip.sub(/\A(['"])(.*)\1\z/, '\2')
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
data/lib/dry/system/settings.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "dry/core/class_builder"
|
4
|
-
require "dry/types"
|
5
|
-
require "dry/struct"
|
6
|
-
|
7
|
-
require "dry/system/settings/file_loader"
|
8
|
-
require "dry/system/constants"
|
9
|
-
|
10
|
-
module Dry
|
11
|
-
module System
|
12
|
-
module Settings
|
13
|
-
class DSL < BasicObject
|
14
|
-
attr_reader :schema
|
15
|
-
|
16
|
-
def initialize(&block)
|
17
|
-
@schema = {}
|
18
|
-
instance_eval(&block)
|
19
|
-
end
|
20
|
-
|
21
|
-
def call
|
22
|
-
Core::ClassBuilder.new(name: "Configuration", parent: Configuration).call do |klass|
|
23
|
-
schema.each do |key, type|
|
24
|
-
klass.setting(key, type)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def key(name, type)
|
30
|
-
schema[name] = type
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class Configuration < Dry::Struct
|
35
|
-
def self.setting(*args)
|
36
|
-
attribute(*args)
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.init(root, env)
|
40
|
-
env_data = load_files(root, env)
|
41
|
-
attributes = {}
|
42
|
-
errors = {}
|
43
|
-
|
44
|
-
schema.each do |key|
|
45
|
-
value = ENV.fetch(key.name.to_s.upcase) { env_data[key.name.to_s.upcase] }
|
46
|
-
type_check = key.try(value || Undefined)
|
47
|
-
|
48
|
-
attributes[key.name] = value if value
|
49
|
-
errors[key] = type_check if type_check.failure?
|
50
|
-
end
|
51
|
-
|
52
|
-
raise InvalidSettingsError, errors unless errors.empty?
|
53
|
-
|
54
|
-
new(attributes)
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.load_files(root, env)
|
58
|
-
FileLoader.new.(root, env)
|
59
|
-
end
|
60
|
-
private_class_method :load_files
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|