thread-local 1.0.0 → 1.1.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: 96d9a2bba22cf0213da7a37e9834689cda7727e256bee89402006ddde7c34aa6
4
- data.tar.gz: 64a871588d675a66599a36aa04a2353a844063bf88ad9af500064d42aad37a86
3
+ metadata.gz: 6f4032930cf7762d586307e1bb9ced4d69b2d3f72b5f1165c616df4df6a96d85
4
+ data.tar.gz: da327e71a8e4b8c7ad46aac6bbb3a8036142a6fee070db816dbec9dcf73861f7
5
5
  SHA512:
6
- metadata.gz: ab2d8d85eaa85e6d30d30b1b28613393f447b1ecee6e278f50135641f1ab1d9507bb036d8c57d025f98605300cb69d20cc2af29edc2f2611f6153bf5a09625b9
7
- data.tar.gz: b52551c7a93f1de9ccae111a2f8ad3acafcac461c88bb40e5de953fa3a27f199f68931ed545c23eefc8ed318478f76d592fe44808fdb9d1cc711454f9075bec8
6
+ metadata.gz: 56bca34b696ab47635edbd9bfd9dd4099f59a57cccdfd795aae7b5eec739f7fb166282e383b9f546964be0251b3a4cdf08320a399f9e260c85e35cb6e762487a
7
+ data.tar.gz: 101f513ddd1a8b5900dc7ae68e7398dacd5e80418b8d9e755a130fb719c2658eb1c84dd7c25b3f8d728061bece1fb57b3baee430b7d29100308e87de08099f6a
@@ -0,0 +1,81 @@
1
+ # Thread::Local
2
+
3
+ Implements a standard interface for per-class/module thread local instances.
4
+
5
+ ## Per-Class Instance
6
+
7
+ By default, classes are instantiated using `self.new`:
8
+
9
+ ~~~ ruby
10
+ require 'thread/local'
11
+
12
+ class MyClass
13
+ extend Thread::Local
14
+ end
15
+
16
+ p MyClass.instance
17
+ ~~~
18
+
19
+ ### Extensions
20
+
21
+ If you need to change the behaviour of an existing thread local, you can prepend a module to wrap the call to `self.new`:
22
+
23
+ ~~~ ruby
24
+ require 'thread/local'
25
+
26
+ class MyClass
27
+ extend Thread::Local
28
+
29
+ attr_accessor :data
30
+ end
31
+
32
+ module MyExtension
33
+ def local
34
+ instance = super
35
+
36
+ # Do something with the thread local instance, e.g.:
37
+ instance.data = [1, 2, 3]
38
+
39
+ return instance
40
+ end
41
+ end
42
+
43
+ MyClass.extend(MyExtension)
44
+
45
+ p MyClass.instance
46
+ ~~~
47
+
48
+ ### Assignment
49
+
50
+ Generally, you should avoid assigning to the thread-local instance. You should prefer extensions as outlined above. However, in some situations (e.g. testing) you may prefer to directly assign to the thread local:
51
+
52
+ ~~~ruby
53
+ require 'thread/local'
54
+
55
+ class MyClass
56
+ extend Thread::Local
57
+ end
58
+
59
+ # Change the instance for the current thread:
60
+ MyClass.instance = Object.new
61
+
62
+ p MyClass.instance
63
+ ~~~
64
+
65
+ ## Per-Module Instance
66
+
67
+ By default, you cannot instantiate a module. So, you must implement your own `self.new` method:
68
+
69
+ ~~~ ruby
70
+ require 'thread/local'
71
+
72
+ module MyModule
73
+ extend Thread::Local
74
+
75
+ def self.new
76
+ Object.new
77
+ end
78
+ end
79
+
80
+ p MyModule.instance
81
+ ~~~
@@ -20,25 +20,37 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require "thread/local/version"
23
+ require_relative "local/version"
24
24
 
25
25
  class Thread
26
26
  module Local
27
27
  # Instantiate a new thread-local object.
28
+ # By default, invokes {new} to generate the instance.
29
+ # @returns [Object]
28
30
  def local
29
31
  self.new
30
32
  end
31
33
 
32
34
  # Get the current thread-local instance. Create it if required.
