Skip to content

Commit d973260

Browse files
committed
Add injector mixin plugin
1 parent 5fa528d commit d973260

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed

lib/dry/system/plugins.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ def enabled_plugins
134134

135135
require "dry/system/plugins/zeitwerk"
136136
register(:zeitwerk, Plugins::Zeitwerk)
137+
138+
require_relative "plugins/injector_mixin"
139+
register(:injector_mixin, Plugins::InjectorMixin)
137140
end
138141
end
139142
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# frozen_string_literal: true
2+
3+
module Dry
4+
module System
5+
module Plugins
6+
# @api private
7+
class InjectorMixin < Module
8+
MODULE_SEPARATOR = "::"
9+
10+
attr_reader :name
11+
12+
def initialize(name: "Deps")
13+
@name = name
14+
end
15+
16+
def extended(container)
17+
container.after(:configure, &method(:define_mixin))
18+
end
19+
20+
private
21+
22+
def define_mixin(container)
23+
inflector = container.config.inflector
24+
25+
name_parts = name.split(MODULE_SEPARATOR)
26+
27+
if name_parts[0] == ""
28+
name_parts.delete_at(0)
29+
root_module = Object
30+
else
31+
root_module = container_parent_module(container)
32+
end
33+
34+
mixin_parent_mod = define_parent_modules(
35+
root_module,
36+
name_parts,
37+
inflector
38+
)
39+
40+
mixin_parent_mod.const_set(
41+
inflector.camelize(name_parts.last),
42+
container.injector
43+
)
44+
end
45+
46+
def container_parent_module(container)
47+
if container.name
48+
parent_name = container.name.split(MODULE_SEPARATOR)[0..-2].join(MODULE_SEPARATOR)
49+
container.config.inflector.constantize(parent_name)
50+
else
51+
Object
52+
end
53+
end
54+
55+
def define_parent_modules(parent_mod, name_parts, inflector)
56+
return parent_mod if name_parts.length == 1
57+
58+
name_parts[0..-2].reduce(parent_mod) { |parent_mod, mod_name|
59+
parent_mod.const_set(inflector.camelize(mod_name), Module.new)
60+
}
61+
end
62+
end
63+
end
64+
end
65+
end
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe "Plugins / Injector mixin" do
4+
5+
describe "default options" do
6+
it "creates a 'Deps' mixin in the container's parent module" do
7+
module Test
8+
class Container < Dry::System::Container
9+
use :injector_mixin
10+
configured!
11+
end
12+
end
13+
14+
component = Object.new
15+
Test::Container.register "component", component
16+
17+
depending_obj = Class.new do
18+
include Test::Deps["component"]
19+
end.new
20+
21+
expect(depending_obj.component).to be component
22+
end
23+
end
24+
25+
describe "name given" do
26+
it "creates a mixin with the given name in the container's parent module" do
27+
module Test
28+
class Container < Dry::System::Container
29+
use :injector_mixin, name: "Inject"
30+
configured!
31+
end
32+
end
33+
34+
component = Object.new
35+
Test::Container.register "component", component
36+
37+
depending_obj = Class.new do
38+
include Test::Inject["component"]
39+
end.new
40+
41+
expect(depending_obj.component).to be component
42+
end
43+
end
44+
45+
describe "nested name given" do
46+
it "creates a mixin with the given name in the container's parent module" do
47+
module Test
48+
class Container < Dry::System::Container
49+
use :injector_mixin, name: "Inject::These::Pls"
50+
configured!
51+
end
52+
end
53+
54+
component = Object.new
55+
Test::Container.register "component", component
56+
57+
depending_obj = Class.new do
58+
include Test::Inject::These::Pls["component"]
59+
end.new
60+
61+
expect(depending_obj.component).to be component
62+
end
63+
end
64+
65+
describe "top-level name given" do
66+
it "creates a mixin with the given name in the top-level module" do
67+
module Test
68+
class Container < Dry::System::Container
69+
use :injector_mixin, name: "::Deps"
70+
configured!
71+
end
72+
end
73+
74+
component = Object.new
75+
Test::Container.register "component", component
76+
77+
depending_obj = Class.new do
78+
include ::Deps["component"]
79+
end.new
80+
81+
expect(depending_obj.component).to be component
82+
end
83+
end
84+
end

0 commit comments

Comments
 (0)