dbg_tags 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dbg_tags.rb +56 -5
  3. data/spec/01_tag_spec.rb +96 -7
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aaad620ad2b1c43ee4fad44431ff99f22d5fe07f66dbb68eb11247246d99083e
4
- data.tar.gz: e33c27bb2b870e18bd4a910ef0918db018174f89eb3aaf95c2619bca74e0dee6
3
+ metadata.gz: 269e2882bb82fb4a015a17417744067bcbdbd6b98a6f5e799f4f57a332b6eadf
4
+ data.tar.gz: 288f736d512ba40960086f54413d149b2b7558e5223cbf5ff545e15dab79b8f6
5
5
  SHA512:
6
- metadata.gz: 660f4307b55f0c7b0ff5e029916b436f000346c31cca80e1956eaada5a71599a2e1e21f654bc0d8cd6dfb086e0489445a4f4385394ec4f558e8f8284a9aaee59
7
- data.tar.gz: 5be152c20aa033ba1372d132b7f514a0ddbd5fe5da459148e9790f120ad5c342564e24402c344cfb61aee4e437aa16238380b13f9a86520fe624242f1c4ec00b
6
+ metadata.gz: 072f1320bae3b4900d895370e17f717f125a721318a6e5a5bc393abef86507b18ca4de3c7b0f39ee4d12aa050dbd6829ceae3eb43bcdd44fe592b39da510114c
7
+ data.tar.gz: cfa63312d3ed1e16ab82d7e73737f6e87b5fe6df12dac8a11d8cec3ad6f0731c6029d43a223ed2d73e7cd2af9e07299175e2c5662854e6d725afaa51cce694ea
data/lib/dbg_tags.rb CHANGED
@@ -130,7 +130,7 @@ module Tag
130
130
  #
131
131
  # enable performs a merge with an existing enable.
132
132
  def enable *features, **opts
133
- org_enabled = @enabled.dup # to restore the state at the end (unused unless block_given)
133
+ org_enabled = @enabled.clone # to restore the state at the end (unused unless block_given)
134
134
  features.each do |feature|
135
135
  case feature
136
136
  when 0..5 # not a feature, apply to :generic
@@ -163,6 +163,21 @@ module Tag
163
163
  end # block_given?
164
164
  end # GlobalState.enable
165
165
 
166
+ # @param state [{Symbol=>0..5}] As returned by Tag.state (aka Tag.enabled)
167
+ # A block can be given to restore the original state afterwards.
168
+ # restore_state overwrites any existing enabled feature.
169
+ def restore_state state
170
+ org_enabled = @enabled.clone # to restore the state at the end (unused unless block_given)
171
+ @enabled = state.dup
172
+ if block_given?
173
+ begin
174
+ yield
175
+ ensure
176
+ @enabled = org_enabled
177
+ end # ensure
178
+ end # block_given?
179
+ end # GlobalState.restore_state
180
+
166
181
  # @param feature [Symbol]
167
182
  # @return [0..5] Current effective level for feature.
168
183
  def level feature
@@ -172,14 +187,31 @@ module Tag
172
187
 
173
188
  class << self
174
189
 
190
+ private # class methods of Tag
191
+
192
+ # @param value [Bool] Value to set
193
+ # Primarily for rspec stuff. Use {disable_fiber_local_state!} instead
194
+ def no_fiber_local_state= value
195
+ @no_fiber_local_state = value
196
+ end # Tag::no_fiber_local_state=
197
+
175
198
  public # class methods of Tag
176
199
 
177
- # @return [GlobalState] Thread local data
200
+ # @return [Bool,nil] True if we should store global state inside the Tag class itself.
201
+ attr :no_fiber_local_state
202
+ alias no_fiber_local_state? no_fiber_local_state
203
+
204
+ # @return [Bool] True (the default) if we should store global state
205
+ # in each fiber/thread of the application.
206
+ def use_fiber_local_state?; !no_fiber_local_state? end
207
+
208
+ # @return [GlobalState] Either fiber local data (default) or truly global.
178
209
  def global_state
