thread_local_var_accessors 1.0.0 → 1.3.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +11 -1
- data/README.md +112 -62
- data/lib/thread_local_var_accessors/version.rb +1 -1
- data/lib/thread_local_var_accessors.rb +113 -39
- data/thread_local_var_accessors.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4537e0db3960367d75a6ab4d731026c6a425e315816bf0523d078b563b90a09a
|
4
|
+
data.tar.gz: d270efc557c3b04f41ae9adf7850157d98c793a7d57cd025e8c88a40d2aaa154
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
32
|
-
argument that is the new value.
|
33
|
-
on the instance variable named `@name`, which should be a
|
34
|
-
`Concurrent::ThreadLocalVar` instance.
|
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
|
-
|
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
|
-
|
61
|
-
|
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)
|
110
|
+
tlv_set(:timeout) # @timeout = Concurrent::ThreadLocalVar.new
|
68
111
|
@timeout.value = 0
|
69
112
|
|
70
|
-
|
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,
|
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:
|
101
|
-
and setter-method name syntax (eg
|
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
|
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
|
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
|
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
|
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
|
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
|
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,
|
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
|
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
|
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
|
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
|
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,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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
64
|
+
# which is the same as:
|
47
65
|
#
|
48
|
-
#
|
66
|
+
# @timeout ||= ThreadLocalVar.new
|
67
|
+
# @timeout.value
|
49
68
|
#
|
50
69
|
# Alternative ways to initialize the thread-local value:
|
51
70
|
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
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
|
-
|
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 =
|
209
|
-
|
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 =
|
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
|
-
|
272
|
+
else # var is not set, initialize it
|
273
|
+
tlv_new(name, value, &block).value
|
219
274
|
end
|
220
275
|
end
|
221
276
|
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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-
|
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
|