dry-system 0.14.0 → 0.18.1

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: 147f6dffc6bc9ebb2773c136ba71789aa3d6ecc5330ea983b6943d257b8c14b8
4
- data.tar.gz: 3479389ed0a9ba38ecbb55dd940b70ac2b59f0fa1ddb6de210dc0cf0732338fa
3
+ metadata.gz: 7634be14c7b544e14f693cd158cd4cdf072e89ea5c947fafec45a0b31e58eb18
4
+ data.tar.gz: 34a55fe75bbae237be83dbcf534c0c13947a66788b146ee2ec12a387d3976e38
5
5
  SHA512:
6
- metadata.gz: 06255e42cbdbf4aaff57a811c6e7c386bf4f8014e672db919e8f2d6ad1ee5310ed1e3f8655dd20b854d3c5cd1bec767c2c6089ca4b84620c76143e454e4408ac
7
- data.tar.gz: 37b351fb70e5681d291b6ead72533ee5e5b5778bf86879136ad16fe20b144427e00af6b9a9cedc5010dda969125abe6dea6865eeb0926aecbe9dda450ed7e28a
6
+ metadata.gz: 1802eb1c676eb114126b37fd1ac9607a446317e209de17c62018f6a61bd9dd6770093e673671685c6a8d665ec53c7d7897141c3a7896c4d64ee3f5161c47bc30
7
+ data.tar.gz: '08fd659802b48151cf10598eb45fcb6555b8f9fa8b55340e6e9f393469608b965ecdefae143e79a880c394bcbede49b719f71f9bf6b96726af73921020121a35'
@@ -1,4 +1,82 @@
1
- ## unreleased
1
+ ## 0.18.1 2020-08-26
2
+
3
+
4
+ ### Fixed
5
+
6
+ - Made `Booter#boot_files` a public method again, since it was required by dry-rails (@timriley)
7
+
8
+
9
+ [Compare v0.18.0...v0.18.1](https://github.com/dry-rb/dry-system/compare/v0.18.0...v0.18.1)
10
+
11
+ ## 0.18.0 2020-08-24
12
+
13
+
14
+ ### Added
15
+
16
+ - New `bootable_dirs` setting on `Dry::System::Container`, which accepts paths to multiple directories for looking up bootable component files. (@timriley in PR #151)
17
+
18
+ For each entry in the `bootable_dirs` array, relative directories will be appended to the container's `root`, and absolute directories will be left unchanged.
19
+
20
+ When searching for bootable files, the first match will win, and any subsequent same-named files will not be loaded. In this way, the `bootable_dirs` act similarly to the `$PATH` in a shell environment.
21
+
22
+
23
+ [Compare v0.17.0...v0.18.0](https://github.com/dry-rb/dry-system/compare/v0.17.0...v0.18.0)
24
+
25
+ ## 0.17.0 2020-02-19
26
+
27
+
28
+ ### Fixed
29
+
30
+ - Works with the latest dry-configurable version (issue #141) (@solnic)
31
+
32
+ ### Changed
33
+
34
+ - Depends on dry-configurable `=> 0.11.1` now (@solnic)
35
+
36
+ [Compare v0.16.0...v0.17.0](https://github.com/dry-rb/dry-system/compare/v0.16.0...v0.17.0)
37
+
38
+ ## 0.16.0 2020-02-15
39
+
40
+
41
+ ### Changed
42
+
43
+ - Plugins can now define their own settings which are available in the `before(:configure)` hook (@solnic)
44
+ - Dependency on dry-configurable was bumped to `~> 0.11` (@solnic)
45
+
46
+ [Compare v0.15.0...v0.16.0](https://github.com/dry-rb/dry-system/compare/v0.15.0...v0.16.0)
47
+
48
+ ## 0.15.0 2020-01-30
49
+
50
+
51
+ ### Added
52
+
53
+ - New hook - `before(:configure)` which a plugin should use if it needs to declare new settings (@solnic)
54
+
55
+ ```ruby
56
+ # in your plugin code
57
+ before(:configure) { setting :my_new_setting }
58
+
59
+ after(:configure) { config.my_new_setting = "awesome" }
60
+ ```
61
+
62
+
63
+ ### Changed
64
+
65
+ - Centralize error definitions in `lib/dry/system/errors.rb` (@cgeorgii)
66
+ - All built-in plugins use `before(:configure)` now to declare their settings (@solnic)
67
+
68
+ [Compare v0.14.1...v0.15.0](https://github.com/dry-rb/dry-system/compare/v0.14.1...v0.15.0)
69
+
70
+ ## 0.14.1 2020-01-22
71
+
72
+
73
+ ### Changed
74
+
75
+ - Use `Kernel.require` explicitly to avoid issues with monkey-patched `require` from ActiveSupport (@solnic)
76
+
77
+ [Compare v0.14.0...v0.14.1](https://github.com/dry-rb/dry-system/compare/v0.14.0...v0.14.1)
78
+
79
+ ## 0.14.0 2020-01-21
2
80
 
3
81
 
4
82
  ### Fixed
@@ -7,7 +85,7 @@
7
85
  - Fail fast if auto_registrar config contains incorrect path (@cutalion)
8
86
 
9
87
 
10
- [Compare v0.13.2...master](https://github.com/dry-rb/dry-system/compare/v0.13.2...master)
88
+ [Compare v0.13.2...v0.14.0](https://github.com/dry-rb/dry-system/compare/v0.13.2...v0.14.0)
11
89
 
12
90
  ## 0.13.2 2019-12-28
13
91
 
@@ -16,6 +16,8 @@ Gem::Specification.new do |spec|
16
16
  spec.description = spec.summary
17
17
  spec.homepage = 'https://dry-rb.org/gems/dry-system'
18
18
  spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-system.gemspec", "lib/**/*"]
19
+ spec.bindir = 'bin'
20
+ spec.executables = []
19
21
  spec.require_paths = ['lib']
20
22
 
21
23
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'
@@ -23,12 +25,12 @@ Gem::Specification.new do |spec|
23
25
  spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-system'
24
26
  spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-system/issues'
25
27
 
26
- spec.required_ruby_version = '>= 2.4.0'
28
+ spec.required_ruby_version = ">= 2.4.0"
27
29
 
28
30
  # to update dependencies edit project.yml
29
31
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
30
32
  spec.add_runtime_dependency "dry-auto_inject", ">= 0.4.0"
31
- spec.add_runtime_dependency "dry-configurable", "~> 0.7"
33
+ spec.add_runtime_dependency "dry-configurable", "~> 0.11", ">= 0.11.1"
32
34
  spec.add_runtime_dependency "dry-container", "~> 0.7", ">= 0.7.2"
33
35
  spec.add_runtime_dependency "dry-core", "~> 0.3", ">= 0.3.1"
34
36
  spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system'
3
+ require "dry/system"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/provider'
4
- require 'dry/system/provider_registry'
3
+ require "dry/system/provider"
4
+ require "dry/system/provider_registry"
5
5
 
6
6
  module Dry
7
7
  module System
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/constants'
4
- require 'dry/system/magic_comments_parser'
5
- require 'dry/system/auto_registrar/configuration'
3
+ require "dry/system/constants"
4
+ require "dry/system/magic_comments_parser"
5
+ require "dry/system/auto_registrar/configuration"
6
6
 
7
7
  module Dry
8
8
  module System
@@ -67,8 +67,8 @@ module Dry
67
67
 
68
68
  # @api private
69
69
  def relative_path(dir, file_path)
70
- dir_root = root.join(dir.to_s.split('/')[0])
71
- file_path.to_s.sub("#{dir_root}/", '').sub(RB_EXT, EMPTY_STRING)
70
+ dir_root = root.join(dir.to_s.split("/")[0])
71
+ file_path.to_s.sub("#{dir_root}/", "").sub(RB_EXT, EMPTY_STRING)
72
72
  end
73
73
 
74
74
  # @api private
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/components/bootable'
4
- require 'dry/system/errors'
5
- require 'dry/system/constants'
6
- require 'dry/system/lifecycle'
7
- require 'dry/system/booter/component_registry'
3
+ require "dry/system/components/bootable"
4
+ require "dry/system/errors"
5
+ require "dry/system/constants"
6
+ require "dry/system/lifecycle"
7
+ require "dry/system/booter/component_registry"
8
+ require "pathname"
8
9
 
9
10
  module Dry
10
11
  module System
@@ -16,29 +17,22 @@ module Dry
16
17
  #
17
18
  # @api private
18
19
  class Booter
19
- attr_reader :path
20
+ attr_reader :paths
20
21
 
21
22
  attr_reader :booted
22
23
 
23
24
  attr_reader :components
24
25
 
25
26
  # @api private
26
- def initialize(path)
27
- @path = path
27
+ def initialize(paths)
28
+ @paths = paths
28
29
  @booted = []
29
30
  @components = ComponentRegistry.new
30
31
  end
31
32
 
32
33
  # @api private
33
34
  def bootable?(component)
34
- boot_file(component).exist?
35
- end
36
-
37
- # @api private
38
- def boot_file(name)
39
- name = name.respond_to?(:root_key) ? name.root_key.to_s : name
40
-
41
- path.join("#{name}#{RB_EXT}")
35
+ !boot_file(component).nil?
42
36
  end
43
37
 
44
38
  # @api private
@@ -47,15 +41,6 @@ module Dry
47
41
  self
48
42
  end
49
43
 
50
- # @api private
51
- def load_component(path)
52
- identifier = Pathname(path).basename(RB_EXT).to_s.to_sym
53
-
54
- require path unless components.exists?(identifier)
55
-
56
- self
57
- end
58
-
59
44
  # @api private
60
45
  def finalize!
61
46
  boot_files.each do |path|
@@ -120,7 +105,7 @@ module Dry
120
105
  # @api private
121
106
  def call(name_or_component)
122
107
  with_component(name_or_component) do |component|
123
- raise ComponentFileMismatchError.new(name, registered_booted_keys) unless component
108
+ raise ComponentFileMismatchError, name unless component
124
109
 
125
110
  yield(component) if block_given?
126
111
 
@@ -129,11 +114,30 @@ module Dry
129
114
  end
130
115
 
131
116
  # @api private
132
- def lifecycle_container(container)
133
- LifecycleContainer.new(container)
117
+ def boot_dependency(component)
118
+ boot_file = boot_file(component)
119
+
120
+ start(boot_file.basename(".*").to_s.to_sym) if boot_file
134
121
  end
135
122
 
136
123
  # @api private
124
+ def boot_files
125
+ @boot_files ||= paths.each_with_object([[], []]) { |path, (boot_files, loaded)|
126
+ files = Dir["#{path}/#{RB_GLOB}"].sort
127
+
128
+ files.each do |file|
129
+ basename = File.basename(file)
130
+
131
+ unless loaded.include?(basename)
132
+ boot_files << Pathname(file)
133
+ loaded << basename
134
+ end
135
+ end
136
+ }.first
137
+ end
138
+
139
+ private
140
+
137
141
  def with_component(id_or_component)
138
142
  component =
139
143
  case id_or_component
@@ -149,24 +153,28 @@ module Dry
149
153
  yield(component)
150
154
  end
151
155
 
152
- # @api private
153
- def require_boot_file(identifier)
154
- boot_file = boot_files.detect { |path|
155
- Pathname(path).basename(RB_EXT).to_s == identifier.to_s
156
- }
156
+ def load_component(path)
157
+ identifier = Pathname(path).basename(RB_EXT).to_s.to_sym
158
+
159
+ Kernel.require path unless components.exists?(identifier)
157
160
 
158
- require boot_file if boot_file
161
+ self
159
162
  end
160
163
 
161
- # @api private
162
- def boot_files
163
- ::Dir["#{path}/**/#{RB_GLOB}"].sort
164
+ def boot_file(name)
165
+ name = name.respond_to?(:root_key) ? name.root_key.to_s : name
166
+
167
+ find_boot_file(name)
164
168
  end
165
169
 
166
- # @api private
167
- def boot_dependency(component)
168
- boot_file = boot_file(component)
169
- start(boot_file.basename('.*').to_s.to_sym) if boot_file.exist?
170
+ def require_boot_file(identifier)
171
+ boot_file = find_boot_file(identifier)
172
+
173
+ Kernel.require boot_file if boot_file
174
+ end
175
+
176
+ def find_boot_file(name)
177
+ boot_files.detect { |file| File.basename(file, RB_EXT) == name.to_s }
170
178
  end
171
179
  end
172
180
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/map'
3
+ require "concurrent/map"
4
4
 
5
- require 'dry-equalizer'
6
- require 'dry/inflector'
7
- require 'dry/system/loader'
8
- require 'dry/system/errors'
9
- require 'dry/system/constants'
5
+ require "dry-equalizer"
6
+ require "dry/inflector"
7
+ require "dry/system/loader"
8
+ require "dry/system/errors"
9
+ require "dry/system/constants"
10
10
 
11
11
  module Dry
12
12
  module System
@@ -118,7 +118,7 @@ module Dry
118
118
  ruby2_keywords(:instance) if respond_to?(:ruby2_keywords, true)
119
119
 
120
120
  # @api private
121
- def boot?
121
+ def bootable?
122
122
  false
123
123
  end
124
124
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system'
3
+ require "dry/system"
4
4
 
5
5
  Dry::System.register_provider(
6
6
  :system,
7
- boot_path: Pathname(__dir__).join('system_components').realpath
7
+ boot_path: Pathname(__dir__).join("system_components").realpath
8
8
  )
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/lifecycle'
4
- require 'dry/system/settings'
5
- require 'dry/system/components/config'
6
- require 'dry/system/constants'
3
+ require "dry/system/lifecycle"
4
+ require "dry/system/settings"
5
+ require "dry/system/components/config"
6
+ require "dry/system/constants"
7
7
 
8
8
  module Dry
9
9
  module System
@@ -70,7 +70,7 @@ module Dry
70
70
  @config = nil
71
71
  @config_block = nil
72
72
  @identifier = identifier
73
- @triggers = { before: TRIGGER_MAP.dup, after: TRIGGER_MAP.dup }
73
+ @triggers = {before: TRIGGER_MAP.dup, after: TRIGGER_MAP.dup}
74
74
  @options = block ? options.merge(block: block) : options
75
75
  @namespace = options[:namespace]
76
76
  finalize = options[:finalize] || DEFAULT_FINALIZE
@@ -229,38 +229,10 @@ module Dry
229
229
  # @return [TrueClass]
230
230
  #
231
231
  # @api private
232
- def boot?
232
+ def bootable?
233
233
  true
234
234
  end
235
235
 
236
- # Return path to component's boot file
237
- #
238
- # @return [String]
239
- #
240
- # @api private
241
- def boot_file
242
- container_boot_files
243
- .detect { |path| Pathname(path).basename(RB_EXT).to_s == identifier.to_s }
244
- end
245
-
246
- # Return path to boot dir
247
- #
248
- # @return [String]
249
- #
250
- # @api private
251
- def boot_path
252
- container.boot_path
253
- end
254
-
255
- # Return all boot files defined under container's boot path
256
- #
257
- # @return [String]
258
- #
259
- # @api private
260
- def container_boot_files
261
- ::Dir[container.boot_path.join("**/#{RB_GLOB}")].sort
262
- end
263
-
264
236
  private
265
237
 
266
238
  # Return lifecycle object used for this component
@@ -21,8 +21,8 @@ module Dry
21
21
  private
22
22
 
23
23
  def method_missing(meth, value = nil)
24
- if meth.to_s.end_with?('=')
25
- @settings[meth.to_s.gsub('=', '').to_sym] = value
24
+ if meth.to_s.end_with?("=")
25
+ @settings[meth.to_s.gsub("=", "").to_sym] = value
26
26
  elsif @settings.key?(meth)
27
27
  @settings[meth]
28
28
  else
@@ -1,46 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/constants'
3
+ require "dry/core/constants"
4
4
 
5
5
  module Dry
6
6
  module System
7
7
  include Dry::Core::Constants
8
8
 
9
- RB_EXT = '.rb'
10
- RB_GLOB = '*.rb'
11
- PATH_SEPARATOR = '/'
12
- DEFAULT_SEPARATOR = '.'
9
+ RB_EXT = ".rb"
10
+ RB_GLOB = "*.rb"
11
+ PATH_SEPARATOR = "/"
12
+ DEFAULT_SEPARATOR = "."
13
13
  WORD_REGEX = /\w+/.freeze
14
-
15
- ComponentsDirMissing = Class.new(StandardError)
16
- DuplicatedComponentKeyError = Class.new(ArgumentError)
17
- InvalidSettingsError = Class.new(ArgumentError) do
18
- # @api private
19
- def initialize(attributes)
20
- message = <<~STR
21
- Could not initialize settings. The following settings were invalid:
22
-
23
- #{attributes_errors(attributes).join("\n")}
24
- STR
25
- super(message)
26
- end
27
-
28
- private
29
-
30
- def attributes_errors(attributes)
31
- attributes.map { |key, error| "#{key.name}: #{error}" }
32
- end
33
- end
34
-
35
- # Exception raise when a plugin dependency failed to load
36
- #
37
- # @api public
38
- PluginDependencyMissing = Class.new(StandardError) do
39
- # @api private
40
- def initialize(plugin, message, gem = nil)
41
- details = gem ? "#{message} - add #{gem} to your Gemfile" : message
42
- super("dry-system plugin #{plugin.inspect} failed to load its dependencies: #{details}")
43
- end
44
- end
45
14
  end
46
15
  end
@@ -1,24 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
-
5
- require 'dry-auto_inject'
6
- require 'dry-configurable'
7
- require 'dry-container'
8
- require 'dry/inflector'
9
-
10
- require 'dry/core/deprecations'
11
-
12
- require 'dry/system'
13
- require 'dry/system/errors'
14
- require 'dry/system/loader'
15
- require 'dry/system/booter'
16
- require 'dry/system/auto_registrar'
17
- require 'dry/system/manual_registrar'
18
- require 'dry/system/importer'
19
- require 'dry/system/component'
20
- require 'dry/system/constants'
21
- require 'dry/system/plugins'
3
+ require "pathname"
4
+
5
+ require "dry-auto_inject"
6
+ require "dry-configurable"
7
+ require "dry-container"
8
+ require "dry/inflector"
9
+
10
+ require "dry/core/deprecations"
11
+
12
+ require "dry/system"
13
+ require "dry/system/errors"
14
+ require "dry/system/loader"
15
+ require "dry/system/booter"
16
+ require "dry/system/auto_registrar"
17
+ require "dry/system/manual_registrar"
18
+ require "dry/system/importer"
19
+ require "dry/system/component"
20
+ require "dry/system/constants"
21
+ require "dry/system/plugins"
22
22
 
23
23
  module Dry
24
24
  module System
@@ -48,8 +48,6 @@ module Dry
48
48
  #
49
49
  # * `:name` - a unique container identifier
50
50
  # * `:root` - a system root directory (defaults to `pwd`)
51
- # * `:system_dir` - directory name relative to root, where bootable components
52
- # can be defined in `boot` dir this defaults to `system`
53
51
  #
54
52
  # @example
55
53
  # class MyApp < Dry::System::Container
@@ -75,8 +73,9 @@ module Dry
75
73
  setting :name
76
74
  setting :default_namespace
77
75
  setting(:root, Pathname.pwd.freeze) { |path| Pathname(path) }
78
- setting :system_dir, 'system'
79
- setting :registrations_dir, 'container'
76
+ setting :system_dir, "system"
77
+ setting :bootable_dirs, ["system/boot"]
78
+ setting :registrations_dir, "container"
80
79
  setting :auto_register, []
81
80
  setting :inflector, Dry::Inflector.new
82
81
  setting :loader, Dry::System::Loader
@@ -95,7 +94,19 @@ module Dry
95
94
  end
96
95
  end
97
96
 
98
- extend Dry::Core::Deprecations['Dry::System::Container']
97
+ extend Dry::Core::Deprecations["Dry::System::Container"]
98
+
99
+ # Define a new configuration setting
100
+ #
101
+ # @see https://dry-rb.org/gems/dry-configurable
102
+ #
103
+ # @api public
104
+ def setting(name, *args, &block)
105
+ super(name, *args, &block)
106
+ # TODO: dry-configurable needs a public API for this
107
+ config._settings << _settings[name]
108
+ self
109
+ end
99
110
 
100
111
  # Configures the container
101
112
  #
@@ -112,9 +123,10 @@ module Dry
112
123
  #
113
124
  # @api public
114
125
  def configure(&block)
126
+ hooks[:before_configure].each { |hook| instance_eval(&hook) }
115
127
  super(&block)
116
128
  load_paths!(config.system_dir)
117
- hooks[:configure].each { |hook| instance_eval(&hook) }
129
+ hooks[:after_configure].each { |hook| instance_eval(&hook) }
118
130
  self
119
131
  end
120
132
 
@@ -157,9 +169,10 @@ module Dry
157
169
 
158
170
  # Registers finalization function for a bootable component
159
171
  #
160
- # By convention, boot files for components should be placed in
161
- # `%{system_dir}/boot` and they will be loaded on demand when components
162
- # are loaded in isolation, or during finalization process.
172
+ # By convention, boot files for components should be placed in a
173
+ # `bootable_dirs` entry and they will be loaded on demand when
174
+ # components are loaded in isolation, or during the finalization
175
+ # process.
163
176
  #
164
177
  # @example
165
178
  # # system/container.rb
@@ -242,30 +255,24 @@ module Dry
242
255
  boot_local(name, **opts, &block)
243
256
  end
244
257
 
258
+ booter.register_component component
259
+
245
260
  components[name] = component
246
261
  end
247
262
  deprecate :finalize, :boot
248
263
 
249
264
  # @api private
250
265
  def boot_external(identifier, from:, key: nil, namespace: nil, &block)
251
- component = System.providers[from].component(
266
+ System.providers[from].component(
252
267
  identifier, key: key, namespace: namespace, finalize: block, container: self
253
268
  )
254
-
255
- booter.register_component(component)
256
-
257
- component
258
269
  end
259
270
 
260
271
  # @api private
261
272
  def boot_local(identifier, namespace: nil, &block)
262
- component = Components::Bootable.new(
273
+ Components::Bootable.new(
263
274
  identifier, container: self, namespace: namespace, &block
264
275
  )
265
-
266
- booter.register_component(component)
267
-
268
- component
269
276
  end
270
277
 
271
278
  # Return if a container was finalized
@@ -475,7 +482,7 @@ module Dry
475
482
  # @param options [Hash] injector options
476
483
  #
477
484
  # @api public
478
- def injector(options = { strategies: strategies })
485
+ def injector(options = {strategies: strategies})
479
486
  Dry::AutoInject(self, options)
480
487
  end
481
488
 
@@ -493,9 +500,9 @@ module Dry
493
500
  # @api public
494
501
  def require_from_root(*paths)
495
502
  paths.flat_map { |path|
496
- path.to_s.include?('*') ? ::Dir[root.join(path)].sort : root.join(path)
503
+ path.to_s.include?("*") ? ::Dir[root.join(path)].sort : root.join(path)
497
504
  }.each { |path|
498
- require path.to_s
505
+ Kernel.require path.to_s
499
506
  }
500
507
  end
501
508
 
@@ -556,12 +563,20 @@ module Dry
556
563
 
557
564
  # @api private
558
565
  def booter
559
- @booter ||= config.booter.new(boot_path)
566
+ @booter ||= config.booter.new(boot_paths)
560
567
  end
561
568
 
562
569
  # @api private
563
- def boot_path
564
- root.join("#{config.system_dir}/boot")
570
+ def boot_paths
571
+ config.bootable_dirs.map { |dir|
572
+ dir = Pathname(dir)
573
+
574
+ if dir.relative?
575
+ root.join(dir)
576
+ else
577
+ dir
578
+ end
579
+ }
565
580
  end
566
581
 
567
582
  # @api private
@@ -622,13 +637,13 @@ module Dry
622
637
  return self if registered?(key)
623
638
 
624
639
  component(key).tap do |component|
625
- if component.boot?
640
+ if component.bootable?
626
641
  booter.start(component)
627
642
  else
628
643
  root_key = component.root_key
629
644
 
630
- if (bootable_dep = component(root_key)).boot?
631
- booter.start(bootable_dep)
645
+ if (root_bootable = component(root_key)).bootable?
646
+ booter.start(root_bootable)
632
647
  elsif importer.key?(root_key)
633
648
  load_imported_component(component.namespaced(root_key))
634
649
  end
@@ -642,7 +657,11 @@ module Dry
642
657
 
643
658
  # @api private
644
659
  def after(event, &block)
645
- hooks[event] << block
660
+ hooks[:"after_#{event}"] << block
661
+ end
662
+
663
+ def before(event, &block)
664
+ hooks[:"before_#{event}"] << block
646
665
  end
647
666
 
648
667
  # @api private
@@ -17,12 +17,8 @@ module Dry
17
17
  # @api public
18
18
  ComponentFileMismatchError = Class.new(StandardError) do
19
19
  def initialize(component)
20
- path = component.boot_path
21
- files = component.container_boot_files
22
-
23
20
  super(<<-STR)
24
- Boot file for component #{component.identifier.inspect} not found.
25
- Container boot files under #{path}: #{files.inspect}")
21
+ Bootable component #{component.identifier.inspect} not found
26
22
  STR
27
23
  end
28
24
  end
@@ -84,5 +80,36 @@ module Dry
84
80
  super("Plugin #{plugin_name.inspect} does not exist")
85
81
  end
86
82
  end
83
+
84
+ ComponentsDirMissing = Class.new(StandardError)
85
+ DuplicatedComponentKeyError = Class.new(ArgumentError)
86
+ InvalidSettingsError = Class.new(ArgumentError) do
87
+ # @api private
88
+ def initialize(attributes)
89
+ message = <<~STR
90
+ Could not initialize settings. The following settings were invalid:
91
+
92
+ #{attributes_errors(attributes).join("\n")}
93
+ STR
94
+ super(message)
95
+ end
96
+
97
+ private
98
+
99
+ def attributes_errors(attributes)
100
+ attributes.map { |key, error| "#{key.name}: #{error}" }
101
+ end
102
+ end
103
+
104
+ # Exception raise when a plugin dependency failed to load
105
+ #
106
+ # @api public
107
+ PluginDependencyMissing = Class.new(StandardError) do
108
+ # @api private
109
+ def initialize(plugin, message, gem = nil)
110
+ details = gem ? "#{message} - add #{gem} to your Gemfile" : message
111
+ super("dry-system plugin #{plugin.inspect} failed to load its dependencies: #{details}")
112
+ end
113
+ end
87
114
  end
88
115
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/map'
3
+ require "concurrent/map"
4
4
 
5
- require 'dry/system/settings'
5
+ require "dry/system/settings"
6
6
 
7
7
  module Dry
8
8
  module System
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/inflector'
3
+ require "dry/inflector"
4
4
 
5
5
  module Dry
6
6
  module System
@@ -7,8 +7,8 @@ module Dry
7
7
  COMMENT_RE = /^#\s+(?<name>[A-Za-z]{1}[A-Za-z0-9_]+):\s+(?<value>.+?)$/.freeze
8
8
 
9
9
  COERCIONS = {
10
- 'true' => true,
11
- 'false' => false
10
+ "true" => true,
11
+ "false" => false
12
12
  }.freeze
13
13
 
14
14
  def self.call(file_name)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/constants'
3
+ require "dry/system/constants"
4
4
 
5
5
  module Dry
6
6
  module System
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/constants'
3
+ require "dry/system/constants"
4
4
 
5
5
  module Dry
6
6
  module System
@@ -40,7 +40,7 @@ module Dry
40
40
 
41
41
  # @api private
42
42
  def load_dependency(dependency, gem)
43
- require dependency
43
+ Kernel.require dependency
44
44
  Plugins.loaded_dependencies << dependency.to_s
45
45
  rescue LoadError => e
46
46
  raise PluginDependencyMissing.new(name, e.message, gem)
@@ -94,6 +94,7 @@ module Dry
94
94
  # @api public
95
95
  def use(name, options = {})
96
96
  return self if enabled_plugins.include?(name)
97
+
97
98
  raise PluginNotFoundError, name unless (plugin = Plugins.registry[name])
98
99
 
99
100
  plugin.load_dependencies
@@ -115,22 +116,22 @@ module Dry
115
116
  @enabled_plugins ||= []
116
117
  end
117
118
 
118
- require 'dry/system/plugins/bootsnap'
119
+ require "dry/system/plugins/bootsnap"
119
120
  register(:bootsnap, Plugins::Bootsnap)
120
121
 
121
- require 'dry/system/plugins/logging'
122
+ require "dry/system/plugins/logging"
122
123
  register(:logging, Plugins::Logging)
123
124
 
124
- require 'dry/system/plugins/env'
125
+ require "dry/system/plugins/env"
125
126
  register(:env, Plugins::Env)
126
127
 
127
- require 'dry/system/plugins/notifications'
128
+ require "dry/system/plugins/notifications"
128
129
  register(:notifications, Plugins::Notifications)
129
130
 
130
- require 'dry/system/plugins/monitoring'
131
+ require "dry/system/plugins/monitoring"
131
132
  register(:monitoring, Plugins::Monitoring)
132
133
 
133
- require 'dry/system/plugins/dependency_graph'
134
+ require "dry/system/plugins/dependency_graph"
134
135
  register(:dependency_graph, Plugins::DependencyGraph)
135
136
  end
136
137
  end
@@ -16,13 +16,13 @@ module Dry
16
16
  def self.extended(system)
17
17
  super
18
18
  system.use(:env)
19
- system.setting :bootsnap, DEFAULT_OPTIONS
19
+ system.before(:configure) { setting :bootsnap, DEFAULT_OPTIONS }
20
20
  system.after(:configure, &:setup_bootsnap)
21
21
  end
22
22
 
23
23
  # @api private
24
24
  def self.dependencies
25
- { bootsnap: 'bootsnap' }
25
+ {bootsnap: "bootsnap"}
26
26
  end
27
27
 
28
28
  # Set up bootsnap for faster booting
@@ -31,12 +31,12 @@ module Dry
31
31
  def setup_bootsnap
32
32
  return unless bootsnap_available?
33
33
 
34
- ::Bootsnap.setup(config.bootsnap.merge(cache_dir: root.join('tmp/cache').to_s))
34
+ ::Bootsnap.setup(config.bootsnap.merge(cache_dir: root.join("tmp/cache").to_s))
35
35
  end
36
36
 
37
37
  # @api private
38
38
  def bootsnap_available?
39
- RUBY_ENGINE == 'ruby' && RUBY_VERSION >= '2.3.0' && RUBY_VERSION < '2.5.0'
39
+ RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.3.0" && RUBY_VERSION < "2.5.0"
40
40
  end
41
41
  end
42
42
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/constants'
4
- require 'dry/system/plugins/dependency_graph/strategies'
3
+ require "dry/system/constants"
4
+ require "dry/system/plugins/dependency_graph/strategies"
5
5
 
6
6
  module Dry
7
7
  module System
@@ -14,7 +14,9 @@ module Dry
14
14
 
15
15
  system.use(:notifications)
16
16
 
17
- system.setting :ignored_dependencies, []
17
+ system.before(:configure) do
18
+ setting :ignored_dependencies, []
19
+ end
18
20
 
19
21
  system.after(:configure) do
20
22
  self[:notifications].register_event(:resolved_dependency)
@@ -26,7 +28,7 @@ module Dry
26
28
 
27
29
  # @api private
28
30
  def self.dependencies
29
- { 'dry-events': 'dry/events/publisher' }
31
+ {'dry-events': "dry/events/publisher"}
30
32
  end
31
33
 
32
34
  # @api private
@@ -14,7 +14,7 @@ module Dry
14
14
 
15
15
  # @api private
16
16
  def define_initialize(klass)
17
- @container['notifications'].instrument(
17
+ @container["notifications"].instrument(
18
18
  :resolved_dependency, dependency_map: dependency_map.to_h, target_class: klass
19
19
  )
20
20
  super(klass)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
3
+ require "logger"
4
4
 
5
5
  module Dry
6
6
  module System
@@ -8,16 +8,18 @@ module Dry
8
8
  module Logging
9
9
  # @api private
10
10
  def self.extended(system)
11
- system.setting :logger, reader: true
11
+ system.before(:configure) do
12
+ setting :logger, reader: true
12
13
 
13
- system.setting :log_dir, 'log'
14
+ setting :log_dir, "log"
14
15
 
15
- system.setting :log_levels,
16
- development: Logger::DEBUG,
17
- test: Logger::DEBUG,
18
- production: Logger::ERROR
16
+ setting :log_levels,
17
+ development: Logger::DEBUG,
18
+ test: Logger::DEBUG,
19
+ production: Logger::ERROR
19
20
 
20
- system.setting :logger_class, ::Logger, reader: true
21
+ setting :logger_class, ::Logger, reader: true
22
+ end
21
23
 
22
24
  system.after(:configure, &:register_logger)
23
25
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/constants'
4
- require 'dry/system/plugins/monitoring/proxy'
3
+ require "dry/system/constants"
4
+ require "dry/system/plugins/monitoring/proxy"
5
5
 
6
6
  module Dry
7
7
  module System
@@ -21,7 +21,7 @@ module Dry
21
21
 
22
22
  # @api private
23
23
  def self.dependencies
24
- { 'dry-events': 'dry/events/publisher' }
24
+ {'dry-events': "dry/events/publisher"}
25
25
  end
26
26
 
27
27
  # @api private
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'delegate'
3
+ require "delegate"
4
4
 
5
5
  module Dry
6
6
  module System
@@ -9,7 +9,7 @@ module Dry
9
9
  # @api private
10
10
  class Proxy < SimpleDelegator
11
11
  # @api private
12
- def self.for(target, key:, methods: [], &block)
12
+ def self.for(target, key:, methods: [])
13
13
  monitored_methods =
14
14
  if methods.empty?
15
15
  target.public_methods - Object.public_instance_methods
@@ -30,7 +30,7 @@ module Dry
30
30
  monitored_methods.each do |meth|
31
31
  define_method(meth) do |*args, &block|
32
32
  object = __getobj__
33
- opts = { target: key, object: object, method: meth, args: args }
33
+ opts = {target: key, object: object, method: meth, args: args}
34
34
 
35
35
  __notifications__.instrument(:monitoring, opts) do
36
36
  object.public_send(meth, *args, &block)
@@ -12,7 +12,7 @@ module Dry
12
12
 
13
13
  # @api private
14
14
  def self.dependencies
15
- { 'dry-monitor': 'dry/monitor/notifications' }
15
+ {'dry-monitor': "dry/monitor/notifications"}
16
16
  end
17
17
 
18
18
  # @api private
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent/map'
4
- require 'dry/system/constants'
5
- require 'dry/system/components/bootable'
3
+ require "concurrent/map"
4
+ require "dry/system/constants"
5
+ require "dry/system/components/bootable"
6
6
 
7
7
  module Dry
8
8
  module System
@@ -41,7 +41,7 @@ module Dry
41
41
  end
42
42
 
43
43
  def load_components
44
- boot_files.each { |f| require f }
44
+ boot_files.each { |f| Kernel.require f }
45
45
  freeze
46
46
  self
47
47
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/core/class_builder'
4
- require 'dry/types'
5
- require 'dry/struct'
3
+ require "dry/core/class_builder"
4
+ require "dry/types"
5
+ require "dry/struct"
6
6
 
7
- require 'dry/system/settings/file_loader'
8
- require 'dry/system/constants'
7
+ require "dry/system/settings/file_loader"
8
+ require "dry/system/constants"
9
9
 
10
10
  module Dry
11
11
  module System
@@ -22,7 +22,7 @@ module Dry
22
22
  end
23
23
 
24
24
  def call
25
- Core::ClassBuilder.new(name: 'Configuration', parent: Configuration).call do |klass|
25
+ Core::ClassBuilder.new(name: "Configuration", parent: Configuration).call do |klass|
26
26
  schema.each do |key, type|
27
27
  klass.setting(key, type)
28
28
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/system/settings/file_parser'
3
+ require "dry/system/settings/file_parser"
4
4
 
5
5
  module Dry
6
6
  module System
@@ -20,7 +20,7 @@ module Dry
20
20
 
21
21
  def files(root, env)
22
22
  [
23
- root.join('.env'),
23
+ root.join(".env"),
24
24
  root.join(".env.#{env}")
25
25
  ].compact
26
26
  end
@@ -37,7 +37,7 @@ module Dry
37
37
  def parse_line(line, hash)
38
38
  if (match = line.match(LINE))
39
39
  key, value = match.captures
40
- hash[key] = parse_value(value || '')
40
+ hash[key] = parse_value(value || "")
41
41
  end
42
42
  hash
43
43
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/container/stub'
3
+ require "dry/container/stub"
4
4
 
5
5
  module Dry
6
6
  module System
@@ -2,7 +2,7 @@
2
2
 
3
3
  Dry::System.register_component(:settings, provider: :system) do
4
4
  init do
5
- require 'dry/system/settings'
5
+ require "dry/system/settings"
6
6
  end
7
7
 
8
8
  start do
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module System
5
- VERSION = '0.14.0'
5
+ VERSION = "0.18.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-system
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.18.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-21 00:00:00.000000000 Z
11
+ date: 2020-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -44,14 +44,20 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.7'
47
+ version: '0.11'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 0.11.1
48
51
  type: :runtime
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
51
54
  requirements:
52
55
  - - "~>"
53
56
  - !ruby/object:Gem::Version
54
- version: '0.7'
57
+ version: '0.11'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 0.11.1
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: dry-container
57
63
  requirement: !ruby/object:Gem::Requirement