dbg_tags 1.0.1 → 1.1.0

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 +149 -119
  3. data/spec/01_tag_spec.rb +45 -0
  4. metadata +6 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0665b5e4280aea457cd828d6cfab8730c71502fc8e32daae72904bd60abe87b3
4
- data.tar.gz: 7ad792027dc763687f856bdae2126d5ad8816b949dc4b16365420c78c9b3aa10
3
+ metadata.gz: aaad620ad2b1c43ee4fad44431ff99f22d5fe07f66dbb68eb11247246d99083e
4
+ data.tar.gz: e33c27bb2b870e18bd4a910ef0918db018174f89eb3aaf95c2619bca74e0dee6
5
5
  SHA512:
6
- metadata.gz: 4cf3f313c0f1c54978f2b9e9538e99c80e8a9a3148fb85f03c5f63b87305db344e508745fce939e5dc94e32550a058515986cef7c282950450c506a61748e82c
7
- data.tar.gz: 5bb9dafd4b182778c9e6ff07208cae8f9b6b713eef2c4ab4fef89c8d20e973faf06a9e442b28d627cc1180e4e6459250bb1a8f0431b7cd259d5e5c486652db57
6
+ metadata.gz: 660f4307b55f0c7b0ff5e029916b436f000346c31cca80e1956eaada5a71599a2e1e21f654bc0d8cd6dfb086e0489445a4f4385394ec4f558e8f8284a9aaee59
7
+ data.tar.gz: 5be152c20aa033ba1372d132b7f514a0ddbd5fe5da459148e9790f120ad5c342564e24402c344cfb61aee4e437aa16238380b13f9a86520fe624242f1c4ec00b
data/lib/dbg_tags.rb CHANGED
@@ -3,45 +3,41 @@
3
3
  #
4
4
  # # enabling
5
5
  # # -----------
6
- # require 'dbg_tags'
6
+ # require 'dbg_tags'
7
7
  #
8
- # Tag.enable :feature1, :feature2..., featureN: :log, featureO: :val, ...
9
- # Tag.enable feature1: :trc, feature2: :val
10
- # Tag.enable feature: Tag::TRC
11
- # Tag.enable :dtl # enables ALL logging for :generic
12
- # Tag.enable :val # enables val+trc+log+err for :generic only
13
- # Tag.enable :trc # enables trc+log+err for :generic only
14
- # Tag.enable :log # enables log+err tags for :generic
15
- # Tag.enable :err # enables err tags for :generic
16
- # Tag.enable # sets :generic to :trc
17
- # Tag.enable(...) do ... end
18
- # Tag.enable feature: nil
19
- # Tag.enable feature: :nil
20
- # Tag.enable all: :err # :all is a default for ALL systems, including :generic
21
- # Tag.enable test: :err # switch on paranoia checking
22
- # Tag.enable feature: '>=trc' # make sure at least level trc
8
+ # Tag.enable :feature1, :feature2..., featureN: :log, featureO: :val, ...
9
+ # Tag.enable feature1: :trc, feature2: :val
10
+ # Tag.enable feature: Tag::TRC
11
+ # Tag.enable :dtl # enables ALL logging for :generic
12
+ # Tag.enable :val # enables val+trc+log+err for :generic only
13
+ # Tag.enable :trc # enables trc+log+err for :generic only
14
+ # Tag.enable :log # enables log+err tags for :generic
15
+ # Tag.enable :err # enables err tags for :generic
16
+ # Tag.enable # sets :generic to :trc
17
+ # Tag.enable(...) do ... end
18
+ # Tag.enable feature: nil
19
+ # Tag.enable feature: :nil
20
+ # Tag.enable all: :err # :all is a default for ALL systems, including :generic
21
+ # Tag.enable test: :err # switch on paranoia checking
22
+ # Tag.enable feature: '>=trc' # make sure at least level trc
23
23
  #
24
24
  # # logging
25
25
  # # -----------
26
- # Tag.err 'text', short for Tag.err(:generic) 'text'
26
+ # Tag.err 'text', short for Tag.err(:generic) 'text'
27
27
  # # :err should be used for fail states and paranoia stuff
