dry-system 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c0977524fa33277150e8611a851c557461c14357e1a5d9c1f1929c283f3c9b3
4
- data.tar.gz: 12de5eaa25ede9f5f959cd77e2af8f1d3b4b287aaebea1554c2915433743c290
3
+ metadata.gz: 2ce0d3b9c3094e2e7d1b20907a31107d6329221e6213839708f8cc7bac1321bd
4
+ data.tar.gz: 2e28bfe4758cace04f1978c2b17fa138921915d5db0b894796772fa428e12549
5
5
  SHA512:
6
- metadata.gz: 6976cb749c98ed536c5fb3e6ca67674aee2707b40cd5d196b6b82472edadfa10877bebac77631b0ebcc5fabe008514ed60e7d9be17ccd1343e8967836f319a11
7
- data.tar.gz: fd894f982bf214dac3ccfa0de1d4fd7f95beeea1f91234cd2868dfab4687b76ea831c153b429d8ba9bd9f04bcb46dd2815f87a7829e6b347b2d8992cf0ebd478
6
+ metadata.gz: 33e7e5e5cccf47481498a95c8dc37fdb282ab9005c595f4db30b05f84c842d5144ba7cfa0f3a15f895212dbb0034554f36d16649d004bf54eebc99dca70d53d1
7
+ data.tar.gz: dc441f94a5d1506e7c7bc4afd9e8ebfd43d43e7956af09e2a793df6d1b02b409ac8eb0252183cae6c388969f2e33b02522675794c1aa4c340f6c52efa0ad7344
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
2
 
