infusible 3.0.0 → 3.2.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: 9ead948e6538cdc8e066bc32341bde9763b3142993cda89a2f3e757bd43cc23f
4
- data.tar.gz: c75f2bfe1ea6c13340844d51373a9e82241aee398a2dd29184081520c6381c7b
3
+ metadata.gz: 6dc14ad940c37db70d202e1c536e89308476388dafb228c79c10632688ae1f80
4
+ data.tar.gz: 62a63f85a1bad5e32dcf76945705d87cc2ea705c337f9f047473987992d4bfff
5
5
  SHA512:
6
- metadata.gz: f6609b17d274e75e300c6867310639bb074455af38c0212e988bdf46e7c30e650a0a8000732d067462d2d73162e020a32c84e65e177ea1d2404ceb5e909e84a8
7
- data.tar.gz: 46fee24a8fb9a5817139effbb467f66cd13fb03b812ae499423c94695227d6cea24f0cae905c72e99e19744614e4a050018cae5def3e7ba225e8cb57ad175401
6
+ metadata.gz: fc043d373809d1f649d32d8ed5f0e4f993511c575125f9e02843e7a81f83b5e13bcf15e7ff070866a88a9ffa2b935d1eeb5e7ec961a2f3d9b73b660c6ffce5fe
7
+ data.tar.gz: 47006245798afea15ba7e440b2c71f8925cbbd649cc0fdb0785612aa7b6716d98bc11cee3bfd720be3c310307ad3a50c7b1d37bf7f3632ffa2cfe4a058176943
checksums.yaml.gz.sig CHANGED
Binary file
data/README.adoc CHANGED
@@ -10,7 +10,7 @@
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
- This means -- 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 {dry-container_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
  ----
@@ -73,7 +73,7 @@ require "infusible"
73
73
 
74
74
  == Usage
75
75
 
76
- There is basic and advanced usage. We'll start with basic and work our to advanced usage.
76
+ There is basic and advanced usage. We'll start with the basics and work our to more advanced usage.
77
77
 
78
78
  === Basic
79
79
 
@@ -81,7 +81,7 @@ This gem requires three steps for proper use:
81
81
 
82
82
  . A container.
83
83
  . An import constant.
84
- . A class and/or multiple classes for dependencies to be injected into.
84
+ . An object and/or multiple objects for dependencies to be injected into.
85
85
 
86
86
  Let's walk through each staring by defining a container of dependencies.
87
87
 
@@ -238,7 +238,7 @@ class Pinger
238
238
  end
239
239
  ----
240
240
 
241
- The above will ensure the logger gets passed upwards to the superclass while remaining accessible by subclass.
241
+ The above will ensure the logger gets passed upwards to the superclass while remaining accessible by the subclass.
242
242
 
243
243
  ==== Inheritance
244
244
 
@@ -289,7 +289,7 @@ end
289
289
 
290
290
  With the above, the child class will have access to both the `logger` and `http` dependencies.
291
291
 
292
- ⚠️ Be careful when using parent dependencies within your child classes since they are _private by default_. Even though you can reach them, they might change, which can break your downstream dependencies and probably should be avoided or at least defined as `protected` by your parent objects in order to avoid breaking your parent/child relationship.
292
+ ⚠️ Be careful when using parent dependencies within your child classes since they are _private by default_. Even though you can reach them, they might change, which can break your downstream dependencies and probably should be avoided or at least defined as `protected` by your parent objects in order to avoid breaking the parent/child relationship.
293
293
 
294
294
  ==== Scopes
295
295
 
@@ -299,7 +299,7 @@ By default -- and in all of the examples shown so far -- your dependencies are p
299
299
  * `include Import.protected(logger)`: Injects a _protected_ logger dependency. Useful with inheritance and a subclass needs access to the dependency.
300
300
  * `include Import.public(:logger)`: Injects a _public_ logger dependency.
301
301
 
302
- There is no `+#private+` method since `#[]` does this for you and is the recommended practice. Use of `#public` and `+#protected+` should be uses sparingly or not at all if you can avoid it. Here's an example where public, protected, and private dependencies are injected:
302
+ There is no `+#private+` method since `#[]` does this for you and is _recommended practice_. Use of `+#public+` and `+#protected+` should be used sparingly or not at all if you can avoid it. Here's an example where public, protected, and private dependencies are injected:
303
303
 
304
304
  [source,ruby]
305
305
  ----
@@ -326,9 +326,43 @@ demo.two # NoMethodError: protected method.
326
326
  demo.three # NoMethodError: private method.
327
327
  ----
328
328
 
329
+ ==== Infused Keys
330
+
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
+
333
+ Example:
334
+
335
+ [source,ruby]
336
+ ----
337
+ module Container
338
+ extend Dry::Container::Mixin
339
+
340
+ register(:one, proc { puts "One" }, call: false)
341
+ register(:two, proc { puts "Two" }, call: false)
342
+ end
343
+
344
+ Import = Infusible.with Container
345
+
346
+ class Demo
347
+ include Import[:one, :two]
348
+
349
+ def call = infused_keys.each { |key| __send__(key).call }
350
+ end
351
+
352
+ Demo.new.call
353
+ # One
354
+ # Two
355
+ ----
356
+
357
+ 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
+ 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
+
361
+ All infused keys are frozen by default.
362
+
329
363
  === Tests
330
364
 
331
- As you architect your implementation, you'll want to test your injected dependencies. You'll also want to stub, mock, or spy on them as well. Testing support is built-in for you by only needing to require the stub refinement as provided by this gem. For demonstration purposes, I'm going to assume you are using RSpec but you can adapt for whatever testing framework you are using.
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.
332
366
 
333
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:
334
368
 
@@ -381,7 +415,7 @@ RSpec.describe Action do
381
415
  end
382
416
  ----
383
417
 
384
- Notice that there is very little setup required to test the injected dependencies. You only need to use the refinement and define what you want stubbed in your `before` and `after` blocks. That's it!
418
+ Notice there is little setup required to test the injected dependencies. You only need to use the refinement and define what you want stubbed in your `before` and `after` blocks. That's it!
385
419
 
386
420
  While the above works great for a single spec, over time you'll want to reduce duplicated setup by using a shared context. Here's a rewrite of the above spec which significantly reduces duplication when needing to test multiple objects using the same dependencies:
387
421
 
@@ -453,7 +487,7 @@ bin/console
453
487
 
454
488
  === Architecture
455
489
 
456
- This gem automates a lot of the boilerplate code you'd normally have to do manually by defining your constructor, initializer, and instance variables for you. Normally, when injecting dependencies, you'd do something like this (using the `Pinger` example provided earlier):
490
+ This gem automates a lot of the boilerplate code you'd manually do by defining your constructor, initializer, and instance variables for you. Normally, when injecting dependencies, you'd do something like this (using the `Pinger` example provided earlier):
457
491
 
458
492
  [source,ruby]
459
493
  ----
@@ -493,10 +527,10 @@ Your constructor, initializer, and instance variables are all there. Only you do
493
527
  When using this gem, along with a container like {dry-container_link}, make sure to adhere to the following guidelines:
494
528
 
495
529
  * 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.
496
- * Use containers that don't have a lot of registered dependencies. If you register too many dependencies, then that means your objects are too complex and need to be simplified further.
530
+ * 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.
497
531
  * Use the `Import` constant to define _what_ is possible to import much like you'd use a `Container` to define your dependencies. Defining what is importable improves performance and should be defined in separate files for improved fuzzy file finding.
498
532
  * Use `**` to forward keyword arguments when defining an initializer which needs to pass injected dependencies upwards.
499
- * Prefer `Import#[]` over the use of `Import#public` and/or `Import#protected` as much as a possible since injected dependencies should be private, by default, in order to not break encapsulation. That said, there are times where making them public and/or protected can save you from writing more boilerplate code.
533
+ * Prefer `Import#[]` over the use of `Import#public` and/or `Import#protected` as much as a possible since injected dependencies should be private, by default, in order to not break encapsulation. That said, there are times where making them public and/or protected can save you from writing boilerplate code.
500
534
 
501
535
  == Tests
502
536
 
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.0.0"
5
+ spec.version = "3.2.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/infusible"
@@ -7,6 +7,10 @@ module Infusible
7
7
  # :reek:TooManyInstanceVariables
8
8
  class Constructor < Module
9
9
  def self.define_instance_variables target, names, keywords
10
+ unless target.instance_variable_defined? :@infused_keys
11
+ target.instance_variable_set :@infused_keys, names
12
+ end
13
+
10
14
  names.each do |name|
11
15
  next unless keywords.key?(name) || !target.instance_variable_defined?(:"@#{name}")
12
16
 
@@ -26,20 +30,25 @@ module Infusible
26
30
  @instance_module = Class.new(Module).new
27
31
  end
28
32
 
29
- def included klass
33
+ def included descendant
34
+ unless descendant.is_a? Class
35
+ fail TypeError,
36
+ "Can only infuse a class, invalid object: #{descendant} (#{descendant.class})."
37
+ end
38
+
30
39
  super
31
- define klass
32
- klass.extend class_module
33
- klass.include instance_module
40
+ define descendant
41
+ descendant.extend class_module
42
+ descendant.include instance_module
34
43
  end
35
44
 
36
45
  private
37
46
 
38
47
  attr_reader :container, :dependencies, :scope, :class_module, :instance_module
39
48
 
40
- def define klass
49
+ def define descendant
41
50
  define_new
42
- define_initialize klass
51
+ define_initialize descendant
43
52
  define_readers
44
53
  end
45
54
 
@@ -52,8 +61,8 @@ module Infusible
52
61
  end
53
62
  end
54
63
 
55
- def define_initialize klass
56
- super_parameters = Marameters.of(klass, :initialize).map do |instance|
64
+ def define_initialize descendant
65
+ super_parameters = Marameters.of(descendant, :initialize).map do |instance|
57
66
  break instance unless instance.only_bare_splats?
58
67
  end
59
68
 
@@ -94,6 +103,7 @@ module Infusible
94
103
  computed_scope = METHOD_SCOPES.include?(scope) ? scope : :private
95
104
 
96
105
  instance_module.module_eval <<-READERS, __FILE__, __LINE__ + 1
106
+ attr_reader :infused_keys
97
107
  #{computed_scope} attr_reader #{methods.join ", "}
98
108
  READERS
99
109
  end
@@ -11,13 +11,12 @@ module Infusible
11
11
  @patterns = patterns
12
12
  @collection = {}
13
13
 
14
- configuration = configuration.dup
15
14
  aliases = configuration.last.is_a?(Hash) ? configuration.pop : {}
16
15
 
17
16
  configuration.each { |identifier| add to_name(identifier), identifier }
18
17
  aliases.each { |name, identifier| add name, identifier }
19
18
 
20
- @names = collection.keys
19
+ @names = collection.keys.freeze
21
20
  end
22
21
 
23
22
  def to_h = collection
data.tar.gz.sig CHANGED
@@ -1 +1 @@
1
- R��9�i*_u߼�ū`��4>n|z�~�B7YU']zԶ�����\�W��n�j!MO���$k�<c���c]��>PYv�wL8��E�n�:P��G��~�<�\@f��J��x�ߋٻ�6�9�5�N�K
1
+ r��K��ߨ�ɨ���wG�`#,�`�ڮ{��[����I�g������
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.0.0
4
+ version: 3.2.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-01-01 00:00:00.000000000 Z
38
+ date: 2024-02-18 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: marameters
@@ -110,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
112
  requirements: []
113
- rubygems_version: 3.5.3
113
+ rubygems_version: 3.5.6
114
114
  signing_key:
115
115
  specification_version: 4
116
116
  summary: An automated dependency manager and injector.
metadata.gz.sig CHANGED
Binary file