infusible 3.3.0 → 3.5.0

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: 02a5684919e16bf773ea7da4a873180f2275319fd2f7a8883fd152e59914c321
4
- data.tar.gz: 458f977111e74f2b78a58a5c313a1b149d26f315ef300bf9c3a508c99cd5826d
3
+ metadata.gz: bc25967c984d1fa86abba7a1319a91da40f62e2eec3a904ef93dee7e60a54dfc
4
+ data.tar.gz: a086e0fd8e9ec8d644e10fbec3f30e6465666358b6f4c190010a8c3ed5105246
5
5
  SHA512:
6
- metadata.gz: 44e5c3621603e874c207aab7dbd69a48b790e8e8159551b98876cfb313194df30483e45a3b7d094d6f3aad4a2c96dc297ee2cf4136ca71c21c2d0e49c240ad73
7
- data.tar.gz: 8c35c9a2da3865a6537283d922eed96659ea82fd6ba8705a1a3f788066175f4517c7a595ead341bd305fd52fc62bc2877c3848bc462367e0f43395277f7bd01a
6
+ metadata.gz: 58e0efa11b9c780f8d018c178cbb5e1f0ac1c56cc4b9b2919b3e79f4949fbc0833304c00f4284895b4f9212b62577bbbdc6f029fb5dfb2c503eb0740320c65c5
7
+ data.tar.gz: f38b08ea1b7a418e1c0c3afc853e1b8fdd184a8880d7699f4320f234bb10c03f0e5e8ed59330f5f4af1ac747d0c3bdbbe01e9282bb3f7ee09aebcd36fd114288
checksums.yaml.gz.sig CHANGED
@@ -1,3 +1 @@
1
- K�Ya�b��]փ���{e5͘���j.,ԑO��W���vr��yA�(�(�� ��YA��$�&隐b_��K����#~Nt �;�gۺ]� ���b<��J����
2
- ���kg��i`u�lP��g��阷{N��]+%)A�[:����a|���~�;���!K���P弇s��>p�.� �6���L����m�}�`&1�`
3
- % �=
1
+ $@��F ����l ��i����ܔ3ǓڶdX��]��H�ߜ���o����4��Ǫ��^֥$J��JaX$-��:Dt���r�(�;&��j�>O6��##g���M0b[�f}��� JO� ��S�uD⹀nE����/��'I���e��k��7�*2_��9Գ�n�! ���k��Kb9��J�In;����zj���J�C)n1hL�~�O�- �9����i� �N:�I�UidO� #{���א�ݼ�\z�E�'�Q%CߙpMpu^�Nڶ�fo#�r<K�"LI���Y�R�r�
data/README.adoc CHANGED
@@ -3,18 +3,18 @@
3
3
  :figure-caption!:
4
4
 
5
5
  :dependency_injection_containers_link: link:https://alchemists.io/articles/dependency_injection_containers[Dependency Injection Containers]
6
- :dry-container_link: link:https://dry-rb.org/gems/dry-container[Dry Container]
6
+ :containable_link: link:https://alchemists.io/projects/containable[Containable]
7
7
  :http_link: link:https://github.com/httprb/http[HTTP]
8
8
 
9
9
  = Infusible
10
10
 
11
11
  Automatically injects dependencies within your object via the _Dependency Inversion Principle_ -- the _D_ in _SOLID_ design -- and is a powerful way to compose complex architectures from small objects which leverage the _Single Responsibility Principle_ -- the _S_ in _SOLID_ design.
12
12
 
13
- When coupled with {dependency_injection_containers_link}, as provided by the {dry-container_link} gem, Infusible completes the second half of the _Dependency Inversion Principle_. Here's a quick example of Infusible in action:
13
+ When coupled with {dependency_injection_containers_link}, as provided by the {containable_link} gem, Infusible completes the second half of the _Dependency Inversion Principle_. Here's a quick example of Infusible in action:
14
14
 
15
15
  [source,ruby]
16
16
  ----
17
- Import = Infusible.with({a: 1, b: 2, c: 3})
17
+ Import = Infusible[a: 1, b: 2, c: 3]
18
18
 
19
19
  class Demo
20
20
  include Import[:a, :b, :c]
@@ -87,19 +87,20 @@ Let's walk through each staring by defining a container of dependencies.
87
87
 
88
88
  ==== Containers
89
89
 
90
- A container provides a common object for which you can group related dependencies for injection and reuse. {dry-container_link} is recommended for defining your dependencies but a primitive `Hash` or any object which responds to the `#[]` message works too.
90
+ A container provides a common object for which you can group related dependencies for injection and reuse. {containable_link} is recommended for defining your dependencies but a primitive `Hash` or any object which responds to the `#[]` message works too.
91
91
 
92
- For documentation purposes, the {dry-container_link} gem will be used. The following creates a simple container where you might want to use the {http_link} gem to make HTTP requests and log information using Ruby's native logger.
92
+ For documentation purposes, the {containable_link} gem will be used. The following creates a simple container where you might want to use the {http_link} gem to make HTTP requests and log information using Ruby's native logger.
93
93
 
94
94
  [source,ruby]
95
95
  ----
96
+ require "containable"
96
97
  require "http"
97
98
  require "logger"
98
99
 
99
100
  module Container
100
- extend Dry::Container::Mixin
101
+ extend Containable
101
102
 
102
- register(:http) { HTTP }
103
+ register :http, HTTP
103
104
  register(:logger) { Logger.new STDOUT }
104
105
  end
105
106
  ----
@@ -112,7 +113,7 @@ Once your container is defined, you'll want to define the corresponding injector
112
113
  ----
113
114
  require "infusible"
114
115
 
115
- Import = Infusible.with Container
116
+ Import = Infusible[Container]
116
117
  ----
117
118
 
118
119
  ==== Dependencies
@@ -304,14 +305,14 @@ There is no `+#private+` method since `#[]` does this for you and is _recommende
304
305
  [source,ruby]
305
306
  ----
306
307
  module Container
307
- extend Dry::Container::Mixin
308
+ extend Containable
308
309
 
309
- register(:one) { "One" }
310
- register(:two) { "Two" }
311
- register(:three) { "Three" }
310
+ register :one, "One"
311
+ register :two, "Two"
312
+ register :three, "Three"
312
313
  end
313
314
 
314
- Import = Infusible.with Container
315
+ Import = Infusible[Container]
315
316
 
316
317
  class Demo
317
318
  include Import.public(:one)
@@ -328,25 +329,25 @@ demo.three # NoMethodError: private method.
328
329
 
329
330
  ==== Infused Keys
330
331
 
331
- You have access to the keys of all infused dependencies via the _private_ `infused_keys` method which can be powerful in metaprogramming situations. For example, consider the following, which calls all injected dependencies since they have the same Object API (i.e. `#call`):
332
+ You have access to the keys of all dependencies via the _private_ `#infused_keys` method which is powerful in metaprogramming situations. For example, consider the following which calls all injected dependencies since they have the same Object API (i.e. `#call`):
332
333
 
333
334
  Example:
334
335
 
335
336
  [source,ruby]
336
337
  ----
337
338
  module Container
338
- extend Dry::Container::Mixin
339
+ extend Containable
339
340
 
340
- register(:one, proc { puts "One" }, call: false)
341
- register(:two, proc { puts "Two" }, call: false)
341
+ register :one, "One"
342
+ register :two, "Two"
342
343
  end
343
344
 
344
- Import = Infusible.with Container
345
+ Import = Infusible[Container]
345
346
 
346
347
  class Demo
347
348
  include Import[:one, :two]
348
349
 
349
- def call = infused_keys.each { |key| __send__(key).call }
350
+ def call = infused_keys.each { |key| puts __send__(key) }
350
351
  end
351
352
 
352
353
  Demo.new.call
@@ -356,27 +357,25 @@ Demo.new.call
356
357
 
357
358
  As you can see, with the _private_ `#infused_keys` attribute reader, we are able to iterate through each infused key and send the `#call` message to each injected dependency.
358
359
 
359
- Since `#infused_keys` is a private attribute reader, this means the infused keys are private to each instance. This includes all ancestors when using inheritance as each super class in the hierarchy will have it's own unique array of infused keys depending on what was injected for that object.
360
+ Since `#infused_keys` is a private attribute reader, this means the infused keys are private to each instance. This includes all ancestors when using inheritance as each parent class in the hierarchy will have it's own unique array of infused jk depending on what was injected for that object.
360
361
 
361
362
  All infused keys are frozen by default.
362
363
 
363
364
  === Tests
364
365
 
365
- As you architect your implementation, you'll want to test your injected dependencies. You might want to stub, mock, or spy on them as well. Test support is built-in for you by only requiring the stub refinement as provided by this gem. For demonstration purposes, I'll assume you are using RSpec but you can adapt for whatever testing framework you are using.
366
-
367
- Let's say you have the following implementation that combines both {dry-container_link} (or a primitive `Hash` would work too) and this gem:
366
+ As you architect your implementation, you'll want to test your injected dependencies. You might want to stub, mock, or spy on them as well. Test support is primarily provided via the {containable_link} gem. Example:
368
367
 
369
368
  [source,ruby]
370
369
  ----
371
370
  # Our container with a single dependency.
372
371
  module Container
373
- extend Dry::Container::Mixin
372
+ extend Containable
374
373
 
375
- register(:kernel) { Kernel }
374
+ register :kernel, Kernel
376
375
  end
377
376
 
378
377
  # Our import which defines our container for potential injection.
379
- Import = Infusible.with Container
378
+ Import = Infusible[Container]
380
379
 
381
380
  # Our action class which injects our kernel dependency from our container.
382
381
  class Action
@@ -390,21 +389,14 @@ With our implementation defined, we can test as follows:
390
389
 
391
390
  [source,ruby]
392
391
  ----
393
- # Required: You must require Dry Container and Infusible stubbing for testing purposes.
394
- require "dry/container/stub"
395
- require "infusible/stub"
396
-
397
392
  RSpec.describe Action do
398
- # Required: You must refine Infusible to leverage stubbing of your dependencies.
399
- using Infusible::Stub
400
-
401
393
  subject(:action) { Action.new }
402
394
 
403
395
  let(:kernel) { class_spy Kernel }
404
396
 
405
- # Required: You must define what dependencies you want to stub and unstub before and after a test.
406
- before { Import.stub kernel: }
407
- after { Import.unstub :kernel }
397
+ before { Container.stub! kernel: }
398
+
399
+ after { Container.restore }
408
400
 
409
401
  describe "#call" do
410
402
  it "prints message" do
@@ -422,16 +414,12 @@ While the above works great for a single spec, over time you'll want to reduce d
422
414
  [source,ruby]
423
415
  ----
424
416
  # spec/support/shared_contexts/application_container.rb
425
- require "dry/container/stub"
426
- require "infusible/stub"
427
-
428
417
  RSpec.shared_context "with application dependencies" do
429
- using Infusible::Stub
430
-
431
418
  let(:kernel) { class_spy Kernel }
432
419
 
433
- before { Import.stub kernel: }
434
- after { Import.unstub :kernel }
420
+ before { Container.stub! kernel: }
421
+
422
+ after { Container.restore }
435
423
  end
436
424
  ----
437
425
 
@@ -452,20 +440,7 @@ RSpec.describe Action do
452
440
  end
453
441
  ----
454
442
 
455
- A shared context allows you to reuse it across multiple specs by including it as needed.
456
-
457
- In both spec examples -- so far -- you'll notice only RSpec `before` and `after` blocks are used. You can use an `around` block too. Example:
458
-
459
- [source,ruby]
460
- ----
461
- around do |example|
462
- Import.stub_with kernel: FakeKernel do
463
- example.run
464
- end
465
- end
466
- ----
467
-
468
- ⚠️ I mention `around` block support last because the caveat is that you can't use an `around` block with any RSpec test double since link:https://github.com/rspec/rspec-mocks/issues/1283[RSpec can't guarantee proper cleanup]. This is why the RSpec `before` and `after` blocks were used to guarantee proper setup and teardown. That said, you can use _fakes_ or any object you own which _isn't_ a RSpec test double but provides the Object API you need for testing purposes.
443
+ A shared context allows for reuse across multiple specs by including it as needed.
469
444
 
470
445
  == Development
471
446
 
@@ -524,7 +499,7 @@ Your constructor, initializer, and instance variables are all there. Only you do
524
499
 
525
500
  === Style Guide
526
501
 
527
- When using this gem, along with a container like {dry-container_link}, make sure to adhere to the following guidelines:
502
+ When using this gem, along with a container like {containable_link}, make sure to adhere to the following guidelines:
528
503
 
529
504
  * Use containers to group related dependencies that make logical sense for the namespace you are working in and avoid using containers as a junk drawer for throwing random objects in.
530
505
  * Use containers that don't have a lot of registered dependencies. If you register too many dependencies, that means your objects are too complex and need to be simplified further.
data/infusible.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "infusible"
5
- spec.version = "3.3.0"
5
+ spec.version = "3.5.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/infusible"
@@ -24,7 +24,6 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.required_ruby_version = "~> 3.3"
26
26
  spec.add_dependency "marameters", "~> 3.0"
27
- spec.add_dependency "zeitwerk", "~> 2.6"
28
27
 
29
28
  spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
30
29
  spec.files = Dir["*.gemspec", "lib/**/*"]
@@ -6,15 +6,16 @@ module Infusible
6
6
  # Provides the automatic and complete resolution of all injected dependencies.
7
7
  # :reek:TooManyInstanceVariables
8
8
  class Constructor < Module
9
- def self.define_instance_variables target, names, keywords
9
+ def self.define_instance_variables target, keys, keywords
10
10
  unless target.instance_variable_defined? :@infused_keys
11
- target.instance_variable_set :@infused_keys, names
11
+ target.instance_variable_set :@infused_names, keys
12
+ target.instance_variable_set :@infused_keys, keys
12
13
  end
13
14
 
14
- names.each do |name|
15
- next unless keywords.key?(name) || !target.instance_variable_defined?(:"@#{name}")
15
+ keys.each do |key|
16
+ next unless keywords.key?(key) || !target.instance_variable_defined?(:"@#{key}")
16
17
 
17
- target.instance_variable_set :"@#{name}", keywords[name]
18
+ target.instance_variable_set :"@#{key}", keywords[key]
18
19
  end
19
20
  end
20
21
 
@@ -76,34 +77,41 @@ module Infusible
76
77
  end
77
78
 
78
79
  def define_initialize_with_positionals super_parameters, variablizer
79
- instance_module.module_exec dependencies.names, variablizer do |names, definer|
80
+ instance_module.module_exec dependencies.keys, variablizer do |keys, definer|
80
81
  define_method :initialize do |*positionals, **keywords, &block|
81
- definer.call self, names, keywords
82
+ definer.call self, keys, keywords
82
83
 
83
84
  if super_parameters.only_single_splats?
84
85
  super(*positionals, **keywords, &block)
85
86
  else
86
- super(*positionals, **super_parameters.keyword_slice(keywords, keys: names), &block)
87
+ super(*positionals, **super_parameters.keyword_slice(keywords, keys:), &block)
87
88
  end
88
89
  end
89
90
  end
90
91
  end
91
92
 
92
93
  def define_initialize_with_keywords super_parameters, variablizer
93
- instance_module.module_exec dependencies.names, variablizer do |names, definer|
94
+ instance_module.module_exec dependencies.keys, variablizer do |keys, definer|
94
95
  define_method :initialize do |**keywords, &block|
95
- definer.call self, names, keywords
96
- super(**super_parameters.keyword_slice(keywords, keys: names), &block)
96
+ definer.call self, keys, keywords
97
+ super(**super_parameters.keyword_slice(keywords, keys:), &block)
97
98
  end
98
99
  end
99
100
  end
100
101
 
101
102
  def define_readers
102
- methods = dependencies.names.map { |name| ":#{name}" }
103
+ methods = dependencies.keys.map { |key| ":#{key}" }
103
104
  computed_scope = METHOD_SCOPES.include?(scope) ? scope : :private
104
105
 
105
106
  instance_module.module_eval <<-READERS, __FILE__, __LINE__ + 1
106
107
  attr_reader :infused_keys
108
+
109
+ def infused_names
110
+ warn "`Inusible#infused_names` is deprecated, use `#infused_keys` instead.",
111
+ category: :deprecated
112
+ @infused_names
113
+ end
114
+
107
115
  #{computed_scope} attr_reader #{methods.join ", "}
108
116
  READERS
109
117
  end
@@ -3,9 +3,9 @@
3
3
  module Infusible
4
4
  # Sanitizes and resolves dependencies for use.
5
5
  class DependencyMap
6
- PATTERNS = {name: /([a-z_][a-zA-Z_0-9]*)$/, valid: /^[\w.]+$/}.freeze
6
+ PATTERNS = {key: /([a-z_][a-zA-Z_0-9]*)$/, valid: /^[\w.]+$/}.freeze
7
7
 
8
- attr_reader :names
8
+ attr_reader :keys
9
9
 
10
10
  def initialize *configuration, patterns: PATTERNS
11
11
  @patterns = patterns
@@ -13,10 +13,10 @@ module Infusible
13
13
 
14
14
  aliases = configuration.last.is_a?(Hash) ? configuration.pop : {}
15
15
 
16
- configuration.each { |identifier| add to_name(identifier), identifier }
17
- aliases.each { |name, identifier| add name, identifier }
16
+ configuration.each { |identifier| add to_key(identifier), identifier }
17
+ aliases.each { |key, identifier| add key, identifier }
18
18
 
19
- @names = collection.keys.freeze
19
+ @keys = collection.keys.freeze
20
20
  end
21
21
 
22
22
  def to_h = collection
@@ -25,20 +25,20 @@ module Infusible
25
25
 
26
26
  attr_reader :patterns, :collection
27
27
 
28
- def to_name identifier
29
- name = identifier[patterns.fetch(:name)]
28
+ def to_key identifier
29
+ key = identifier[patterns.fetch(:key)]
30
30
 
31
- return name if name && name.match?(patterns.fetch(:valid))
31
+ return key if key && key.match?(patterns.fetch(:valid))
32
32
 
33
33
  fail(Errors::InvalidDependency.new(identifier:))
34
34
  end
35
35
 
36
- def add name, identifier
37
- name = name.to_sym
36
+ def add key, identifier
37
+ key = key.to_sym
38
38
 
39
- return collection[name] = identifier unless collection.key? name
39
+ return collection[key] = identifier unless collection.key? key
40
40
 
41
- fail Errors::DuplicateDependency.new name:, identifier:
41
+ fail Errors::DuplicateDependency.new key:, identifier:
42
42
  end
43
43
  end
44
44
  end
@@ -4,8 +4,8 @@ module Infusible
4
4
  module Errors
5
5
  # Prevents duplicate dependencies from being injected.
6
6
  class DuplicateDependency < StandardError
7
- def initialize name:, identifier:
8
- super "Remove #{identifier.inspect} since it's a duplicate of #{name.inspect}."
7
+ def initialize key:, identifier:
8
+ super "Remove #{identifier.inspect} since it's a duplicate of #{key.inspect}."
9
9
  end
10
10
  end
11
11
  end
@@ -7,14 +7,27 @@ module Infusible
7
7
  module Stub
8
8
  refine Actuator do
9
9
  def stub_with(pairs, &)
10
+ warn "`#{self.class}##{__method__}` is deprecated, use the Containable gem instead.",
11
+ category: :deprecated
12
+
10
13
  return unless block_given?
11
14
 
12
15
  container.is_a?(Hash) ? stub_hash_with(pairs, &) : stub_container_with(pairs, &)
13
16
  end
14
17
 
15
- def stub(pairs) = container.is_a?(Hash) ? stub_hash(pairs) : stub_container(pairs)
18
+ def stub pairs
19
+ warn "`#{self.class}##{__method__}` is deprecated, use the Containable gem instead",
20
+ category: :deprecated
21
+
22
+ container.is_a?(Hash) ? stub_hash(pairs) : stub_container(pairs)
23
+ end
16
24
 
17
- def unstub(*keys) = container.is_a?(Hash) ? unstub_hash(*keys) : unstub_container(*keys)
25
+ def unstub(*keys)
26
+ warn "`#{self.class}##{__method__}` is deprecated, use the Containable gem instead",
27
+ category: :deprecated
28
+
29
+ container.is_a?(Hash) ? unstub_hash(*keys) : unstub_container(*keys)
30
+ end
18
31
 
19
32
  private
20
33
 
data/lib/infusible.rb CHANGED
@@ -1,21 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "zeitwerk"
4
-
5
- Zeitwerk::Loader.new.then do |loader|
6
- loader.tag = File.basename __FILE__, ".rb"
7
- loader.ignore "#{__dir__}/infusible/stub"
8
- loader.push_dir __dir__
9
- loader.setup
10
- end
3
+ require "infusible/actuator"
4
+ require "infusible/constructor"
5
+ require "infusible/dependency_map"
6
+ require "infusible/errors/duplicate_dependency"
7
+ require "infusible/errors/invalid_dependency"
11
8
 
12
9
  # Main namespace.
13
10
  module Infusible
14
11
  METHOD_SCOPES = %i[public protected private].freeze
15
12
 
16
- def self.loader registry = Zeitwerk::Registry
17
- @loader ||= registry.loaders.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
18
- end
13
+ def self.[](container) = Actuator.new container
19
14
 
20
- def self.with(container) = Actuator.new container
15
+ def self.with container
16
+ warn "`Infusible.#{__method__}` is deprecated, use `.[]` instead.", category: :deprecated
17
+ Actuator.new container
18
+ end
21
19
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: infusible
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -35,7 +35,7 @@ cert_chain:
35
35
  3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
36
36
  gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
37
37
  -----END CERTIFICATE-----
38
- date: 2024-03-03 00:00:00.000000000 Z
38
+ date: 2024-04-03 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: marameters
@@ -51,20 +51,6 @@ dependencies:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '3.0'
54
- - !ruby/object:Gem::Dependency
55
- name: zeitwerk
56
- requirement: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '2.6'
61
- type: :runtime
62
- prerelease: false
63
- version_requirements: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '2.6'
68
54
  description:
69
55
  email:
70
56
  - brooke@alchemists.io
@@ -110,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
96
  - !ruby/object:Gem::Version
111
97
  version: '0'
112
98
  requirements: []
113
- rubygems_version: 3.5.6
99
+ rubygems_version: 3.5.7
114
100
  signing_key:
115
101
  specification_version: 4
116
102
  summary: An automated dependency manager and injector.
metadata.gz.sig CHANGED
Binary file