28
- # Tag.log 'text' # prints very important messages only
29
- # Tag.trc 'text' # default level, method entries, for example
30
- # Tag.val 'text' # prints more details
31
- # Tag.dtl 'text' # likely prints megabytes of details
32
- # Tag.err :feature, 'FAILURE'
33
- # Tag.log :feature, 'log me'
34
- # Tag.trc :feature, 'called method'
35
- # Tag.val(:feature) { "text#{expr}" }
36
- # Tag.dtl(:feature) { "text#{very complicated expr}" }
37
- # Tag.err(:test) { raise 'aaaarg' if complex_paranoia_failure }
38
- # Tag.err(:test) { raise 'CANTHAPPEN' if complex_paranoia_failure }
28
+ # Tag.log 'text' # prints very important messages only
29
+ # Tag.trc 'text' # default level, method entries, for example
30
+ # Tag.val 'text' # prints more details
31
+ # Tag.dtl 'text' # likely prints megabytes of details
32
+ # Tag.err :feature, 'FAILURE'
33
+ # Tag.log :feature, 'log me'
34
+ # Tag.trc :feature, 'called method'
35
+ # Tag.val(:feature) { "text#{expr}" }
36
+ # Tag.dtl(:feature) { "text#{very complicated expr}" }
37
+ # Tag.err(:test) { raise 'aaaarg' if complex_paranoia_failure }
38
+ # Tag.err(:test) { raise 'CANTHAPPEN' if complex_paranoia_failure }
39
39
 
40
40
  module Tag
41
-
42
- # the default is :trc
43
- TAG_DEFAULT_LEVEL = 3
44
-
45
41
  # :all overrides the minimum level on ALL tags in the system
46
42
  TAG_FEATURE_ALL = :all
47
43
 
@@ -66,81 +62,26 @@ module Tag
66
62
  # level 5. Mostly used for exhaustive dumping of attribute values and minor details
67
63
  DTL = 5
68
64
 
65
+ # the default is :trc
66
+ TAG_DEFAULT_LEVEL = TRC
67
+
69
68
  # nil and :nil will both map to NONE
70
69
  TAG_MAPPING = { none: NONE, err: ERR, log: LOG, trc: TRC, val: VAL, dtl: DTL,
71
70
  nil: NONE,
72
71
  nil => NONE
73
72
  } # TAG_MAPPING
74
73
 
75
- # @@enabled[:feature] => 0..5
76
- @@enabled = {}
77
- @@stream = STDERR
78
-
79
- module InstanceMethods
80
- @@inside = false
81
-
82
- # @param feature [Symbol,nil] Subsystem to print logging for. Fully dynamic/free
83
- # @param msg [String,nil]
84
- # @note feature and msg can be switched
85
- # @param block [Proc,nil] If set the result overrides and msg passed.
86
- # The call is silently ignored if called from inside another Tag block (likely
87
- # a sign of a stack overflow in process).
88
- # The call is silently ignored if the current tag level is too low.
89
- # For trc it should be trc or val or dtl to actually print something.
90
- # @!method trc feature = TAG_FEATURE_GENERIC, msg = '', &block
91
-
92
- # see trc
93
- # !method err feature = TAG_FEATURE_GENERIC, msg = '', &block
94
-
95
- # see trc
96
- # !method log feature = TAG_FEATURE_GENERIC, msg = '', &block
97
-
98
- # see trc
99
- # !method val feature = TAG_FEATURE_GENERIC, msg = '', &block
100
-
101
- # see trc
102
- # !method dtl feature = TAG_FEATURE_GENERIC, msg = '', &block
103
-
104
- TAG_MAPPING.each do |meth, lev|
105
- next if lev == NONE
106
- define_method meth do |feature = TAG_FEATURE_GENERIC, msg = '', &msg_block|
107
- msg, feature = feature, TAG_FEATURE_GENERIC if String === feature
108
- #STDERR.puts "DEBUGTAG #{meth}. feature=#{feature}, level=#{Tag.level(feature)}, lev=#{lev}"
109
- return if @@inside || (Tag.level(feature) || Tag::NONE) < lev
110
- # either msg OR msg_block must be set
111
- if msg_block
112
- prev_inside = @@inside
113
- begin
114
- @@inside = true
115
- msg = msg_block.call
116
- ensure
117
- @@inside = prev_inside
118
- end
119
- end
120
- if msg
121
- c = caller[0]
122
- #STDERR.puts "DEBUGTAG c[#{idx}] = #{c}, caller[1]=#{caller[1]}, caller[2]=#{caller[2]}"
123
- label = c[/\w+\.rb:\d+:in `[^']+'/]&.sub(/in `([^']+)'/, '\1:') ||
124
- c[/\w+\.rb:\d+:/] ||
125
- c[/[^:\/]+:\d+:/] ||
126
- c
127
- Tag.stream.print "#{label} #{msg}\n"
128
- end
129
- end # Tag.err, Tag.log, Tag.trc, Tag.val, Tag.dtl
130
- end # each
131
-
132
- # inside? -> true if we are currently executing a block in err/log/trc/val or dtl.
133
- def inside?; @@inside; end
134
-
135
- end # module Tag::InstanceMethods
74
+ # This class stores an instance of the global state of the Tag system
75
+ class GlobalState
76
+ private
77
+ def initialize
78
+ # @enabled[:feature] => 0..5
79
+ @enabled = {}
80
+ @inside = false
81
+ @stream = STDERR
82
+ end # GlobalState.initialize
136
83
 
137
- extend InstanceMethods
138
- include InstanceMethods
139
-
140
- class << self
141
- private # class methods of Tag
142
-
143
- # @param level_spec [Integer,Symbol,String]
84
+ # @param level_spec [Integer,Symbol,String,nil]
144
85
  # @param feature [Symbol]
145
86
  # @return [0..5]
146
87
  def debunk_level level_spec, feature
@@ -148,6 +89,7 @@ module Tag
148
89
  # OK STDERR.puts "DEBUNK: level_spec=#{level_spec.inspect}, feature=#{feature.inspect}"
149
90
  case level_spec
150
91
  when 0..5 then return level_spec
92
+ when nil then return NONE
151
93
  when Symbol
152
94
  r = TAG_MAPPING[level_spec] and return r
153
95
  when /\A(err|log|trc|val|dtl)\z/
@@ -161,9 +103,21 @@ module Tag
161
103
  raise ArgumentError, "bad level #{level_spec.inspect}"
162
104
  end # Tag::debunk_level
163
105
 
164
- public # class methods of Tag
106
+ public # methods of GlobalState
107
+
108
+ # @return [{Symbol} => 0..5]
109
+ attr :enabled
110
+
111
+ # @return [Bool] True if a Tag.err..dtl is currently active
112
+ attr_accessor :inside
113
+ alias inside? inside
165
114
 
166
- # @param features [<Symbol>]
115
+ # @return [IO] Current output stream
116
+ attr_accessor :stream
117
+
118
+ # @param features [<Symbol>] To enable on :trc level
119
+ # @param opts [{Symbol => Symbol}] Keys are features, values levels.
120
+ # A block can be given to restore the original state afterwards
167
121
  # enable :feature, ...[, feature: level, ...] [block]
168
122
  # :generic is NO LONGER IMPLICETELY ENABLED as of version 1.0.0
169
123
  # Use :all to set a default for all features not mentioned otherwise
@@ -172,62 +126,138 @@ module Tag
172
126
  # Strings can be used in the shape of 'err' or '>=err' etc.
173
127
  # If '>=LVL' is used the level will not lower, if already set in an outer block.
174
128
  # If no level is specified for a feature the default is :trc (== TRC == 3)
175
- # use nil or :none to disable all tags, even the ERR level ones.
129
+ # use nil, :nil, :none or Tag::NONE to disable all tags, even the ERR level ones.
176
130
  #
177
131
  # enable performs a merge with an existing enable.
178
132
  def enable *features, **opts
179
- org_enabled = @@enabled.dup # to restore the state at the end (unused unless block_given)
133
+ org_enabled = @enabled.dup # to restore the state at the end (unused unless block_given)
180
134
  features.each do |feature|
181
135
  case feature
182
136
  when 0..5 # not a feature, apply to :generic
183
- @@enabled[TAG_FEATURE_GENERIC] = feature
137
+ @enabled[TAG_FEATURE_GENERIC] = feature
184
138
  when Symbol
185
139
  if TAG_MAPPING[feature] # not a feature
186
- @@enabled[TAG_FEATURE_GENERIC] = TAG_MAPPING[feature]
140
+ @enabled[TAG_FEATURE_GENERIC] = TAG_MAPPING[feature]
187
141
  else
188
- @@enabled[feature] = TAG_DEFAULT_LEVEL
142
+ @enabled[feature] = TAG_DEFAULT_LEVEL
189
143
  end
190
144
  when String
191
- @@enabled[TAG_FEATURE_GENERIC] = debunk_level feature, TAG_FEATURE_GENERIC
145
+ @enabled[TAG_FEATURE_GENERIC] = debunk_level feature, TAG_FEATURE_GENERIC
192
146
  else
193
147
  raise ArgumentError "bad level #{feature.inspect}"
194
148
  end # case
195
149
  end # each
196
150
  opts.each do |feature, level|
197
151
  # OK STDERR.puts "OPTION!!!!!!!!!!!!!!!!!, calling debunk_level"
198
- @@enabled[feature] = debunk_level level, feature
152
+ @enabled[feature] = debunk_level level, feature
199
153
  end
200
154
  if features.empty? && opts.empty?
201
- @@enabled[TAG_FEATURE_GENERIC] = TAG_DEFAULT_LEVEL
155
+ @enabled[TAG_FEATURE_GENERIC] = TAG_DEFAULT_LEVEL
202
156
  end
203
157
  if block_given?
204
- # STDERR.puts "TAG: block_given!"
205
158
  begin
206
- # STDERR.puts "TAG: yield!"
207
159
  yield
208
160
  ensure
209
- @@enabled = org_enabled
161
+ @enabled = org_enabled
210
162
  end # ensure
211
163
  end # block_given?
212
- end # Tag.enable
164
+ end # GlobalState.enable
165
+
166
+ # @param feature [Symbol]
167
+ # @return [0..5] Current effective level for feature.
168
+ def level feature
169
+ @enabled[feature] || @enabled[TAG_FEATURE_ALL] || Tag::NONE
170
+ end # GlobalState.level
171
+ end # GlobalState
172
+
173
+ class << self
174
+
175
+ public # class methods of Tag
176
+
177
+ # @return [GlobalState] Thread local data
178
+ def global_state
179
+ if gs = Thread.current[:dbg_tags_global_state]
180
+ gs
181
+ else
182
+ Thread.current[:dbg_tags_global_state] = GlobalState.new
183
+ end
184
+ end # Tag::global_state
185
+
186
+ # @param feature [Symbol,nil] Subsystem to print logging for. Fully dynamic/free
187
+ # @param msg [String,nil]
188
+ # @note feature and msg can be switched
189
+ # @param block [Proc,nil] If set the result overrides and msg passed.
190
+ # The call is silently ignored if called from inside another Tag block (likely
191
+ # a sign of a stack overflow in process).
192
+ # The call is silently ignored if the current tag level is too low.
193
+ # For trc it should be trc or val or dtl to actually print something.
194
+ # @!method trc feature = TAG_FEATURE_GENERIC, msg = '', &block
195
+
196
+ # @!method err feature = TAG_FEATURE_GENERIC, msg = '', &block
197
+ # @see trc
198
+
199
+ # @!method log feature = TAG_FEATURE_GENERIC, msg = '', &block
200
+ # @see trc
201
+
202
+ # @!method val feature = TAG_FEATURE_GENERIC, msg = '', &block
203
+ # @see trc
204
+
205
+ # @!method dtl feature = TAG_FEATURE_GENERIC, msg = '', &block
206
+ # @see trc
207
+
208
+ TAG_MAPPING.each do |meth, lev|
209
+ next if lev == NONE
210
+ define_method meth do |feature = TAG_FEATURE_GENERIC, msg = '', &msg_block|
211
+ state = global_state
212
+ msg, feature = feature, TAG_FEATURE_GENERIC if String === feature
213
+ #STDERR.puts "DEBUGTAG #{meth}. feature=#{feature}, level=#{Tag.level(feature)}, lev=#{lev}"
214
+ return if state.inside? || (state.level(feature) || Tag::NONE) < lev
215
+ # either msg OR msg_block must be set
216
+ if msg_block
217
+ prev_inside = state.inside?
218
+ begin
219
+ state.inside = true
220
+ msg = msg_block.call
221
+ ensure
222
+ state.inside = prev_inside
223
+ end
224
+ end
225
+ if msg
226
+ c = caller[0]
227
+ #STDERR.puts "DEBUGTAG c[#{idx}] = #{c}, caller[1]=#{caller[1]}, caller[2]=#{caller[2]}"
228
+ label = c[/\w+\.rb:\d+:in `[^']+'/]&.sub(/in `([^']+)'/, '\1:') ||
229
+ c[/\w+\.rb:\d+:/] ||
230
+ c[/[^:\/]+:\d+:/] ||
231
+ c
232
+ state.stream.print "#{label} #{msg}\n"
233
+ end
234
+ end # Tag.err, Tag.log, Tag.trc, Tag.val, Tag.dtl
235
+ end # each
236
+
237
+ # inside? -> true if we are currently executing a block in err/log/trc/val or dtl.
238
+ def inside?; global_state.inside?; end
239
+
240
+ # @see GlobalState.enable
241
+ def enable(...); global_state.enable(...); end
213
242
 
214
243
  # @return [{Symbol=>0..5}] Keys are the features
215
- def enabled; @@enabled; end
244
+ def enabled; global_state.enabled; end
216
245
 
217
246
  # @return [IO] By default this is STDERR
218
- def stream; @@stream; end
247
+ def stream; global_state.stream; end
219
248
 
220
249
  # @param val [IO]
221
250
  # Override the output stream.
222
- def stream= val; @@stream = val; end
251
+ def stream= val; global_state.stream = val; end
223
252
 
224
253
  # @param feature [Symbol]
225
254
  # @return [0..5] Current effective level for feature.
226
255
  # 2023-08-14 no longer returns nil
227
- def level feature; @@enabled[feature] || @@enabled[TAG_FEATURE_ALL] || Tag::NONE; end
256
+ def level feature; global_state.level feature; end
228
257
 
229
258
  # @param feature [Symbol]
230
259
  # @return [bool] Reflects explicit enable calls only. The :all feature is IGNORED
231
- def enabled? feature; (@@enabled[feature] || NONE) > NONE; end
260
+ def enabled? feature; (global_state.enabled[feature] || NONE) > NONE; end
261
+
232
262
  end # singleton class Tag
233
263
  end # module Tag
data/spec/01_tag_spec.rb CHANGED
@@ -175,6 +175,12 @@ describe 'tag' do
175
175
  end
176
176
  end
177
177
 
178
+ it 'is allowed to use nil for :nil in enable (tag_110)' do
179
+ Tag.enable feature: nil do
180
+ expect(Tag.enabled[:feature]).to eq Tag::NONE
181
+ end
182
+ end # it
183
+
178
184
  # however, it only works with LAZY calls.
179
185
  # def to_s; Tag.trc "HERE in #{self}"; super; end
180
186
  # will OBVIOUSLY cause a stack overflow.
@@ -246,6 +252,44 @@ describe 'tag' do
246
252
  end # it
247
253
  end # context 'Nested levels'
248
254
 
255
+ it 'has thread local data to prevent mix ups (tag_300)' do
256
+ t1 = Thread.new do
257
+ Tag.enable threads: :trc do
258
+ Tag.trc(:threads) {
259
+ expect(Tag.inside?).to be true
260
+ sleep 1
261
+ nil
262
+ }
263
+ end
264
+ end
265
+ t2 = Thread.new do
266
+ sleep 0.2
267
+ expect(Tag.enabled).to eq({})
268
+ expect(Tag.inside?).to be false
269
+ end
270
+ t1.join
271
+ t2.join
272
+ end # it
273
+
274
+ it 'each thread has a private tag system (tag_301)' do
275
+ Tag.enable threads: :trc do
276
+ expect(Tag.enabled).to eq({threads: 3})
277
+ t1 = Thread.new do
278
+ expect(Tag.enabled).to eq({})
279
+ Tag.enable threads: :log do
280
+ expect(Tag.enabled).to eq({threads: 2})
281
+ Tag.trc(:threads) {
282
+ expect(Tag.inside?).to be true
283
+ sleep 1
284
+ nil
285
+ }
286
+ end
287
+ end
288
+ t1.join
289
+ expect(Tag.enabled).to eq({threads: 3})
290
+ end
291
+ end # it
292
+
249
293
  it 'does not allow levels out of range (tag_900)' do
250
294
  expect do
251
295
  Tag.enable nest: 24
@@ -263,4 +307,5 @@ describe 'tag' do
263
307
  Tag.enable nest: '>=foo'
264
308
  end.to raise_error ArgumentError, /bad level/i
265
309
  end # it
310
+
266
311
  end # describe
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.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugene Brazwick
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-14 00:00:00.000000000 Z
11
+ date: 2024-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -66,7 +66,7 @@ homepage: https://github.com/Eugene-Brazwick/dbg_tags
66
66
  licenses:
67
67
  - GPL-3.0
68
68
  metadata: {}
69
- post_install_message:
69
+ post_install_message:
70
70
  rdoc_options: []
71
71
  require_paths:
72
72
  - lib
@@ -74,7 +74,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
74
  requirements:
75
75
  - - ">="
76
76
  - !ruby/object:Gem::Version
77
- version: '2.7'
77
+ version: '3.0'
78
78
  required_rubygems_version: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
@@ -82,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
82
  version: '0'
83
83
  requirements: []
84
84
  rubygems_version: 3.3.5
85
- signing_key:
85
+ signing_key:
86
86
  specification_version: 4
87
87
  summary: a versatile dynamic debug tracing system
88
88
  test_files: