dry-system 0.14.0 → 0.18.1

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: 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