dry-system 0.20.0 → 0.21.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 +32 -0
- data/README.md +1 -1
- data/lib/dry/system/auto_registrar.rb +1 -13
- data/lib/dry/system/booter/component_registry.rb +3 -3
- data/lib/dry/system/booter.rb +4 -4
- data/lib/dry/system/component.rb +103 -45
- data/lib/dry/system/component_dir.rb +112 -45
- data/lib/dry/system/components/bootable.rb +10 -19
- data/lib/dry/system/config/component_dir.rb +70 -38
- data/lib/dry/system/config/component_dirs.rb +28 -41
- data/lib/dry/system/config/namespace.rb +71 -0
- data/lib/dry/system/config/namespaces.rb +121 -0
- data/lib/dry/system/constants.rb +1 -1
- data/lib/dry/system/container.rb +25 -29
- data/lib/dry/system/errors.rb +11 -20
- data/lib/dry/system/identifier.rb +57 -80
- data/lib/dry/system/indirect_component.rb +65 -0
- data/lib/dry/system/loader.rb +2 -3
- data/lib/dry/system/manual_registrar.rb +4 -8
- data/lib/dry/system/plugins.rb +1 -3
- data/lib/dry/system/provider.rb +6 -6
- data/lib/dry/system/provider_registry.rb +4 -4
- data/lib/dry/system/settings.rb +1 -4
- data/lib/dry/system/version.rb +1 -1
- data/lib/dry/system.rb +5 -5
- metadata +5 -2
@@ -13,42 +13,29 @@ module Dry
|
|
13
13
|
#
|
14
14
|
# @api public
|
15
15
|
class Identifier
|
16
|
-
include Dry::Equalizer(:
|
16
|
+
include Dry::Equalizer(:key, :separator)
|
17
17
|
|
18
|
-
# @return [String] the identifier string
|
18
|
+
# @return [String] the identifier's string key
|
19
19
|
# @api public
|
20
|
-
attr_reader :
|
21
|
-
|
22
|
-
# @return [String, nil] the namespace for the component
|
23
|
-
# @api public
|
24
|
-
attr_reader :namespace
|
20
|
+
attr_reader :key
|
25
21
|
|
26
22
|
# @return [String] the configured namespace separator
|
27
23
|
# @api public
|
28
24
|
attr_reader :separator
|
29
25
|
|
30
26
|
# @api private
|
31
|
-
def initialize(
|
32
|
-
@
|
33
|
-
@namespace = namespace
|
27
|
+
def initialize(key, separator: DEFAULT_SEPARATOR)
|
28
|
+
@key = key.to_s
|
34
29
|
@separator = separator
|
35
30
|
end
|
36
31
|
|
37
|
-
# @!method key
|
38
|
-
# Returns the identifier string
|
39
|
-
#
|
40
|
-
# @return [String]
|
41
|
-
# @see #identifier
|
42
|
-
# @api public
|
43
|
-
alias_method :key, :identifier
|
44
|
-
|
45
32
|
# @!method to_s
|
46
|
-
# Returns the identifier string
|
33
|
+
# Returns the identifier string key
|
47
34
|
#
|
48
35
|
# @return [String]
|
49
|
-
# @see #
|
36
|
+
# @see #key
|
50
37
|
# @api public
|
51
|
-
alias_method :to_s, :
|
38
|
+
alias_method :to_s, :key
|
52
39
|
|
53
40
|
# Returns the root namespace segment of the identifier string, as a symbol
|
54
41
|
#
|
@@ -62,31 +49,11 @@ module Dry
|
|
62
49
|
segments.first.to_sym
|
63
50
|
end
|
64
51
|
|
65
|
-
# Returns
|
66
|
-
#
|
67
|
-
# source file.
|
68
|
-
#
|
69
|
-
# @example
|
70
|
-
# identifier.key # => "articles.operations.create"
|
71
|
-
# identifier.namespace # => "admin"
|
52
|
+
# Returns true if the given leading namespaces are a leading part of the
|
53
|
+
# identifier's key
|
72
54
|
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
# @return [String] the path
|
76
|
-
# @api public
|
77
|
-
def path
|
78
|
-
@require_path ||= identifier.gsub(separator, PATH_SEPARATOR).yield_self { |path|
|
79
|
-
if namespace
|
80
|
-
namespace_path = namespace.to_s.gsub(separator, PATH_SEPARATOR)
|
81
|
-
"#{namespace_path}#{PATH_SEPARATOR}#{path}"
|
82
|
-
else
|
83
|
-
path
|
84
|
-
end
|
85
|
-
}
|
86
|
-
end
|
87
|
-
|
88
|
-
# Returns true if the given namespace prefix is part of the identifier's leading
|
89
|
-
# namespaces
|
55
|
+
# Also returns true if nil is given (technically, from nothing everything is
|
56
|
+
# wrought)
|
90
57
|
#
|
91
58
|
# @example
|
92
59
|
# identifier.key # => "articles.operations.create"
|
@@ -94,64 +61,74 @@ module Dry
|
|
94
61
|
# identifier.start_with?("articles.operations") # => true
|
95
62
|
# identifier.start_with?("articles") # => true
|
96
63
|
# identifier.start_with?("article") # => false
|
64
|
+
# identifier.start_with?(nil) # => true
|
97
65
|
#
|
98
66
|
# @param leading_namespaces [String] the one or more leading namespaces to check
|
99
67
|
# @return [Boolean]
|
100
68
|
# @api public
|
101
69
|
def start_with?(leading_namespaces)
|
102
|
-
|
103
|
-
|
70
|
+
leading_namespaces.nil? ||
|
71
|
+
key.start_with?("#{leading_namespaces}#{separator}") ||
|
72
|
+
key.eql?(leading_namespaces)
|
104
73
|
end
|
105
74
|
|
106
|
-
# Returns
|
107
|
-
# the identifier string.
|
108
|
-
#
|
109
|
-
# Additional options may be provided, which are passed to #initialize when
|
110
|
-
# constructing the new copy of the identifier
|
111
|
-
#
|
112
|
-
# @param leading_namespace [String] the one or more leading namespaces to remove
|
113
|
-
# @param options [Hash] additional options for initialization
|
75
|
+
# Returns the key with its segments separated by the given separator
|
114
76
|
#
|
115
|
-
# @
|
77
|
+
# @example
|
78
|
+
# identifier.key # => "articles.operations.create"
|
79
|
+
# identifier.key_with_separator("/") # => "articles/operations/create"
|
116
80
|
#
|
117
|
-
# @
|
81
|
+
# @return [String] the key using the separator
|
118
82
|
# @api private
|
119
|
-
def
|
120
|
-
|
121
|
-
/^#{Regexp.escape(leading_namespaces)}#{Regexp.escape(separator)}/,
|
122
|
-
EMPTY_STRING
|
123
|
-
)
|
124
|
-
|
125
|
-
return self if new_identifier == identifier
|
126
|
-
|
127
|
-
self.class.new(
|
128
|
-
new_identifier,
|
129
|
-
namespace: namespace,
|
130
|
-
separator: separator,
|
131
|
-
**options
|
132
|
-
)
|
83
|
+
def key_with_separator(separator)
|
84
|
+
segments.join(separator)
|
133
85
|
end
|
134
86
|
|
135
|
-
# Returns a copy of the identifier with the
|
87
|
+
# Returns a copy of the identifier with the key's leading namespace(s) replaced
|
88
|
+
#
|
89
|
+
# @example Changing a namespace
|
90
|
+
# identifier.key # => "articles.operations.create"
|
91
|
+
# identifier.namespaced(from: "articles", to: "posts").key # => "posts.commands.create"
|
92
|
+
#
|
93
|
+
# @example Removing a namespace
|
94
|
+
# identifier.key # => "articles.operations.create"
|
95
|
+
# identifier.namespaced(from: "articles", to: nil).key # => "operations.create"
|
136
96
|
#
|
137
|
-
# @
|
97
|
+
# @example Adding a namespace
|
98
|
+
# identifier.key # => "articles.operations.create"
|
99
|
+
# identifier.namespaced(from: nil, to: "admin").key # => "admin.articles.operations.create"
|
100
|
+
#
|
101
|
+
# @param from [String, nil] the leading namespace(s) to replace
|
102
|
+
# @param to [String, nil] the replacement for the leading namespace
|
138
103
|
#
|
139
104
|
# @return [Dry::System::Identifier] the copy of the identifier
|
140
105
|
#
|
141
106
|
# @see #initialize
|
142
107
|
# @api private
|
143
|
-
def
|
144
|
-
self
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
108
|
+
def namespaced(from:, to:)
|
109
|
+
return self if from == to
|
110
|
+
|
111
|
+
separated_to = "#{to}#{separator}" if to
|
112
|
+
|
113
|
+
new_key =
|
114
|
+
if from.nil?
|
115
|
+
"#{separated_to}#{key}"
|
116
|
+
else
|
117
|
+
key.sub(
|
118
|
+
/^#{Regexp.escape(from.to_s)}#{Regexp.escape(separator)}/,
|
119
|
+
separated_to || EMPTY_STRING
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
return self if new_key == key
|
124
|
+
|
125
|
+
self.class.new(new_key, separator: separator)
|
149
126
|
end
|
150
127
|
|
151
128
|
private
|
152
129
|
|
153
130
|
def segments
|
154
|
-
@segments ||=
|
131
|
+
@segments ||= key.split(separator)
|
155
132
|
end
|
156
133
|
end
|
157
134
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module System
|
7
|
+
# An indirect component is a component that cannot be directly from a source file
|
8
|
+
# directly managed by the container. It may be component that needs to be loaded
|
9
|
+
# indirectly, either via a manual registration file or an imported container
|
10
|
+
#
|
11
|
+
# Indirect components are an internal abstraction and, unlike ordinary components, are
|
12
|
+
# not exposed to users via component dir configuration hooks.
|
13
|
+
#
|
14
|
+
# @see Container#load_component
|
15
|
+
# @see Container#find_component
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
class IndirectComponent
|
19
|
+
include Dry::Equalizer(:identifier)
|
20
|
+
|
21
|
+
# @!attribute [r] identifier
|
22
|
+
# @return [String] the component's unique identifier
|
23
|
+
attr_reader :identifier
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def initialize(identifier)
|
27
|
+
@identifier = identifier
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns false, indicating that the component is not directly loadable from the
|
31
|
+
# files managed by the container
|
32
|
+
#
|
33
|
+
# This is the inverse of {Component#loadable?}
|
34
|
+
#
|
35
|
+
# @return [FalseClass]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
def loadable?
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the component's unique key
|
43
|
+
#
|
44
|
+
# @return [String] the key
|
45
|
+
#
|
46
|
+
# @see Identifier#key
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
def key
|
50
|
+
identifier.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the root namespace segment of the component's key, as a symbol
|
54
|
+
#
|
55
|
+
# @see Identifier#root_key
|
56
|
+
#
|
57
|
+
# @return [Symbol] the root key
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
def root_key
|
61
|
+
identifier.root_key
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/dry/system/loader.rb
CHANGED
@@ -28,7 +28,7 @@ module Dry
|
|
28
28
|
#
|
29
29
|
# @api public
|
30
30
|
def require!(component)
|
31
|
-
require(component.
|
31
|
+
require(component.require_path)
|
32
32
|
self
|
33
33
|
end
|
34
34
|
|
@@ -61,8 +61,7 @@ module Dry
|
|
61
61
|
# @api public
|
62
62
|
def constant(component)
|
63
63
|
inflector = component.inflector
|
64
|
-
|
65
|
-
inflector.constantize(inflector.camelize(component.path))
|
64
|
+
inflector.constantize(inflector.camelize(component.const_path))
|
66
65
|
end
|
67
66
|
|
68
67
|
private
|
@@ -30,16 +30,12 @@ module Dry
|
|
30
30
|
end
|
31
31
|
|
32
32
|
# @api private
|
33
|
-
def call(
|
34
|
-
|
35
|
-
|
36
|
-
require(root.join(config.registrations_dir, name))
|
33
|
+
def call(component)
|
34
|
+
require(root.join(config.registrations_dir, component.root_key.to_s))
|
37
35
|
end
|
38
36
|
|
39
|
-
def file_exists?(
|
40
|
-
|
41
|
-
|
42
|
-
File.exist?(File.join(registrations_dir, "#{name}#{RB_EXT}"))
|
37
|
+
def file_exists?(component)
|
38
|
+
File.exist?(File.join(registrations_dir, "#{component.root_key}#{RB_EXT}"))
|
43
39
|
end
|
44
40
|
|
45
41
|
private
|
data/lib/dry/system/plugins.rb
CHANGED
@@ -84,9 +84,7 @@ module Dry
|
|
84
84
|
# Enables a plugin if not already enabled.
|
85
85
|
# Raises error if plugin cannot be found in the plugin registry.
|
86
86
|
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
# @param [Symbol] name The plugin identifier
|
87
|
+
# @param [Symbol] name The plugin name
|
90
88
|
# @param [Hash] options Plugin options
|
91
89
|
#
|
92
90
|
# @return [self]
|
data/lib/dry/system/provider.rb
CHANGED
@@ -7,14 +7,14 @@ require "dry/system/components/bootable"
|
|
7
7
|
module Dry
|
8
8
|
module System
|
9
9
|
class Provider
|
10
|
-
attr_reader :
|
10
|
+
attr_reader :name
|
11
11
|
|
12
12
|
attr_reader :options
|
13
13
|
|
14
14
|
attr_reader :components
|
15
15
|
|
16
|
-
def initialize(
|
17
|
-
@
|
16
|
+
def initialize(name, options)
|
17
|
+
@name = name
|
18
18
|
@options = options
|
19
19
|
@components = Concurrent::Map.new
|
20
20
|
end
|
@@ -35,9 +35,9 @@ module Dry
|
|
35
35
|
boot_files.detect { |path| Pathname(path).basename(RB_EXT).to_s == name.to_s }
|
36
36
|
end
|
37
37
|
|
38
|
-
def component(
|
39
|
-
|
40
|
-
components.fetch(
|
38
|
+
def component(component_name, options = {})
|
39
|
+
component_key = options[:key] || component_name
|
40
|
+
components.fetch(component_key).new(component_name, options)
|
41
41
|
end
|
42
42
|
|
43
43
|
def load_components
|
@@ -15,12 +15,12 @@ module Dry
|
|
15
15
|
items.each(&block)
|
16
16
|
end
|
17
17
|
|
18
|
-
def register(
|
19
|
-
items << Provider.new(
|
18
|
+
def register(name, options)
|
19
|
+
items << Provider.new(name, options)
|
20
20
|
end
|
21
21
|
|
22
|
-
def [](
|
23
|
-
detect { |provider| provider.
|
22
|
+
def [](name)
|
23
|
+
detect { |provider| provider.name == name }
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/dry/system/settings.rb
CHANGED
@@ -11,12 +11,9 @@ module Dry
|
|
11
11
|
module System
|
12
12
|
module Settings
|
13
13
|
class DSL < BasicObject
|
14
|
-
attr_reader :identifier
|
15
|
-
|
16
14
|
attr_reader :schema
|
17
15
|
|
18
|
-
def initialize(
|
19
|
-
@identifier = identifier
|
16
|
+
def initialize(&block)
|
20
17
|
@schema = {}
|
21
18
|
instance_eval(&block)
|
22
19
|
end
|
data/lib/dry/system/version.rb
CHANGED
data/lib/dry/system.rb
CHANGED
@@ -8,17 +8,17 @@ module Dry
|
|
8
8
|
# Register external component provider
|
9
9
|
#
|
10
10
|
# @api public
|
11
|
-
def self.register_provider(
|
12
|
-
providers.register(
|
13
|
-
providers[
|
11
|
+
def self.register_provider(name, options)
|
12
|
+
providers.register(name, options)
|
13
|
+
providers[name].load_components
|
14
14
|
self
|
15
15
|
end
|
16
16
|
|
17
17
|
# Register an external component that can be booted within other systems
|
18
18
|
#
|
19
19
|
# @api public
|
20
|
-
def self.register_component(
|
21
|
-
providers[provider].register_component(
|
20
|
+
def self.register_component(name, provider:, &block)
|
21
|
+
providers[provider].register_component(name, block)
|
22
22
|
self
|
23
23
|
end
|
24
24
|
|
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.
|
4
|
+
version: 0.21.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-
|
11
|
+
date: 2021-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -197,11 +197,14 @@ files:
|
|
197
197
|
- lib/dry/system/components/config.rb
|
198
198
|
- lib/dry/system/config/component_dir.rb
|
199
199
|
- lib/dry/system/config/component_dirs.rb
|
200
|
+
- lib/dry/system/config/namespace.rb
|
201
|
+
- lib/dry/system/config/namespaces.rb
|
200
202
|
- lib/dry/system/constants.rb
|
201
203
|
- lib/dry/system/container.rb
|
202
204
|
- lib/dry/system/errors.rb
|
203
205
|
- lib/dry/system/identifier.rb
|
204
206
|
- lib/dry/system/importer.rb
|
207
|
+
- lib/dry/system/indirect_component.rb
|
205
208
|
- lib/dry/system/lifecycle.rb
|
206
209
|
- lib/dry/system/loader.rb
|
207
210
|
- lib/dry/system/loader/autoloading.rb
|