3
+ ## 0.22.0 2022-01-06
4
+
5
+
6
+ ### Added
7
+
8
+ - Expanded public interfaces for `Dry::System::Config::ComponentDirs` and `Dry::System::Config::Namespaces` to better support programmatic construction and inspection of these configs (@timriley in #195)
9
+
10
+ ### Changed
11
+
12
+ - Deprecated `Dry::System::Config::Namespaces#root` as the way to add and configure a root namespace. Use `#add_root` instead (@timriley in #195)
13
+ - Allow bootsnap plugin to use bootsnap on Ruby versions up to 3.0 (pusewicz in #196)
14
+
15
+ [Compare v0.21.0...v0.22.0](https://github.com/dry-rb/dry-system/compare/v0.21.0...v0.22.0)
16
+
3
17
  ## 0.21.0 2021-11-01
4
18
 
5
19
 
@@ -29,6 +43,7 @@
29
43
  (@timriley in #181)
30
44
  - `Dry::System::Component#path` has been removed and replaced by `Component#require_path` and `Component#const_path` (@timriley in #181)
31
45
  - Unused `Dry::System::FileNotFoundError` and `Dry::System::InvalidComponentIdentifierTypeError` errors have been removed (@timriley in #194)
46
+ - Allow bootsnap for Rubies up to 3.0.x (via #196) (@pusewicz)
32
47
 
33
48
  [Compare v0.20.0...v0.21.0](https://github.com/dry-rb/dry-system/compare/v0.20.0...v0.21.0)
34
49
 
data/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  # dry-system [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
9
9
 
10
10
  [![Gem Version](https://badge.fury.io/rb/dry-system.svg)][gem]
11
- [![CI Status](https://github.com/dry-rb/dry-system/workflows/CI/badge.svg)][actions]
11
+ [![CI Status](https://github.com/dry-rb/dry-system/workflows/ci/badge.svg)][actions]
12
12
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/3a0e30d0ae2542c7ba047ba5f923c0bb)][codacy]
13
13
  [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/3a0e30d0ae2542c7ba047ba5f923c0bb)][codacy]
14
14
  [![Inline docs](http://inch-ci.org/github/dry-rb/dry-system.svg?branch=master)][inchpages]
@@ -9,6 +9,7 @@ require_relative "namespaces"
9
9
  module Dry
10
10
  module System
11
11
  module Config
12
+ # @api public
12
13
  class ComponentDir
13
14
  include Dry::Configurable
14
15
 
@@ -37,6 +38,7 @@ module Dry
37
38
  #
38
39
  # @see auto_register
39
40
  # @see Component
41
+ # @api public
40
42
  #
41
43
  # @!method auto_register
42
44
  #
@@ -45,6 +47,7 @@ module Dry
45
47
  # @return [Boolean, Proc] the configured policy
46
48
  #
47
49
  # @see auto_register=
50
+ # @api public
48
51
  setting :auto_register, default: true
49
52
 
50
53
  # @!method add_to_load_path=(policy)
@@ -60,6 +63,7 @@ module Dry
60
63
  #
61
64
  # @see add_to_load_path
62
65
  # @see Container.configure
66
+ # @api public
63
67
  #
64
68
  # @!method add_to_load_path
65
69
  #
@@ -68,6 +72,7 @@ module Dry
68
72
  # @return [Boolean]
69
73
  #
70
74
  # @see add_to_load_path=
75
+ # @api public
71
76
  setting :add_to_load_path, default: true
72
77
 
73
78
  # @!method loader=(loader)
@@ -85,6 +90,7 @@ module Dry
85
90
  # @see loader
86
91
  # @see Loader
87
92
  # @see Loader::Autoloading
93
+ # @api public
88
94
  #
89
95
  # @!method loader
90
96
  #
@@ -93,6 +99,7 @@ module Dry
93
99
  # @return [#call]
94
100
  #
95
101
  # @see loader=
102
+ # @api public
96
103
  setting :loader, default: Dry::System::Loader
97
104
 
98
105
  # @!method memoize=(policy)
@@ -119,6 +126,7 @@ module Dry
119
126
  #
120
127
  # @see memoize
121
128
  # @see Component
129
+ # @api public
122
130
  #
123
131
  # @!method memoize
124
132
  #
@@ -127,6 +135,7 @@ module Dry
127
135
  # @return [Boolean, Proc] the configured memoization policy
128
136
  #
129
137
  # @see memoize=
138
+ # @api public
130
139
  setting :memoize, default: false
131
140
 
132
141
  # @!method namespaces
@@ -135,11 +144,13 @@ module Dry
135
144
  #
136
145
  # Allows namespaces to added on the returned object via {Namespaces#add}.
137
146
  #
138
- # @see Namespaces#add
139
- #
140
147
  # @return [Namespaces] the namespaces
148
+ #
149
+ # @see Namespaces#add
150
+ # @api public
141
151
  setting :namespaces, default: Namespaces.new, cloneable: true
142
152
 
153
+ # @api public
143
154
  def default_namespace=(namespace)
144
155
  Dry::Core::Deprecations.announce(
145
156
  "Dry::System::Config::ComponentDir#default_namespace=",
@@ -157,6 +168,7 @@ module Dry
157
168
  namespaces.add namespace_path, key: nil
158
169
  end
159
170
 
171
+ # @api public
160
172
  def default_namespace
161
173
  Dry::Core::Deprecations.announce(
162
174
  "Dry::System::Config::ComponentDir#default_namespace",
@@ -179,7 +191,7 @@ module Dry
179
191
  # @return [String] the path
180
192
  attr_reader :path
181
193
 
182
- # @api private
194
+ # @api public
183
195
  def initialize(path)
184
196
  super()
185
197
  @path = path
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "concurrent/map"
4
3
  require "dry/system/constants"
5
4
  require "dry/system/errors"
6
5
  require_relative "component_dir"
@@ -8,6 +7,9 @@ require_relative "component_dir"
8
7
  module Dry
9
8
  module System
10
9
  module Config
10
+ # The configured component dirs for a container
11
+ #
12
+ # @api public
11
13
  class ComponentDirs
12
14
  # @!group Settings
13
15
 
@@ -63,71 +65,141 @@ module Dry
63
65
  #
64
66
  # @see memoize=
65
67
 
68
+ # rubocop:disable Layout/LineLength
69
+
66
70
  # @!method namespaces
67
71
  #
68
72
  # Returns the default configured namespaces for all added component dirs
69
73
  #
70
- # Allows namespaces to added on the returned object via {Namespaces#add}.
74
+ # Allows namespaces to added on the returned object via {Dry::System::Config::Namespaces#add}.
71
75
  #
72
- # @see Namespaces#add
76
+ # @see Dry::System::Config::Namespaces#add
73
77
  #
74
78
  # @return [Namespaces] the namespaces
75
79
 
80
+ # rubocop:enable Layout/LineLength
81
+
76
82
  # @!endgroup
77
83
 
78
84
  # A ComponentDir for configuring the default values to apply to all added
79
85
  # component dirs
80
86
  #
87
+ # @see #method_missing
81
88
  # @api private
82
89
  attr_reader :defaults
83
90
 
91
+ # Creates a new component dirs
92
+ #
84
93
  # @api private
85
94
  def initialize
86
- @dirs = Concurrent::Map.new
95
+ @dirs = {}
87
96
  @defaults = ComponentDir.new(nil)
88
97
  end
89
98
 
90
99
  # @api private
91
100
  def initialize_copy(source)
92
- @dirs = source.dirs.dup
101
+ @dirs = source.dirs.map { |path, dir| [path, dir.dup] }.to_h
93
102
  @defaults = source.defaults.dup
94
103
  end
95
104
 
96
- # Adds and configures a component dir
105
+ # Returns and optionally yields a previously added component dir
106
+ #
107
+ # @param path [String] the path for the component dir
108
+ # @yieldparam dir [ComponentDir] the component dir
109
+ #
110
+ # @return [ComponentDir] the component dir
111
+ #
112
+ # @api public
113
+ def dir(path)
114
+ dirs[path].tap do |dir|
115
+ # Defaults can be (re-)applied first, since the dir has already been added
116
+ apply_defaults_to_dir(dir) if dir
117
+ yield dir if block_given?
118
+ end
119
+ end
120
+ alias_method :[], :dir
121
+
122
+ # @overload add(path)
123
+ # Adds and configures a component dir for the given path
124
+ #
125
+ # @param path [String] the path for the component dir, relative to the configured
126
+ # container root
127
+ # @yieldparam dir [ComponentDir] the component dir to configure
97
128
  #
98
- # @param path [String] the path for the component dir, relative to the configured
99
- # container root
129
+ # @return [ComponentDir] the added component dir
100
130
  #
101
- # @yieldparam dir [ComponentDir] the component dir to configure
131
+ # @example
132
+ # component_dirs.add "lib" do |dir|
133
+ # dir.default_namespace = "my_app"
134
+ # end
102
135
  #
103
- # @return [ComponentDir] the added component dir
136
+ # @see ComponentDir
137
+ # @api public
104
138
  #
105
- # @example
106
- # component_dirs.add "lib" do |dir|
107
- # dir.default_namespace = "my_app"
108
- # end
139
+ # @overload add(dir)
140
+ # Adds a configured component dir
109
141
  #
110
- # @see ComponentDir
111
- def add(path)
142
+ # @param dir [ComponentDir] the configured component dir
143
+ #
144
+ # @return [ComponentDir] the added component dir
145
+ #
146
+ # @example
147
+ # dir = Dry::System::ComponentDir.new("lib")
148
+ # component_dirs.add dir
149
+ #
150
+ # @see ComponentDir
151
+ # @api public
152
+ def add(path_or_dir)
153
+ path, dir_to_add = path_and_dir(path_or_dir)
154
+
112
155
  raise ComponentDirAlreadyAddedError, path if dirs.key?(path)
113
156
 
114
- dirs[path] = ComponentDir.new(path).tap do |dir|
115
- yield dir if block_given?
157
+ dirs[path] = dir_to_add.tap do |dir|
158
+ # Defaults must be applied after yielding, since the dir is being newly added,
159
+ # and must have its configuration fully in place before we can know which
160
+ # defaults to apply
161
+ yield dir if path_or_dir == path && block_given?
116
162
  apply_defaults_to_dir(dir)
117
163
  end
118
164
  end
119
165
 
120
- # Returns the added component dirs, with default settings applied
166
+ # Deletes and returns a previously added component dir
121
167
  #
122
- # @return [Hash<String, ComponentDir>] the component dirs as a hash, keyed by path
123
- def dirs
124
- @dirs.each { |_, dir| apply_defaults_to_dir(dir) }
168
+ # @param path [String] the path for the component dir
169
+ #
170
+ # @return [ComponentDir] the removed component dir
171
+ #
172
+ # @api public
173
+ def delete(path)
174
+ dirs.delete(path)
125
175
  end
126
176
 
177
+ # Returns the paths of the component dirs
178
+ #
179
+ # @return [Array<String>] the component dir paths
180
+ #
181
+ # @api public
182
+ def paths
183
+ dirs.keys
184
+ end
185
+
186
+ # Returns the count of component dirs
187
+ #
188
+ # @return [Integer]
189
+ #
190
+ # @api public
191
+ def length
192
+ dirs.length
193
+ end
194
+ alias_method :size, :length
195
+
127
196
  # Returns the added component dirs, with default settings applied
128
197
  #
129
198
  # @return [Array<ComponentDir>]
199
+ #
200
+ # @api public
130
201
  def to_a
202
+ dirs.each { |_, dir| apply_defaults_to_dir(dir) }
131
203
  dirs.values
132
204
  end
133
205
 
@@ -135,12 +207,46 @@ module Dry
135
207
  # argument.
136
208
  #
137
209
  # @yieldparam dir [ComponentDir] the yielded component dir
210
+ #
211
+ # @api public
138
212
  def each(&block)
139
213
  to_a.each(&block)
140
214
  end
141
215
 
216
+ protected
217
+
218
+ # Returns the hash of component dirs, keyed by their paths
219
+ #
220
+ # Recently changed default configuration may not be applied to these dirs. Use
221
+ # #to_a or #each to access dirs with default configuration fully applied.
222
+ #
223
+ # This method exists to encapsulate the instance variable and to serve the needs
224
+ # of #initialize_copy
225
+ #
226
+ # @return [Hash{String => ComponentDir}]
227
+ #
228
+ # @api private
229
+ attr_reader :dirs
230
+
142
231
  private
143
232
 
233
+ # Converts a path string or pre-built component dir into a path and dir tuple
234
+ #
235
+ # @param path_or_dir [String,ComponentDir]
236
+ #
237
+ # @return [Array<(String, ComponentDir)>]
238
+ #
239
+ # @see #add
240
+ def path_and_dir(path_or_dir)
241
+ if path_or_dir.is_a?(ComponentDir)
242
+ dir = path_or_dir
243
+ [dir.path, dir]
244
+ else
245
+ path = path_or_dir
246
+ [path, ComponentDir.new(path)]
247
+ end
248
+ end
249
+
144
250
  # Applies default settings to a component dir. This is run every time the dirs are
145
251
  # accessed to ensure defaults are applied regardless of when new component dirs
146
252
  # are added. This method must be idempotent.
@@ -21,16 +21,19 @@ module Dry
21
21
  #
22
22
  # @see Namespaces#add
23
23
  #
24
- # @api private
24
+ # @api public
25
25
  class Namespace
26
26
  ROOT_PATH = nil
27
27
 
28
28
  include Dry::Equalizer(:path, :key, :const)
29
29
 
30
+ # @api public
30
31
  attr_reader :path
31
32
 
33
+ # @api public
32
34
  attr_reader :key
33
35
 
36
+ # @api public
34
37
  attr_reader :const
35
38
 
36
39
  # Returns a namespace configured to serve as the default root namespace for a
@@ -48,20 +51,24 @@ module Dry
48
51
  )
49
52
  end
50
53
 
54
+ # @api private
51
55
  def initialize(path:, key:, const:)
52
56
  @path = path
53
57
  @key = key
54
58
  @const = const
55
59
  end
56
60
 
61
+ # @api public
57
62
  def root?
58
63
  path == ROOT_PATH
59
64
  end
60
65
 
66
+ # @api public
61
67
  def path?
62
68
  !root?
63
69
  end
64
70
 
71
+ # @api private
65
72
  def default_key?
66
73
  key == path
67
74
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/core/deprecations"
3
4
  require "dry/system/errors"
4
5
  require_relative "namespace"
5
6
 
@@ -26,6 +27,39 @@ module Dry
26
27
  @namespaces = source.namespaces.dup
27
28
  end
28
29
 
30
+ # Returns the namespace configured for the path, or nil if no such namespace has
31
+ # been configured
32
+ #
33
+ # @return [Namespace, nil] the namespace, if configured
34
+ #
35
+ # @api public
36
+ def namespace(path)
37
+ namespaces[path]
38
+ end
39
+ alias_method :[], :namespace
40
+
41
+ # Returns the namespace configured for the root path, or nil if the root namespace
42
+ # has not been configured
43
+ #
44
+ # @return [Namespace, nil] the root namespace, if configured
45
+ #
46
+ # @api public
47
+ def root(**options)
48
+ if options.any?
49
+ Dry::Core::Deprecations.announce(
50
+ "Dry::System::Config::Namespaces#root (with arguments)",
51
+ "Use `#add_root(key: nil, const: nil)` instead",
52
+ tag: "dry-system",
53
+ uplevel: 1
54
+ )
55
+
56
+ add_root(**options)
57
+ return
58
+ end
59
+
60
+ namespaces[Namespace::ROOT_PATH]
61
+ end
62
+
29
63
  # rubocop:disable Layout/LineLength
30
64
 
31
65
  # Adds a component dir namespace
@@ -62,8 +96,8 @@ module Dry
62
96
  #
63
97
  # @param path [String] the path to the sub-directory of source files to which this
64
98
  # namespace should apply, relative to the component dir
65
- # @param identifier [String, nil] the leading namespace to apply to the registered
66
- # identifiers for the components. Set `nil` for the identifiers to be top-level.
99
+ # @param key [String, nil] the leading namespace to apply to the container keys
100
+ # for the components. Set `nil` for the keys to be top-level.
67
101
  # @param const [String, nil] the Ruby constant namespace to expect for constants
68
102
  # defined within the components. This should be provided in underscored string
69
103
  # form, e.g. "hello_there/world" for a Ruby constant of `HelloThere::World`. Set
@@ -87,31 +121,84 @@ module Dry
87
121
  # @see #add
88
122
  #
89
123
  # @api public
90
- def root(key: nil, const: nil)
124
+ def add_root(key: nil, const: nil)
91
125
  add(Namespace::ROOT_PATH, key: key, const: const)
92
126
  end
93
127
 
94
- # @api private
128
+ # Deletes the configured namespace for the given path and returns the namespace
129
+ #
130
+ # If no namespace was previously configured for the given path, returns nil
131
+ #
132
+ # @param path [String] the path for the namespace
133
+ #
134
+ # @return [Namespace, nil]
135
+ #
136
+ # @api public
137
+ def delete(path)
138
+ namespaces.delete(path)
139
+ end
140
+
141
+ # Deletes the configured root namespace and returns the namespace
142
+ #
143
+ # If no root namespace was previously configured, returns nil
144
+ #
145
+ # @return [Namespace, nil]
146
+ #
147
+ # @api public
148
+ def delete_root
149
+ delete(Namespace::ROOT_PATH)
150
+ end
151
+
152
+ # Returns the paths of the configured namespaces
153
+ #
154
+ # @return [Array<String,nil>] the namespace paths, with nil representing the root
155
+ # namespace
156
+ #
157
+ # @api public
158
+ def paths
159
+ namespaces.keys
160
+ end
161
+
162
+ # Returns the count of configured namespaces
163
+ #
164
+ # @return [Integer]
165
+ #
166
+ # @api public
167
+ def length
168
+ namespaces.length
169
+ end
170
+ alias_method :size, :length
171
+
172
+ # Returns true if there are no configured namespaces
173
+ #
174
+ # @return [Boolean]
175
+ #
176
+ # @api public
95
177
  def empty?
96
178
  namespaces.empty?
97
179
  end
98
180
 
99
181
  # Returns the configured namespaces as an array
100
182
  #
101
- # This adds a root namespace to the end of the array if one was not configured
102
- # manually. This fallback ensures that all components in the component dir can be
103
- # loaded.
183
+ # Adds a default root namespace to the end of the array if one was not added
184
+ # explicitly. This fallback ensures that all components in the component dir can
185
+ # be loaded.
104
186
  #
105
187
  # @return [Array<Namespace>] the namespaces
106
188
  #
107
- # @api private
189
+ # @api public
108
190
  def to_a
109
191
  namespaces.values.tap do |arr|
110
192
  arr << Namespace.default_root unless arr.any?(&:root?)
111
193
  end
112
194
  end
113
195
 
114
- # @api private
196
+ # Calls the given block once for each configured namespace, passing the namespace
197
+ # as an argument.
198
+ #
199
+ # @yieldparam namespace [Namespace] the yielded namespace
200
+ #
201
+ # @api public
115
202
  def each(&block)
116
203
  to_a.each(&block)
117
204
  end
@@ -36,7 +36,7 @@ module Dry
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 < "3.1.0"
40
40
  end
41
41
  end
42
42
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module System
5
- VERSION = "0.21.0"
5
+ VERSION = "0.22.0"
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.21.0
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-31 00:00:00.000000000 Z
11
+ date: 2022-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby