thread_local_var_accessors 1.0.0 → 1.3.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: 44a2d47618384051b762c595994639af0699cde590462760853d3be02a611ffa
4
- data.tar.gz: 4d4e3629f6bdfa482e5f080c6576d4a74d465a6b67c567b3c169db87e3b782fa
3
+ metadata.gz: 4537e0db3960367d75a6ab4d731026c6a425e315816bf0523d078b563b90a09a
4
+ data.tar.gz: d270efc557c3b04f41ae9adf7850157d98c793a7d57cd025e8c88a40d2aaa154
5
5
  SHA512:
6
- metadata.gz: e840c90fd9f096762ee4fd12ba5c4cffc9fb6952af177375327e04395cd9734a572542f1301ada916704daa507c21aaf42d4543d4dd01538e85bdf652a631c34
7
- data.tar.gz: 826a2db9381d3f7ab70482b0c866427554e58e4c7d70e238964e34593437add0d276067a21aa2e2775f8b9dc050cf05e99776f56374f330dd2a9e952738ecda7
6
+ metadata.gz: b1ad3ff8ce74641cdb6956fe084d8bd69e2712b002805302c2ca3550d82591e2874e94322dbf3ba4123f70f8185318fb05c6ef51e8527ce6145361f72347fb64
7
+ data.tar.gz: 16ad94b606dfc4249bf344fcd859c1db7929bd026680fc8ef885e6768097c20cfbbc4753543c4989fea1095ce2876fbd525b5ba9090570fd117d79936446838b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- thread_local_var_accessors (1.0.0)
4
+ thread_local_var_accessors (1.3.0)
5
5
  concurrent-ruby
6
6
 
7
7
  GEM
@@ -9,6 +9,8 @@ GEM
9
9
  specs:
10
10
  ast (2.4.2)
11
11
  builder (3.2.4)
12
+ byebug (11.1.3)
13
+ coderay (1.1.3)
12
14
  concurrent-ruby (1.2.2)
13
15
  diff-lcs (1.5.0)
14
16
  docile (1.4.0)
@@ -16,9 +18,16 @@ GEM
16
18
  rspec-core (~> 3.0)
17
19
  ruby-progressbar (~> 1.4)
18
20
  json (2.6.3)
21
+ method_source (1.0.0)
19
22
  parallel (1.22.1)
20
23
  parser (3.2.1.1)
21
24
  ast (~> 2.4.1)
25
+ pry (0.14.2)
26
+ coderay (~> 1.1)
27
+ method_source (~> 1.0)
28
+ pry-byebug (3.10.1)
29
+ byebug (~> 11.0)
30
+ pry (>= 0.13, < 0.15)
22
31
  rainbow (3.1.1)
23
32
  rake (13.0.6)
24
33
  redcarpet (3.6.0)
@@ -74,6 +83,7 @@ PLATFORMS
74
83
  DEPENDENCIES
75
84
  bundler
76
85
  fuubar
86
+ pry-byebug
77
87
  rake
78
88
  redcarpet
79
89
  rspec
data/README.md CHANGED
@@ -28,10 +28,10 @@ variables that use `ThreadLocalVar` (TLV) objects.
28
28
  the instance variable names '@name', which is expected to be either nil,
29
29
  or already have a `Concurrent::ThreadLocalVar` instance.
30
30
 
31
- - `tlv_writer` creates an instance method with the name `name=`, which accepts a single
32
- argument that is the new value. This method checks for an existing value
33
- on the instance variable named `@name`, which should be a
34
- `Concurrent::ThreadLocalVar` instance. If `@name` value is nil, then a new
31
+ - `tlv_writer` creates an instance method with the name `name=`, which accepts a
32
+ single argument that is the new value. This method checks for an existing
33
+ value on the instance variable named `@name`, which should be a
34
+ `Concurrent::ThreadLocalVar` instance. If `@name` value is nil, then a new
35
35
  `Concurrent::ThreadLocalVar` instance is assigned to it. In either case, the
36
36
  instance variable's TLV object is assigned the new value, which is returned.
37
37
 
@@ -41,6 +41,35 @@ For reference, see [ThreadLocalVars](https://ruby-concurrency.github.io/concurre
41
41
 
42
42
  ### Instance Methods
43
43
 
44
+ The following are a brief list of the instance variable in
45
+ the `ThreadLocalVarAccessors` class.
46
+
47
+ These methods interrogate or set thread-local variable values:
48
+
49
+ tlv_get NAME # => TLV value
50
+ tlv_set NAME, VALUE # => TLV value
51
+ tlv_set NAME { VALUE } # => TLV value
52
+ tlv_set_once NAME, VALUE # => current TLV value, or new VALUE
53
+ tlv_set_once NAME { VALUE } # => current TLV value, or new VALUE
54
+
55
+ There is a method to fetch the TLV object for a given instance variable name,
56
+ but only if it is actually a TLV. If the instance variable is unassigned, or
57
+ contains a non-TLV, then `nil` is returned.
58
+
59
+ tlv_get_var NAME # => TLV object or nil
60
+
61
+ The methods below manage the default values for thread-local variables:
62
+
63
+ tlv_new NAME, DEFAULT # => new TLV
64
+ tlv_new NAME { DEFAULT } # => new TLV
65
+ tlv_init NAME, DEFAULT # => DEFAULT
66
+ tlv_init NAME { DEFAULT } # => DEFAULT
67
+ tlv_default NAME # => TLV default value for NAME
68
+ tlv_set_default NAME, VALUE # => VALUE
69
+ tlv_set_default NAME { VALUE } # => VALUE
70
+
71
+ ### Instance Variable Details
72
+
44
73
  With the accessor methods, obtaining values and setting values
45
74
  becomes very simple:
46
75
 
@@ -49,25 +78,41 @@ becomes very simple:
49
78
  timeout # fetches the current TLV value, unique to each thread
50
79
  ...
51
80
  self.timeout = 0.5 # stores the TLV value just for this thread
52
-
81
+
53
82
  The `tlv_init` method creates a _new_ TLVar and sets its default value.
54
83
 
55
- Note that the default value is used when any thread evaluates the instance
84
+ Note that the default value is used when any thread evaluates the instance
56
85
  variable and there has been no thread-specific value assignment.
57
86
 
58
- The TLV default value is used across *all* threads.
87
+ Note: It's a best practice to use `tlv_init` to set the thread-local
88
+ instance variables with non-nil defaults that may be inherited across multiple
89
+ threads.
90
+
91
+ On the other hand, if the ruby developer using threads does not rely on
92
+ any particular value (other than nil) to be inherited, then using `tlv_set`
93
+ is the right way to go.
94
+
59
95
 
60
- tlv_init(:timeout, _default_)
61
- tlv_init(:timeout) { _default_ }
96
+ The TLV default value is used across *all* threads, when there is no value
97
+ specifically assigned for a given thread.
98
+
99
+ tlv_init(:timeout, default)
100
+ tlv_init(:timeout) { default }
101
+
102
+ The `tlv_init` method is essentially the same as `tlv_set_default` followed
103
+ by `tlv_get`: it sets the default value (or block) of a given TLVar, without
104
+ affecting any possible thread-local variables already assigned.
62
105
 
63
106
  Alternative ways to initialize:
64
107
 
65
- tlv_set(:timeout, 0)
108
+ tlv_set(:timeout, 0) # => 0
66
109
 
67
- tlv_set(:timeout) # ensure that @timeout is initialized to an TLV
110
+ tlv_set(:timeout) # @timeout = Concurrent::ThreadLocalVar.new
68
111
  @timeout.value = 0
69
112
 
70
- The following methods are used within the above reader, writer, accessor
113
+ ### More Details
114
+
115
+ The following methods are used within the above reader, writer, and accessor
71
116
  methods:
72
117
 
73
118
  tlv_get(name) - fetches the value of TLV `name`
@@ -76,29 +121,29 @@ methods:
76
121
  There is a block form to `tls_set`:
77
122
 
78
123
  tlv_set(name) { |old_val| new_val }
79
-
124
+
80
125
  In addition, there is also a `tlv_set_once` method that can be used to set
81
126
  a TLV value only if has not currently be set already.
82
127
 
83
128
  tlv_set_once(name, value)
84
-
129
+
85
130
  tlv_set_once(name) { |old_val| new_value }
86
131
 
87
- For `tlv_accessor` instance variables, it's possible to use the assign operators, eg: `+=`, or `||=`.
88
- For example:
132
+ For `tlv_accessor` instance variables, it's possible to use the assign operators,
133
+ eg: `+=`, or `||=`. For example:
89
134
 
90
135
  tlv_accessor :timeout, :count
91
-
136
+
92
137
  self.timeout ||= DEFAULT_TIMEOUT
93
-
138
+
94
139
  self.count += 1
95
140
 
96
141
  ### TLV Name Arguments
97
142
 
98
143
  The `name` argument to `tlv_get` and `tlv_set` is the same as given on
99
144
  the accessor, reader, and writer methods: either a string or symbol name,
100
- automatically converted as needed to instance-variable syntax (eg: :@name),
101
- and setter-method name syntax (eg :name=).
145
+ automatically converted as needed to instance-variable syntax (eg: `:@name`),
146
+ and setter-method name syntax (eg `:name=`).
102
147
 
103
148
 
104
149
  ## Installation
@@ -115,14 +160,16 @@ Then:
115
160
 
116
161
  ## Usage
117
162
 
118
- To use the class methods, they must be included into the current module or class, with:
163
+ To use the class methods, they must be included into the current module or
164
+ class, with:
119
165
 
120
166
  class MyNewClass
121
167
  include ThreadLocalVarAccessors
122
168
  ...
123
169
  end
124
-
125
- With the include above, you can use the class methods to declare instance getter and setter methods:
170
+
171
+ With the include above, you can use the class methods to declare instance getter
172
+ and setter methods:
126
173
 
127
174
  class MyNewClass
128
175
  include ThreadLocalVarAccessors
@@ -130,24 +177,28 @@ With the include above, you can use the class methods to declare instance getter
130
177
  tlv_reader :name1
131
178
  tlv_writer :name2
132
179
  tlv_accessor :name3, :name4
133
-
180
+
134
181
  end
135
-
136
- The above invocations:
182
+
183
+ The above invocations:
137
184
 
138
185
  - create reader methods for `name1`, `name3`, and `name4`.
139
186
  - create writer methods for `name2`, `name3`, and `name4`.
140
187
 
141
- The writer methods accept a value as the second argument, or from the result of an optional, associated block.
188
+ The writer methods accept a value as the second argument, or from the result of
189
+ an optional, associated block.
142
190
 
143
- Note: to use the read-and-operate operators, eg: `+=`, `-=`, `||=`, etc., the object must have both a reader and writer method. In other words, it needs to have been created as an `tlv_accessor`.
191
+ Note: to use the read-and-operate operators, eg: `+=`, `-=`, `||=`, etc., the
192
+ object must have both a reader and writer method. In other words, it needs to
193
+ have been created as an `tlv_accessor`.
144
194
 
145
- When adapting legacy code to become thread-safe, it's sometimes necessary to use the underlying instance methods:
195
+ When adapting legacy code to become thread-safe, it's sometimes necessary to use
196
+ the underlying instance methods:
146
197
 
147
198
  tlv_get(name)
148
199
  tlv_set(name, value)
149
200
  tlv_set_once(name, value)
150
-
201
+
151
202
  Alternative block forms:
152
203
 
153
204
  tlv_set(name) { |oldval| newval }
@@ -155,14 +206,15 @@ Alternative block forms:
155
206
 
156
207
  In all cases, the `name` can be a string or symbol, with or without a leading `@`.
157
208
 
158
- Ultimately, these methods are all doing these basic accesses of the corresponding instance variables:
209
+ Ultimately, these methods are all performing basic accesses of the corresponding
210
+ instance variables:
159
211
 
160
212
  @name1 ||= ThreadLocalVar.new
161
213
  @name1.value = per_thread_value
162
214
  ...
163
215
  @name1.value # returns the per_thread_value
164
-
165
- If you prefer the style above, then you don't really need these accessor methods.
216
+
217
+ If you prefer the style above, then you don't really need these accessor methods.
166
218
 
167
219
  ### Example Usage
168
220
 
@@ -176,12 +228,26 @@ class MyClass
176
228
  tlv_reader :sleep_time
177
229
  tlv_writer :locked
178
230
 
231
+ # if the ivars will not be inherited in new threads after initialization
179
232
  def initialize(**args)
233
+ # set the current thread's local value for each ivar
180
234
  self.limit = args[:limit]
181
235
  self.timeout = args[:timeout]
182
236
  self.max_time = args[:max_time]
183
237
  self.sleep_time = args[:sleep_time]
184
238
  end
239
+
240
+ # if the ivars might possibly be inherited in new threads after
241
+ # initialization, then the defaults should be set for each thread to
242
+ # inherit.
243
+
244
+ def alt_initialize(**args)
245
+ # for each ivar, set the default value, which is inherited across all threads
246
+ tlv_init :limit, args[:limit]
247
+ tlv_init :timeout, args[:timeout]
248
+ tlv_init :max_time, args[:max_time]
249
+ tlv_init :sleep_time, args[:sleep_time]
250
+ end
185
251
 
186
252
  def run
187
253
  while count < limit && delay_time < timeout
@@ -196,34 +262,14 @@ class MyClass
196
262
  end
197
263
  ```
198
264
 
199
- There may be times where you may want to use the `tlv_`-prefix methods and not use the accessors.
200
-
201
- The following are a set of equivalencies.
202
-
203
- ```ruby
204
- tlv_accessor :timeout
205
- ```
206
-
207
- produces both the reader and writer methods, using the `tlv_get` and `tlv_set` methods.
208
-
209
- ```ruby
210
- def timeout
211
- tlv_get(:timeout)
212
- end
213
-
214
- def timeout=(val)
215
- tlv_set(:timeout, val)
216
- end
217
- ```
218
-
219
- The advantage of the block method, especially for `tlv_set_once`, is that the
220
- VALUE is only evaluated when the instance variable value is being set, and, the block will receive the old value as a parameter.
221
-
222
265
  ## Development
223
266
 
224
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
267
+ After checking out the repo, run `bin/setup` to install dependencies. Then,
268
+ run `rake spec` to run the tests. You can also run `bin/console` for an
269
+ interactive prompt that will allow you to experiment.
225
270
 
226
- For both development and testing, the environment variables described above must be defined.
271
+ For both development and testing, the environment variables described above must
272
+ be defined.
227
273
 
228
274
  ## Testing
229
275
 
@@ -231,12 +277,16 @@ For both development and testing, the environment variables described above must
231
277
 
232
278
  This repo is configured to the [gitflow](https://datasift.github.io/gitflow/IntroducingGitFlow.html) pattern, with the `develop` branch being the _default_ branch on PRs.
233
279
 
234
- The `main` branch gets updated with a PR or with a manual merge-and-push from the `develop` branch by a repo admin.
280
+ The `main` branch gets updated with a PR or with a manual merge-and-push from
281
+ the `develop` branch by a repo admin.
235
282
 
236
- When any branch is pushed, the continuous integration with causes the branch to be tested with all of the `rspec` tests _(except the integration tests)_.
283
+ When any branch is pushed, the continuous integration with causes the branch to
284
+ be tested with all of the `rspec` tests _(except the integration tests)_.
237
285
 
238
- When the `main` branch is updated and after its tests pass, the `deploy` action is invoked which causes the newest build of the gem to be pushed to rubygems.org.
286
+ When the `main` branch is updated and after its tests pass, the `deploy` action
287
+ is invoked which causes the newest build of the gem to be pushed to
288
+ rubygems.org.
239
289
 
240
290
  ## Original Author:
241
-
291
+
242
292
  Alan K. Stebbens <aks@stebbens.org>
@@ -1,3 +1,3 @@
1
1
  module ThreadLocalVarAccessors
2
- VERSION = '1.0.0'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'concurrent-ruby'
4
+
3
5
  # This module has methods making it easy to use the Concurrent::ThreadLocalVar
4
6
  # as instance variables. This makes instance variables using this code as
5
7
  # actually thread-local, without also leaking memory over time.
@@ -7,6 +9,8 @@
7
9
  # See [Why Concurrent::ThreadLocalVar](https://github.com/ruby-concurrency/concurrent-ruby/blob/master/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb#L10-L17)
8
10
  # to understand why we use TLVs instead of `Thread.current.thread_variable_(set|get)`
9
11
  #
12
+ # Class Methods
13
+ #
10
14
  # The following class methods declare `Concurrent::ThreadLocalVar` reader,
11
15
  # writer, and accessors with these class methods:
12
16
  #
@@ -32,58 +36,85 @@
32
36
  #
33
37
  # tlv_accessor :timeout
34
38
  #
39
+ # Instance Methods
40
+ #
35
41
  # Create a new TLV instance with an associated default, applied across all threads.
36
42
  #
37
- # tlv_init :timeout, default_timeout
43
+ # tlv_new :timeout, default_timeout
44
+ # tlv_new :timeout { default_timeout }
45
+ #
46
+ # This method _always_ assignes the instance variable. It is equivalent to:
38
47
  #
39
- # tlv_init :timeout { default_timeout }
48
+ # @instance_var = ThreadLocalVar.new(default)
49
+ # @instance_var = ThreadLocalVar.new { default }
50
+ #
51
+ # Assign the current thread value for the TLV variable:
52
+ #
53
+ # self.timeout = 0.5 # stores the TLV value just for this thread
40
54
  #
55
+ # which is equivalent to:
56
+ #
57
+ # @timeout ||= ThreadLocalVar.new
58
+ # @timeout.value = 0.5
41
59
  #
42
60
  # Reference the current thread value for the TLV variable:
43
61
  #
44
62
  # timeout # fetches the current TLV value, unique to each thread
45
63
  #
46
- # Assign the current thread value for the TLV variable:
64
+ # which is the same as:
47
65
  #
48
- # self.timeout = 0.5 # stores the TLV value just for this thread
66
+ # @timeout ||= ThreadLocalVar.new
67
+ # @timeout.value
49
68
  #
50
69
  # Alternative ways to initialize the thread-local value:
51
70
  #
52
- # ltv_set(:timeout, 0)
53
- #
54
- # ltv_set(:timeout) # ensure that @timeout is initialized to an LTV
55
- #
56
- # @timeout.value = 0
71
+ # tlv_set(:timeout, 0)
72
+ # tlv_set(:timeout) # ensure that @timeout is initialized to an LTV
73
+ # tlv_set_once(:timeout, value) # set timeout only if it isn't already set
57
74
  #
58
75
  # Each thread-local instance can be independently assigned a value, which defaults
59
76
  # to the _default_ value, or _block_, that was associated with the original
60
- # `ThreadLocalVar.new` method. This module also provides an easy way to do this:
77
+ # `ThreadLocalVar.new` method. This module also provides an easy way to do this.
61
78
  #
62
79
  # Initializes a TLV on the `@timeout` instance variable with a default value of
63
80
  # 0.15 seconds:
64
81
  #
65
- # tlv_init(:timeout, 0.15)
82
+ # tlv_new(:timeout, 0.15)
66
83
  #
67
84
  # This does the same, but uses a block (a Proc object) to possibly return a
68
85
  # dynamic default value, as the proc is invoked each time the TLV instance is
69
86
  # evaluted in a Thread.
70
87
  #
71
- # tlv_init(:sleep_time) { computed_sleep_time }
88
+ # tlv_new(:sleep_time) { computed_sleep_time }
72
89
  #
73
90
  # The block-proc is evaluated at the time the default value is needed, not when
74
91
  # the TLV is assigned to the instance variable. In other words, much later
75
92
  # during process, when the instance variable value is evaluated, _that_ is when
76
93
  # the default block is evaluated.
77
94
  #
95
+ # The `tlv_new` method always assigns a new TLVar to the named instance variable.
96
+ #
97
+ # There is a corresponding method to either create a new TLVar instance or
98
+ # assign the default value to the existing TLVar instance: `tlv_init`.
99
+ #
100
+ # tlv_init(IVAR, DEFAULT)
101
+ # tlv_init(IVAR) { DEFAULT }
102
+ #
78
103
  # Note that `tlv_init` does not assign the thread-local value; it assigns the
79
104
  # _instance variable_ to a new TLV with the given default. If any thread
80
105
  # evaluates that instance variable, the default value will be returned unless
81
- # and until each thread associates a new, thread-local value with the TLV.
106
+ # and until the current thread associates a new, thread-local value with the TLV
107
+ # instance.
108
+ #
109
+ # The purpose of `tlv_init` is to make the initialization of a TLVar be idempotent:
110
+ # a. if the TLVar does not yet exist, it is created with the default value.
111
+ # b. if the TLVar already exists, it's default value is set.
112
+ #
113
+ # In neither case are any thread-local value set; only the default.
82
114
  #
83
115
  # The default for an existing TLV can be redefined, using either an optional
84
116
  # default value, or an optional default block.
85
117
  #
86
- #
87
118
  # tlv_set_default(:timeout, new_default)
88
119
  # tlv_set_default(:timeout) { new_default }
89
120
  #
@@ -145,10 +176,7 @@
145
176
  # To assign a new value to an TLV instance:
146
177
  #
147
178
  # @timeout.value = new_value
148
-
149
- require 'concurrent-ruby'
150
-
151
- # methods for making usage of ThreadLocalVars easy
179
+ #
152
180
  module ThreadLocalVarAccessors
153
181
  # @!visibility private
154
182
  module MyRefinements
@@ -200,45 +228,89 @@ module ThreadLocalVarAccessors
200
228
  end
201
229
 
202
230
  # instance methods
231
+ # Returns the value of the TLV instance variable, if any.
203
232
  def tlv_get(name)
204
- instance_variable_get(name.to_ivar)&.value
233
+ tlv_get_var(name)&.value
205
234
  end
206
235
 
236
+ # @return [ThreadLocalVar] the TLV, if any, of the named instance variable.
237
+ def tlv_get_var(name)
238
+ var = instance_variable_get(name.to_ivar)
239
+ var if var.is_a?(Concurrent::ThreadLocalVar)
240
+ end
241
+
242
+ # If the instance variable is already a TLV, then set it's value to the
243
+ # given value, or the value returned by the block, if any. If the
244
+ # instance variable is not a TLV, then create a new TLV, initializing
245
+ # it's default value with the given value, or the value returned by the block,
246
+ # if any, then, returning it's local value -- which returns the default value.
247
+ #
248
+ # This method is equivalent to:
249
+ # if @name.is_a?(ThreadLocalVar)
250
+ # @name.value = block_given? ? yield : value
251
+ # else
252
+ # @name = ThreadLocalVar(value, &block)
253
+ # end
254
+ # @return [Object] the value of the TLV instance variable
207
255
  def tlv_set(name, value = nil, &block)
208
- var = instance_variable_get(name.to_ivar) || tlv_new(name)
209
- tlv_set_var(var, value, &block)
256
+ if (var = tlv_get_var(name))
257
+ tlv_set_var(var, value, &block)
258
+ else
259
+ tlv_new(name, value, &block).value
260
+ end
210
261
  end
211
262
 
263
+ # Sets the thread-local value of the TLV instance variable, but only
264
+ # if it is not already set. It is equivalent to:
265
+ # @name ||= ThreadLocalVar.new
266
+ # @name.value ||= block_given? yield : value
212
267
  def tlv_set_once(name, value = nil, &block)
213
- if (var = instance_variable_get(name.to_ivar)) && !var.value.nil?
268
+ if (var = tlv_get_var(name))&.value
214
269
  var.value
215
270
  elsif var # var is set, but its value is nil
216
271
  tlv_set_var(var, value, &block)
217
- else # var is not set
218
- tlv_set_var(tlv_new(name), value, &block)
272
+ else # var is not set, initialize it
273
+ tlv_new(name, value, &block).value
219
274
  end
220
275
  end
221
276
 
222
- # @param [String|Symbol] name the TLV name
223
- # @param [Object|nil] default the optional default value
224
- # @param [Proc] block the optional associated block
225
- # @return [ThreadLocalVar] a new TLV set in the instance variable
226
- # @example Default argument
227
- # tlv_init(:ivar, default_value)
228
- # @example Default block
229
- # tlv_init(:ivar) { default_value }
277
+ # Creates a new TLVar with the given default value or block.
278
+ # Equivalent to:
279
+ # @name = ThreadLocalVar.new(block_given? ? yield : default)
280
+ def tlv_new(name, default=nil, &block)
281
+ instance_variable_set(
282
+ name.to_ivar,
283
+ Concurrent::ThreadLocalVar.new(default, &block)
284
+ )
285
+ end
286
+
287
+ # Creates a new TLVar with a default, or assigns the default value to an
288
+ # existing TLVar, without affecting any existing thread-local values.
289
+ # Returns the value of the new TLVar.
290
+ # Equivalent to:
291
+ # @name ||= ThreadLocalVar.new
292
+ # @name.instance_variable_set(:@default, block_given? ? yield : default)
293
+ # @name.value
230
294
  def tlv_init(name, default=nil, &block)
231
- instance_variable_set(name.to_ivar, Concurrent::ThreadLocalVar.new(default, &block))
295
+ tlv_set_default(name, default, &block)
296
+ tlv_get(name)
232
297
  end
233
- alias tlv_new tlv_init
234
298
 
235
- # Fetches the default value for the TLVar
299
+ # Fetches the default value for the TLVar at the ivar
236
300
  def tlv_default(name)
237
- instance_variable_get(name.to_ivar)&.send(:default)
301
+ tlv_get_default(tlv_get_var(name))
302
+ end
303
+
304
+ # gets the default value from a TLV
305
+ # this masks the private ThreadLocalVar#default method
306
+ def tlv_get_default(tlv)
307
+ tlv&.send(:default)
238
308
  end
239
309
 
240
- # Sets the default value or block for the TLV _(which is applied across all threads)_
241
- def tlv_set_default(name, default=nil, &block)
310
+ # Sets the default value or block for the TLV _(which is applied across all threads)_.
311
+ # Creates a new TLV if the instance variable is not initialized.
312
+ # @return [Object] the effective default value of the TLV instance variable
313
+ def tlv_set_default(name, default=nil, &block)1
242
314
  tlv = instance_variable_get(name.to_ivar)
243
315
  if tlv
244
316
  raise ArgumentError, "tlv_set_default: can only use a default or a block, not both" if default && block
@@ -250,9 +322,11 @@ module ThreadLocalVarAccessors
250
322
  tlv.instance_variable_set(:@default_block, nil)
251
323
  tlv.instance_variable_set(:@default, default)
252
324
  end
325
+ tlv
253
326
  else
254
- tlv_init(name, default, &block)
327
+ tlv = tlv_new(name, default, &block)
255
328
  end
329
+ tlv_get_default(tlv)
256
330
  end
257
331
 
258
332
  # @!visibility private
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_development_dependency 'bundler'
21
21
  s.add_development_dependency 'fuubar'
22
+ s.add_development_dependency 'pry-byebug'
22
23
  s.add_development_dependency 'rake'
23
24
  s.add_development_dependency 'redcarpet'
24
25
  s.add_development_dependency 'rspec'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thread_local_var_accessors
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alan Stebbens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-26 00:00:00.000000000 Z
11
+ date: 2023-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement