inoculate 0.4.0 → 0.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: 7bd8610b9bbde1304734505a64fdf22c8665961e3b02d93171ac4fc6ccf313aa
4
- data.tar.gz: 66ee174fa4bd02dfd671a39a946a8343da1d63bb88f9be05ee94816d033a5e4e
3
+ metadata.gz: 7f86297ac65acf1b0193d5afc05cda7cd6970b6ffcd3699f0003256f2fc06b8b
4
+ data.tar.gz: ce435f6820bd36596f50fa23d5bfbd1a018bca2f2926f5d404f04ac0f54a1296
5
5
  SHA512:
6
- metadata.gz: bbc2655324e68cd2ad977192b81f9cbef0d63b72da91f05521c59eb91f1d58993da68dbcd8d4f6b69be5e5d93708e847f567955f80cb042761e187b64c1bcdbc
7
- data.tar.gz: ef316f9b6e6dfa9cd42811f8af5082f402d0c03478a280a2728b61ce9c706a9e0b1cd0249921d18818cfa85b28ccf81969a1330744c3d8d19e95e5fd4f73a81c
6
+ metadata.gz: 885671688aa9dc16c6bde1f677326049d8c5d53fbaf8300e77c4c86d5ded34719ba1dbee542f3baa29a1d5d6c35e75773564142aab6e159448a564a8f49ca9f0
7
+ data.tar.gz: 2b709302a5cba52f5eff6d8faae9e0d1fbfefe893c20763d6ea4865f113af010993bbf89b15cdfe6c6090a52b36e3fb9d8ff513d16d24a0741b323f7c5aff0c5
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
- ## v0.4.0 \[Unreleased]
1
+ ## v0.5.0 \[2022-10-13]
2
+
3
+ * Add thread singleton dependency registration.
4
+
5
+ ## v0.4.0 \[2022-10-13]
2
6
 
3
7
  * Add singleton dependency registration.
4
8
 
data/README.md CHANGED
@@ -210,6 +210,80 @@ This results in:
210
210
  => nil
211
211
  ```
212
212
 
213
+ #### Thread Singleton
214
+ Thread Singleton dependencies are constructed once for any thread or fiber.
215
+
216
+ ```ruby
217
+ class Counter
218
+ attr_reader :count
219
+
220
+ def initialize
221
+ @count = 0
222
+ end
223
+
224
+ def inc
225
+ @count += 1
226
+ end
227
+ end
228
+
229
+ Inoculate.initialize do |config|
230
+ config.thread_singleton(:counter) { Counter.new }
231
+ end
232
+
233
+ class Example
234
+ include Inoculate::Porter
235
+ inoculate_with :counter
236
+
237
+ def initialize(name)
238
+ @name = "Example: #{name}"
239
+ end
240
+
241
+ def to_s
242
+ counter.inc
243
+ "[#{@name}] Count is: #{counter.count}"
244
+ end
245
+ end
246
+
247
+ class AnotherExample
248
+ include Inoculate::Porter
249
+ inoculate_with :counter
250
+
251
+ def initialize(name)
252
+ @name = "AnotherExample: #{name}"
253
+ end
254
+
255
+ def to_s
256
+ 5.times { counter.inc }
257
+ "[#{@name}] Count is: #{counter.count}"
258
+ end
259
+ end
260
+
261
+ threads = %w[a b].map do |tag|
262
+ Thread.new(tag) do |t|
263
+ e = Example.new(t)
264
+ a = AnotherExample.new(t)
265
+ puts e, e, a, a
266
+ end
267
+ end
268
+
269
+ threads.each(&:join)
270
+ ```
271
+
272
+ This results in:
273
+
274
+ ```
275
+ [Example: a] Count is: 1
276
+ [Example: b] Count is: 1
277
+ [Example: b] Count is: 2
278
+ [Example: a] Count is: 2
279
+ [AnotherExample: b] Count is: 7
280
+ [AnotherExample: a] Count is: 7
281
+ [AnotherExample: b] Count is: 12
282
+ [AnotherExample: a] Count is: 12
283
+ => [#<Thread:0x000000010d703c68 (irb):177 dead>, #<Thread:0x000000010d703b50 (irb):177 dead>]
284
+ ```
285
+
286
+
213
287
  ### Renaming the Declaration API
214
288
  The `inoculate_with` API is named to avoid immediate collisions with other modules
215
289
  and code you may have. You can use it as-is, or rename it to something you see fit
@@ -36,6 +36,15 @@ module Inoculate
36
36
  nil
37
37
  end
38
38
 
39
+ # Register a thread singleton dependency.
40
+ # @see Manufacturer#thread_singleton
41
+ #
42
+ # @since 0.5.0
43
+ def thread_singleton(name, &block)
44
+ manufacturer.thread_singleton(name, &block)
45
+ nil
46
+ end
47
+
39
48
  private
40
49
 
41
50
  attr_reader :manufacturer
@@ -88,6 +88,29 @@ module Inoculate
88
88
  register_blueprint(name, :singleton, &block)
89
89
  end
90
90
 
91
+ # Register a thread singleton dependency.
92
+ #
93
+ # A thread singleton dependency gets created once per thread or fiber.
94
+ #
95
+ # @example With a block
96
+ # manufacturer.thread_singleton(:sha1_hasher) { Digest::SHA1.new }
97
+ #
98
+ # @example With a Proc
99
+ # manufacturer.thread_singleton(:sha1_hasher, &-> { Digest::SHA1.new })
100
+ #
101
+ # @param name [Symbol, #to_sym] the dependency name which will be used to access it
102
+ # @param block [Block, Proc] a factory method to build the dependency
103
+ #
104
+ # @raise [Errors::RequiresCallable] if no block is provided
105
+ # @raise [Errors::InvalidName] if the name is not a symbol, cannot be converted to a symbol,
106
+ # or is not a valid attribute name
107
+ # @raise [Errors::AlreadyRegistered] if the name has been registered previously
108
+ #
109
+ # @since 0.5.0
110
+ def thread_singleton(name, &block)
111
+ register_blueprint(name, :thread_singleton, &block)
112
+ end
113
+
91
114
  private
92
115
 
93
116
  def register_blueprint(name, lifecycle, &block)
@@ -110,6 +133,7 @@ module Inoculate
110
133
  when :transient then build_transient(name, factory)
111
134
  when :instance then build_instance(name, factory)
112
135
  when :singleton then build_singleton(name, factory)
136
+ when :thread_singleton then build_thread_singleton(name, factory)
113
137
  else raise ArgumentError, "Life cycle #{lifecycle} is not valid. Something has gone very wrong."
114
138
  end
115
139
 
@@ -144,6 +168,13 @@ module Inoculate
144
168
  end
145
169
  end
146
170
 
171
+ def build_thread_singleton(name, factory)
172
+ thread_variable_name = "icache_#{hash_name(name)}"
173
+ Module.new do
174
+ private define_method(name) { Thread.current[thread_variable_name] ||= factory.call }
175
+ end
176
+ end
177
+
147
178
  def validate_dependency_name(name)
148
179
  raise Errors::InvalidName, "name must be a symbol or convert to one" unless name.respond_to? :to_sym
149
180
  begin
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Inoculate
4
4
  # The library version.
5
- VERSION = "0.4.0"
5
+ VERSION = "0.5.0"
6
6
  end
data/sig/inoculate.rbs CHANGED
@@ -35,6 +35,7 @@ module Inoculate
35
35
  def transient: (builder_name | _ToSymbol) { () -> void } -> void
36
36
  def instance: (builder_name | _ToSymbol) { () -> void } -> void
37
37
  def singleton: (builder_name | _ToSymbol) { () -> void } -> void
38
+ def thread_singleton: (builder_name | _ToSymbol) { () -> void } -> void
38
39
  end
39
40
 
40
41
  class Configurer
@@ -43,6 +44,7 @@ module Inoculate
43
44
  def transient: (builder_name | _ToSymbol) { () -> void } -> nil
44
45
  def instance: (builder_name | _ToSymbol) { () -> void } -> nil
45
46
  def singleton: (builder_name | _ToSymbol) { () -> void } -> nil
47
+ def thread_singleton: (builder_name | _ToSymbol) { () -> void } -> nil
46
48
 
47
49
  private
48
50
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inoculate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephan Tarulli