33
- def instance(thread = Thread.current)
35
+ # @returns [Object] The thread-local instance.
36
+ def instance
37
+ thread = Thread.current
34
38
  name = self.name
35
39
 
36
40
  unless instance = thread.thread_variable_get(name)
37
- instance = self.local
38
- thread.thread_variable_set(name, instance)
41
+ if instance = self.local
42
+ thread.thread_variable_set(name, instance)
43
+ end
39
44
  end
40
45
 
41
46
  return instance
42
47
  end
48
+
49
+ # Assigns the current thread-local instance.
50
+ # @parameter instance [Object] The object that will become the thread-local instance.
51
+ def instance= instance
52
+ thread = Thread.current
53
+ thread.thread_variable_set(self.name, instance)
54
+ end
43
55
  end
44
56
  end
@@ -20,10 +20,8 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'thread'
24
-
25
23
  class Thread
26
24
  module Local
27
- VERSION = "1.0.0"
25
+ VERSION = "1.1.0"
28
26
  end
29
27
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thread-local
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-22 00:00:00.000000000 Z
11
+ date: 2020-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: covered
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: bundler
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +25,7 @@ dependencies:
39
25
  - !ruby/object:Gem::Version
40
26
  version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
- name: rspec
28
+ name: covered
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - ">="
@@ -53,7 +39,7 @@ dependencies:
53
39
  - !ruby/object:Gem::Version
54
40
  version: '0'
55
41
  - !ruby/object:Gem::Dependency
56
- name: rake
42
+ name: rspec
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - ">="
@@ -66,27 +52,20 @@ dependencies:
66
52
  - - ">="
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
- description:
55
+ description:
70
56
  email:
71
- - samuel.williams@oriontransfer.co.nz
72
57
  executables: []
73
58
  extensions: []
74
59
  extra_rdoc_files: []
75
60
  files:
76
- - ".github/workflows/development.yml"
77
- - ".gitignore"
78
- - ".rspec"
79
- - Gemfile
80
- - README.md
81
- - Rakefile
61
+ - lib/thread/local.md
82
62
  - lib/thread/local.rb
83
63
  - lib/thread/local/version.rb
84
- - thread-local.gemspec
85
- homepage:
64
+ homepage: https://github.com/socketry/thread-local
86
65
  licenses:
87
66
  - MIT
88
67
  metadata: {}
89
- post_install_message:
68
+ post_install_message:
90
69
  rdoc_options: []
91
70
  require_paths:
92
71
  - lib
@@ -94,7 +73,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
94
73
  requirements:
95
74
  - - ">="
96
75
  - !ruby/object:Gem::Version
97
- version: 2.3.0
76
+ version: 2.5.0
98
77
  required_rubygems_version: !ruby/object:Gem::Requirement
99
78
  requirements:
100
79
  - - ">="
@@ -102,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
81
  version: '0'
103
82
  requirements: []
104
83
  rubygems_version: 3.1.2
105
- signing_key:
84
+ signing_key:
106
85
  specification_version: 4
107
86
  summary: Provides a class-level mixin to make thread local state easy.
108
87
  test_files: []