179
- if gs = Thread.current[:dbg_tags_global_state]
180
- gs
210
+ if @no_fiber_local_state # testing undefined ivar here. But no warnings... That is good,
211
+ # at least for performance
212
+ @global_state ||= GlobalState.new
181
213
  else
182
- Thread.current[:dbg_tags_global_state] = GlobalState.new
214
+ Thread.current[:dbg_tags_global_state] ||= GlobalState.new
183
215
  end
184
216
  end # Tag::global_state
185
217
 
@@ -240,8 +272,12 @@ module Tag
240
272
  # @see GlobalState.enable
241
273
  def enable(...); global_state.enable(...); end
242
274
 
275
+ # @see GlobalState.restore_state
276
+ def restore_state(...); global_state.restore_state(...); end
277
+
243
278
  # @return [{Symbol=>0..5}] Keys are the features
244
279
  def enabled; global_state.enabled; end
280
+ alias state enabled
245
281
 
246
282
  # @return [IO] By default this is STDERR
247
283
  def stream; global_state.stream; end
@@ -259,5 +295,20 @@ module Tag
259
295
  # @return [bool] Reflects explicit enable calls only. The :all feature is IGNORED
260
296
  def enabled? feature; (global_state.enabled[feature] || NONE) > NONE; end
261
297
 
298
+ # shortcut for no_fiber_local_state := true
299
+ # By default fiber local state is enabled but this means that
300
+ # 'enabling' of tags in some fiber does not work in others.
301
+ # Or more specific, that changing the Tag state outside of any fiber
302
+ # does not effect any fibers (already) created.
303
+ # Now it is possible to transfer data into the fiber using 'resume'
304
+ # but this is a hassle.
305
+ # So: when using threads leave this enabled, as it will cause race conditions.
306
+ # when using fibers, but no threads it is probably convenient to disable it.
307
+ def disable_fiber_local_state; self.no_fiber_local_state = true end
308
+
309
+ # shortcut for no_fiber_local_state := false
310
+ # For rspec use mostly.
311
+ def enable_fiber_local_state; self.no_fiber_local_state = false end
312
+
262
313
  end # singleton class Tag
263
314
  end # module Tag
data/spec/01_tag_spec.rb CHANGED
@@ -1,6 +1,8 @@
1
1
 
2
- require 'simplecov'
3
- SimpleCov.start
2
+ if t = ENV['USE_SIMPLECOV'] and !t.empty?
3
+ require 'simplecov'
4
+ SimpleCov.start { add_filter '/spec/' }
5
+ end
4
6
 
5
7
  require_relative '../lib/dbg_tags'
6
8
 
@@ -9,7 +11,7 @@ class Pathological
9
11
  Tag.trc { "HERE in #{self}!" }
10
12
  super
11
13
  end # to_s
12
- end
14
+ end # class Pathological
13
15
 
14
16
  describe 'tag' do
15
17
  before :each do
@@ -253,6 +255,7 @@ describe 'tag' do
253
255
  end # context 'Nested levels'
254
256
 
255
257
  it 'has thread local data to prevent mix ups (tag_300)' do
258
+ Tag.enable_fiber_local_state # NOTE enabled by default, but other examples may botch it
256
259
  t1 = Thread.new do
257
260
  Tag.enable threads: :trc do
258
261
  Tag.trc(:threads) {
@@ -272,22 +275,108 @@ describe 'tag' do
272
275
  end # it
273
276
 
274
277
  it 'each thread has a private tag system (tag_301)' do
278
+ Tag.enable_fiber_local_state # NOTE enabled by default, but other examples may botch it
279
+ executed = false
275
280
  Tag.enable threads: :trc do
276
- expect(Tag.enabled).to eq({threads: 3})
281
+ expect(Tag.enabled).to eq({threads: Tag::TRC})
277
282
  t1 = Thread.new do
278
283
  expect(Tag.enabled).to eq({})
279
284
  Tag.enable threads: :log do
280
- expect(Tag.enabled).to eq({threads: 2})
281
- Tag.trc(:threads) {
285
+ expect(Tag.enabled).to eq({threads: Tag::LOG})
286
+ Tag.log(:threads) {
282
287
  expect(Tag.inside?).to be true
283
288
  sleep 1
289
+ executed = true
284
290
  nil
285
291
  }
286
292
  end
287
293
  end
288
294
  t1.join
289
- expect(Tag.enabled).to eq({threads: 3})
295
+ expect(Tag.enabled).to eq({threads: Tag::TRC})
290
296
  end
297
+ expect(executed).to be true
298
+ end # it
299
+
300
+ it 'each fiber has a private tag system (tag_302)' do
301
+ Tag.enable_fiber_local_state # NOTE enabled by default, but other examples may botch it
302
+ executed = false
303
+ Tag.enable threads: :trc do
304
+ expect(Tag.enabled).to eq({threads: Tag::TRC})
305
+ t1 = Fiber.new do
306
+ expect(Tag.enabled).to eq({})
307
+ Tag.enable threads: :log do
308
+ expect(Tag.enabled).to eq({threads: Tag::LOG})
309
+ Tag.log(:threads) {
310
+ expect(Tag.inside?).to be true
311
+ executed = true
312
+ nil
313
+ }
314
+ end
315
+ end
316
+ t1.resume
317
+ expect(Tag.enabled).to eq({threads: Tag::TRC})
318
+ end
319
+ expect(executed).to be true
320
+ end # it
321
+
322
+ it 'allows to disable fiber local state (tag_305)' do
323
+ Tag.disable_fiber_local_state
324
+ executed = false
325
+ Tag.enable threads: :trc do
326
+ expect(Tag.enabled).to eq({threads: Tag::TRC})
327
+ t1 = Fiber.new do
328
+ expect(Tag.enabled).to eq({threads: Tag::TRC})
329
+ Tag.enable threads: :log do
330
+ expect(Tag.enabled).to eq({threads: Tag::LOG})
331
+ Tag.log(:threads) {
332
+ expect(Tag.inside?).to be true
333
+ executed = true
334
+ nil
335
+ }
336
+ end
337
+ end
338
+ t1.resume
339
+ expect(Tag.enabled).to eq({threads: Tag::TRC})
340
+ expect(executed).to be true
341
+ end
342
+ end # it
343
+
344
+ it 'does allow restore_state to transfer state through a Fiber barrier (tag_310)' do
345
+ Tag.enable_fiber_local_state
346
+ did_something = false
347
+ Tag.enable example: :dtl, fiber: :trc do
348
+ state = Tag.state # same as Tag.enabled
349
+ expect(state).to eq({example: Tag::DTL, fiber: Tag::TRC})
350
+ t1 = Fiber.new do
351
+ expect(Tag.state).to eq({})
352
+ Tag.enable foo: :trc
353
+ Tag.restore_state state do
354
+ expect(Tag.state).to eq({example: Tag::DTL, fiber: Tag::TRC})
355
+ did_something = true
356
+ end
357
+ end
358
+ t1.resume
359
+ expect(Tag.state).to eq({example: Tag::DTL, fiber: Tag::TRC})
360
+ end # enable
361
+ expect(did_something).to be true
362
+ end # it
363
+
364
+ it 'does allow a nil-state to transfer state through a Fiber barrier (tag_311)' do
365
+ Tag.enable_fiber_local_state
366
+ did_something = false
367
+ state = Tag.state
368
+ expect(state).to eq({})
369
+ t1 = Fiber.new do
370
+ expect(Tag.state).to eq({})
371
+ Tag.enable foo: :trc
372
+ Tag.restore_state state do
373
+ expect(Tag.state).to eq({})
374
+ did_something = true
375
+ end
376
+ end
377
+ t1.resume
378
+ expect(Tag.state).to eq({})
379
+ expect(did_something).to be true
291
380
  end # it
292
381
 
293
382
  it 'does not allow levels out of range (tag_900)' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbg_tags
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugene Brazwick
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-06 00:00:00.000000000 Z
11
+ date: 2024-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec