inoculate 0.3.0 → 0.4.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: 2649bf406a68234451cc147c069a8b9d58ce91d2a1538e728a532ff4abda2180
4
- data.tar.gz: 3bf808d9e35467647432ed7d74cab98e669a41f7e887e889735c8d583844eaf7
3
+ metadata.gz: 7bd8610b9bbde1304734505a64fdf22c8665961e3b02d93171ac4fc6ccf313aa
4
+ data.tar.gz: 66ee174fa4bd02dfd671a39a946a8343da1d63bb88f9be05ee94816d033a5e4e
5
5
  SHA512:
6
- metadata.gz: ff27ab41b2f2da2cc6ebf22e434c88b626b9b0c2bf6dab505a9baa1a777faf82c60512a44bb258e19bf0ceb71315b0f0123ab724d6dcb65dfb0468d3d9cf7b35
7
- data.tar.gz: 23212f8eeb9dc79c159651ebebc93d4ca13ad7623aa2d85622fe8de7b64f993880db5837e51a072f9116bffc169f02030b0676247f1befb254e86023443436ed
6
+ metadata.gz: bbc2655324e68cd2ad977192b81f9cbef0d63b72da91f05521c59eb91f1d58993da68dbcd8d4f6b69be5e5d93708e847f567955f80cb042761e187b64c1bcdbc
7
+ data.tar.gz: ef316f9b6e6dfa9cd42811f8af5082f402d0c03478a280a2728b61ce9c706a9e0b1cd0249921d18818cfa85b28ccf81969a1330744c3d8d19e95e5fd4f73a81c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## v0.4.0 \[Unreleased]
2
+
3
+ * Add singleton dependency registration.
4
+
1
5
  ## v0.3.0 \[2022-10-11]
2
6
 
3
7
  * Add instance dependency registration.
data/README.md CHANGED
@@ -25,6 +25,7 @@ It provides several life-cycles and provides dependency access through private a
25
25
  1. [Dependency Life Cycles](#dependency-life-cycles)
26
26
  1. [Transient](#transient)
27
27
  2. [Instance](#instance)
28
+ 3. [Singleton](#singleton)
28
29
  2. [Renaming the Declaration API](#renaming-the-declaration-api)
29
30
  3. [Hide Your Dependency on Inoculate](#hide-your-dependency-on-inoculate)
30
31
  3. [Installation](#installation)
@@ -100,13 +101,16 @@ class Example
100
101
  end
101
102
  end
102
103
 
103
- puts Example.new
104
+ a = Example.new
105
+ puts a, a, a
104
106
  ```
105
107
 
106
108
  This results in:
107
109
 
108
110
  ```
109
111
  Count is: 0
112
+ Count is: 0
113
+ Count is: 0
110
114
  => nil
111
115
  ```
112
116
 
@@ -158,6 +162,54 @@ This results in:
158
162
  => nil
159
163
  ```
160
164
 
165
+ #### Singleton
166
+ Singleton dependencies are constructed once.
167
+
168
+ ```ruby
169
+ class Counter
170
+ attr_reader :count
171
+
172
+ def initialize
173
+ @count = 0
174
+ end
175
+
176
+ def inc
177
+ @count += 1
178
+ end
179
+ end
180
+
181
+ Inoculate.initialize do |config|
182
+ config.singleton(:counter) { Counter.new }
183
+ end
184
+
185
+ class Example
186
+ include Inoculate::Porter
187
+ inoculate_with :counter
188
+
189
+ def initialize(name)
190
+ @name = name
191
+ end
192
+
193
+ def to_s
194
+ counter.inc
195
+ "[#{@name}] Count is: #{counter.count}"
196
+ end
197
+ end
198
+
199
+ a = Example.new("a")
200
+ b = Example.new("b")
201
+ puts a, a, b
202
+ ```
203
+
204
+ This results in:
205
+
206
+ ```
207
+ [a] Count is: 1
208
+ [a] Count is: 2
209
+ [b] Count is: 3
210
+ => nil
211
+ ```
212
+
161
213
  ### Renaming the Declaration API
162
214
  The `inoculate_with` API is named to avoid immediate collisions with other modules
163
215
  and code you may have. You can use it as-is, or rename it to something you see fit
@@ -27,6 +27,15 @@ module Inoculate
27
27
  nil
28
28
  end
29
29
 
30
+ # Register a singleton dependency.
31
+ # @see Manufacturer#singleton
32
+ #
33
+ # @since 0.4.0
34
+ def singleton(name, &block)
35
+ manufacturer.singleton(name, &block)
36
+ nil
37
+ end
38
+
30
39
  private
31
40
 
32
41
  attr_reader :manufacturer
@@ -5,7 +5,6 @@ require "digest"
5
5
  module Inoculate
6
6
  # Registers and builds dependency injection modules.
7
7
  # @todo singleton life cycle
8
- # @todo instance life cycle
9
8
  # @todo thread singleton life cycle
10
9
  #
11
10
  # @since 0.1.0
@@ -40,16 +39,7 @@ module Inoculate
40
39
  #
41
40
  # @since 0.1.0
42
41
  def transient(name, &block)
43
- validate_dependency_name name
44
- raise Errors::AlreadyRegistered if @registered_blueprints.has_key? name
45
- raise Errors::RequiresCallable if block.nil?
46
-
47
- blueprint_name = name.to_sym
48
- @registered_blueprints[blueprint_name] = {
49
- lifecycle: :transient,
50
- factory: block,
51
- accessor_module: build_module(blueprint_name, :transient, block)
52
- }
42
+ register_blueprint(name, :transient, &block)
53
43
  end
54
44
 
55
45
  # Register an instance dependency.
@@ -72,26 +62,54 @@ module Inoculate
72
62
  #
73
63
  # @since 0.3.0
74
64
  def instance(name, &block)
65
+ register_blueprint(name, :instance, &block)
66
+ end
67
+
68
+ # Register a singleton dependency.
69
+ #
70
+ # A singleton dependency gets created once.
71
+ #
72
+ # @example With a block
73
+ # manufacturer.singleton(:sha1_hasher) { Digest::SHA1.new }
74
+ #
75
+ # @example With a Proc
76
+ # manufacturer.singleton(:sha1_hasher, &-> { Digest::SHA1.new })
77
+ #
78
+ # @param name [Symbol, #to_sym] the dependency name which will be used to access it
79
+ # @param block [Block, Proc] a factory method to build the dependency
80
+ #
81
+ # @raise [Errors::RequiresCallable] if no block is provided
82
+ # @raise [Errors::InvalidName] if the name is not a symbol, cannot be converted to a symbol,
83
+ # or is not a valid attribute name
84
+ # @raise [Errors::AlreadyRegistered] if the name has been registered previously
85
+ #
86
+ # @since 0.4.0
87
+ def singleton(name, &block)
88
+ register_blueprint(name, :singleton, &block)
89
+ end
90
+
91
+ private
92
+
93
+ def register_blueprint(name, lifecycle, &block)
75
94
  validate_dependency_name name
76
95
  raise Errors::AlreadyRegistered if @registered_blueprints.has_key? name
77
96
  raise Errors::RequiresCallable if block.nil?
78
97
 
79
98
  blueprint_name = name.to_sym
80
99
  @registered_blueprints[blueprint_name] = {
81
- lifecycle: :instance,
100
+ lifecycle: lifecycle,
82
101
  factory: block,
83
- accessor_module: build_module(blueprint_name, :instance, block)
102
+ accessor_module: build_module(blueprint_name, lifecycle, block)
84
103
  }
85
104
  end
86
105
 
87
- private
88
-
89
106
  def build_module(name, lifecycle, factory)
90
- module_name = "I#{Digest::SHA1.hexdigest(name.to_s)}"
107
+ module_name = "I#{hash_name(name)}"
91
108
  module_body =
92
109
  case lifecycle
93
110
  when :transient then build_transient(name, factory)
94
111
  when :instance then build_instance(name, factory)
112
+ when :singleton then build_singleton(name, factory)
95
113
  else raise ArgumentError, "Life cycle #{lifecycle} is not valid. Something has gone very wrong."
96
114
  end
97
115
 
@@ -105,7 +123,7 @@ module Inoculate
105
123
  end
106
124
 
107
125
  def build_instance(name, factory)
108
- cache_variable_name = "@icache_#{Digest::SHA1.hexdigest(name.to_s)}"
126
+ cache_variable_name = "@icache_#{hash_name(name)}"
109
127
  Module.new do
110
128
  define_method(name) do
111
129
  instance_variable_set(cache_variable_name, factory.call) unless instance_variable_defined?(cache_variable_name)
@@ -115,6 +133,17 @@ module Inoculate
115
133
  end
116
134
  end
117
135
 
136
+ def build_singleton(name, factory)
137
+ cache_variable_name = "@@icache_#{hash_name(name)}"
138
+ Module.new do |mod|
139
+ define_method(name) do
140
+ mod.class_variable_set(cache_variable_name, factory.call) unless mod.class_variable_defined?(cache_variable_name)
141
+ mod.class_variable_get(cache_variable_name)
142
+ end
143
+ private name
144
+ end
145
+ end
146
+
118
147
  def validate_dependency_name(name)
119
148
  raise Errors::InvalidName, "name must be a symbol or convert to one" unless name.respond_to? :to_sym
120
149
  begin
@@ -123,5 +152,9 @@ module Inoculate
123
152
  raise Errors::InvalidName, "name must be a valid attr_reader"
124
153
  end
125
154
  end
155
+
156
+ def hash_name(name)
157
+ Digest::SHA1.hexdigest(name.to_s)
158
+ end
126
159
  end
127
160
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Inoculate
4
4
  # The library version.
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
6
6
  end
data/sig/inoculate.rbs CHANGED
@@ -34,6 +34,7 @@ module Inoculate
34
34
  attr_reader registered_blueprints: Hash[builder_name, blueprint]
35
35
  def transient: (builder_name | _ToSymbol) { () -> void } -> void
36
36
  def instance: (builder_name | _ToSymbol) { () -> void } -> void
37
+ def singleton: (builder_name | _ToSymbol) { () -> void } -> void
37
38
  end
38
39
 
39
40
  class Configurer
@@ -41,6 +42,7 @@ module Inoculate
41
42
 
42
43
  def transient: (builder_name | _ToSymbol) { () -> void } -> nil
43
44
  def instance: (builder_name | _ToSymbol) { () -> void } -> nil
45
+ def singleton: (builder_name | _ToSymbol) { () -> void } -> nil
44
46
 
45
47
  private
46
48
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inoculate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephan Tarulli
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-12 00:00:00.000000000 Z
11
+ date: 2022-10-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Inoculate is a small, thread-safe dependency injection library configured entirely with Ruby.