@@ -1,34 +0,0 @@
1
- name: Development
2
-
3
- on: [push, pull_request]
4
-
5
- jobs:
6
- test:
7
- strategy:
8
- matrix:
9
- os:
10
- - ubuntu
11
- - macos
12
-
13
- ruby:
14
- - 2.4
15
- - 2.5
16
- - 2.6
17
- - 2.7
18
-
19
- include:
20
- - os: 'ubuntu'
21
- ruby: '2.6'
22
- env: COVERAGE=PartialSummary,Coveralls
23
-
24
- runs-on: ${{matrix.os}}-latest
25
-
26
- steps:
27
- - uses: actions/checkout@v1
28
- - uses: ruby/setup-ruby@v1
29
- with:
30
- ruby-version: ${{matrix.ruby}}
31
- - name: Install dependencies
32
- run: bundle install
33
- - name: Run tests
34
- run: ${{matrix.env}} bundle exec rspec
data/.gitignore DELETED
@@ -1,12 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
12
- Gemfile.lock
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- # Specify your gem's dependencies in thread-local.gemspec
4
- gemspec
data/README.md DELETED
@@ -1,85 +0,0 @@
1
- # Thread::Local ![Development](https://github.com/socketry/thread-local/workflows/Development/badge.svg?branch=master)
2
-
3
- A module to simplify thread-local state.
4
-
5
- ## Motivation
6
-
7
- In my own web framework, [utopia](https://github.com/socketry/utopia), I have been struggling with the best way to expose configuration details. I was setting both global variables and modifying `ENV` which made it impossible to have multiple isolated instances of the application in the same process. This in turn makes it hard to implement things like graceful restart in multi-threaded [falcon](https://github.com/socketry/falcon). Such issues also affect application code running in other multi-threaded contexts, which are becoming increasingly common (e.g. JRuby, TruffleRuby).
8
-
9
- Global variables are often not thread-safe and encourage poor programming style. In many cases it is desirable to have thread-local state, but implementing this directly in Ruby is unpleasant at best. This gem provides a best-practice wrapper which can extend existing classes to provide per-thread instances.
10
-
11
- Conceptually, a thread is a container for application state. This works well when servers consider applications to be isolated on a per-thread basis, but this isn't always the case:
12
-
13
- | Server | Application | Thread Safety |
14
- |----------------------|------------------|--------------------------|
15
- | Falcon Multi-Process | One per process. | Isolated. |
16
- | Falcon Multi-Thread | One per thread. | Isolated, Shared State. |
17
- | Puma Multi-Thread | One per process. | Reentrant, Shared State. |
18
- | Puma Cluster | One per worker. | Reentrant, Shared State. |
19
- | Unicorn | One per process. | Isolated. |
20
-
21
- Puma requires applications to be completely thread safe and reentrant, which isn't always easy. However, this gem attempts to provide a model which works in all the above servers, providing isolated, thread-safe, mutable per-thread state.
22
-
23
- ## Installation
24
-
25
- ```
26
- bundle add thread-local
27
- ```
28
-
29
- ## Usage
30
-
31
- In your own class:
32
-
33
- ```ruby
34
- class MyThing
35
- extend Thread::Local
36
- end
37
- ```
38
-
39
- Now, instead of instantiating your class `MyThing.new`, use `MyThing.instance`. It will return a thread-local instance.
40
-
41
- ```ruby
42
- Thread.new do
43
- MyThing.instance
44
- # => #<MyObject:0x000055a14ec6be80>
45
- end
46
-
47
- Thread.new do
48
- MyThing.instance
49
- # => #<MyObject:0x000055a14ec597d0>
50
- end
51
- ```
52
-
53
- Use this as a thread-safe alternative to globals.
54
-
55
- ## Contributing
56
-
57
- 1. Fork it
58
- 2. Create your feature branch (`git checkout -b my-new-feature`)
59
- 3. Commit your changes (`git commit -am 'Add some feature'`)
60
- 4. Push to the branch (`git push origin my-new-feature`)
61
- 5. Create new Pull Request
62
-
63
- ## License
64
-
65
- Released under the MIT license.
66
-
67
- Copyright, 2020, by [Samuel G. D. Williams](https://www.codeotaku.com).
68
-
69
- Permission is hereby granted, free of charge, to any person obtaining a copy
70
- of this software and associated documentation files (the "Software"), to deal
71
- in the Software without restriction, including without limitation the rights
72
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
73
- copies of the Software, and to permit persons to whom the Software is
74
- furnished to do so, subject to the following conditions:
75
-
76
- The above copyright notice and this permission notice shall be included in
77
- all copies or substantial portions of the Software.
78
-
79
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
80
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
81
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
82
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
83
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
84
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
85
- THE SOFTWARE.
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require_relative 'lib/thread/local/version'
24
-
25
- Gem::Specification.new do |spec|
26
- spec.name = "thread-local"
27
- spec.version = Thread::Local::VERSION
28
- spec.authors = ["Samuel Williams"]
29
- spec.email = ["samuel.williams@oriontransfer.co.nz"]
30
-
31
- spec.summary = "Provides a class-level mixin to make thread local state easy."
32
- spec.license = "MIT"
33
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
34
-
35
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
36
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
37
- end
38
-
39
- spec.require_paths = ["lib"]
40
-
41
- spec.add_development_dependency "covered"
42
- spec.add_development_dependency "bundler"
43
- spec.add_development_dependency "rspec"
44
- spec.add_development_dependency "rake"
45
- end