request_store 1.6.0 → 1.7.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/.github/workflows/ci.yml +33 -33
- data/.gitignore +17 -17
- data/Gemfile +13 -13
- data/LICENSE.txt +21 -21
- data/README.md +147 -147
- data/Rakefile +12 -12
- data/lib/request_store/middleware.rb +36 -36
- data/lib/request_store/railtie.rb +21 -21
- data/lib/request_store/version.rb +3 -3
- data/lib/request_store.rb +58 -68
- data/request_store.gemspec +24 -24
- data/test/middleware_test.rb +101 -101
- data/test/request_store_test.rb +80 -80
- data/test/test_helper.rb +29 -29
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9883603b6fb82a3e39d90b6e7509911f3813160d2fe267ad892536305c5d741
|
4
|
+
data.tar.gz: 437805cfcdfc5bc8c3c59bafe9d12bf4ae3ba1685e5261ca40dfce79f7cee845
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb19a5818c773c1e27ee3b1c215d1422bdabecf7929eaf235db48364c0a0f05467203c4c3b651ce9470c6d51f412d1f7d54e0c5043d44f0c2744d22a0e28d727
|
7
|
+
data.tar.gz: b0a56bde2842cecf4b291622e332130bed3c175d649f0659024594e4d38a49309a6e1ad40171afc6ee368045e98a93e6c8aa1c56f1235ed50d38d3197298e570
|
data/.github/workflows/ci.yml
CHANGED
@@ -1,33 +1,33 @@
|
|
1
|
-
name: CI
|
2
|
-
|
3
|
-
on:
|
4
|
-
pull_request:
|
5
|
-
|
6
|
-
push:
|
7
|
-
branches: [master]
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
build:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
strategy:
|
13
|
-
matrix:
|
14
|
-
ruby:
|
15
|
-
- 3.0
|
16
|
-
- 3.1
|
17
|
-
- 3.2
|
18
|
-
- 3.3
|
19
|
-
- ruby-head
|
20
|
-
- jruby-9.1
|
21
|
-
- jruby-9.2
|
22
|
-
- jruby-9.3
|
23
|
-
- jruby-head
|
24
|
-
- truffleruby-head
|
25
|
-
|
26
|
-
steps:
|
27
|
-
- uses: actions/checkout@
|
28
|
-
- uses: ruby/setup-ruby@v1
|
29
|
-
with:
|
30
|
-
ruby-version: ${{ matrix.ruby }}
|
31
|
-
bundler-cache: true # 'bundle install' and cache
|
32
|
-
- name: Test
|
33
|
-
run: bundle exec rake
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
|
6
|
+
push:
|
7
|
+
branches: [master]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby:
|
15
|
+
- '3.0'
|
16
|
+
- 3.1
|
17
|
+
- 3.2
|
18
|
+
- 3.3
|
19
|
+
- ruby-head
|
20
|
+
- jruby-9.1
|
21
|
+
- jruby-9.2
|
22
|
+
- jruby-9.3
|
23
|
+
- jruby-head
|
24
|
+
- truffleruby-head
|
25
|
+
|
26
|
+
steps:
|
27
|
+
- uses: actions/checkout@v4
|
28
|
+
- uses: ruby/setup-ruby@v1
|
29
|
+
with:
|
30
|
+
ruby-version: ${{ matrix.ruby }}
|
31
|
+
bundler-cache: true # 'bundle install' and cache
|
32
|
+
- name: Test
|
33
|
+
run: bundle exec rake
|
data/.gitignore
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
.bundle
|
4
|
-
.config
|
5
|
-
.yardoc
|
6
|
-
Gemfile.lock
|
7
|
-
InstalledFiles
|
8
|
-
_yardoc
|
9
|
-
coverage
|
10
|
-
doc/
|
11
|
-
lib/bundler/man
|
12
|
-
pkg
|
13
|
-
rdoc
|
14
|
-
spec/reports
|
15
|
-
test/tmp
|
16
|
-
test/version_tmp
|
17
|
-
tmp
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
data/Gemfile
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in request_store.gemspec
|
4
|
-
gemspec
|
5
|
-
|
6
|
-
case Gem::Version.new(RUBY_VERSION.dup)
|
7
|
-
when ->(ruby_version) { ruby_version >= Gem::Version.new('2.2.0') }
|
8
|
-
gem 'rake', '~> 13'
|
9
|
-
when ->(ruby_version) { ruby_version >= Gem::Version.new('2.0.0') }
|
10
|
-
gem 'rake', '~> 12.3.3'
|
11
|
-
else
|
12
|
-
gem 'rake', '~> 11'
|
13
|
-
end
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in request_store.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
case Gem::Version.new(RUBY_VERSION.dup)
|
7
|
+
when ->(ruby_version) { ruby_version >= Gem::Version.new('2.2.0') }
|
8
|
+
gem 'rake', '~> 13'
|
9
|
+
when ->(ruby_version) { ruby_version >= Gem::Version.new('2.0.0') }
|
10
|
+
gem 'rake', '~> 12.3.3'
|
11
|
+
else
|
12
|
+
gem 'rake', '~> 11'
|
13
|
+
end
|
data/LICENSE.txt
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
Copyright (c) 2012 Steve Klabnik
|
2
|
-
|
3
|
-
MIT License
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
1
|
+
Copyright (c) 2012 Steve Klabnik
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,147 +1,147 @@
|
|
1
|
-
# RequestStore [](https://github.com/steveklabnik/request_store/actions/workflows/ci.yml) [](https://codeclimate.com/github/steveklabnik/request_store)
|
2
|
-
|
3
|
-
Ever needed to use a global variable in Rails? Ugh, that's the worst. If you
|
4
|
-
need global state, you've probably reached for `Thread.current`. Like this:
|
5
|
-
|
6
|
-
```ruby
|
7
|
-
def self.foo
|
8
|
-
Thread.current[:foo] ||= 0
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.foo=(value)
|
12
|
-
Thread.current[:foo] = value
|
13
|
-
end
|
14
|
-
```
|
15
|
-
|
16
|
-
Ugh! I hate it. But you gotta do what you gotta do...
|
17
|
-
|
18
|
-
### The problem
|
19
|
-
|
20
|
-
Everyone's worrying about concurrency these days. So people are using those
|
21
|
-
fancy threaded web servers, like Thin or Puma. But if you use `Thread.current`,
|
22
|
-
and you use one of those servers, watch out! Values can stick around longer
|
23
|
-
than you'd expect, and this can cause bugs. For example, if we had this in
|
24
|
-
our controller:
|
25
|
-
|
26
|
-
```ruby
|
27
|
-
def index
|
28
|
-
Thread.current[:counter] ||= 0
|
29
|
-
Thread.current[:counter] += 1
|
30
|
-
|
31
|
-
render :text => Thread.current[:counter]
|
32
|
-
end
|
33
|
-
```
|
34
|
-
|
35
|
-
If we ran this on MRI with Webrick, you'd get `1` as output, every time. But if
|
36
|
-
you run it with Thin, you get `1`, then `2`, then `3`...
|
37
|
-
|
38
|
-
### The solution
|
39
|
-
|
40
|
-
Add this line to your application's Gemfile:
|
41
|
-
|
42
|
-
```ruby
|
43
|
-
gem 'request_store'
|
44
|
-
```
|
45
|
-
|
46
|
-
And change the code to this:
|
47
|
-
|
48
|
-
```ruby
|
49
|
-
def index
|
50
|
-
RequestStore.store[:foo] ||= 0
|
51
|
-
RequestStore.store[:foo] += 1
|
52
|
-
|
53
|
-
render :text => RequestStore.store[:foo]
|
54
|
-
end
|
55
|
-
```
|
56
|
-
|
57
|
-
Yep, everywhere you used `Thread.current` just change it to
|
58
|
-
`RequestStore.store`. Now no matter what server you use, you'll get `1` every
|
59
|
-
time: the storage is local to that request.
|
60
|
-
|
61
|
-
### API
|
62
|
-
|
63
|
-
The `fetch` method returns the stored value if it already exists. If no stored value exists, it uses the provided block to add a new stored value.
|
64
|
-
|
65
|
-
```ruby
|
66
|
-
top_posts = RequestStore.fetch(:top_posts) do
|
67
|
-
# code to obtain the top posts
|
68
|
-
end
|
69
|
-
```
|
70
|
-
|
71
|
-
### Rails 2 compatibility
|
72
|
-
|
73
|
-
The gem includes a Railtie that will configure everything properly for Rails 3+
|
74
|
-
apps, but if your app is tied to an older (2.x) version, you will have to
|
75
|
-
manually add the middleware yourself. Typically this should just be a matter
|
76
|
-
of adding:
|
77
|
-
|
78
|
-
```ruby
|
79
|
-
config.middleware.use RequestStore::Middleware
|
80
|
-
```
|
81
|
-
|
82
|
-
into your config/environment.rb.
|
83
|
-
|
84
|
-
### No Rails? No Problem!
|
85
|
-
|
86
|
-
A Railtie is added that configures the Middleware for you, but if you're not
|
87
|
-
using Rails, no biggie! Just use the Middleware yourself, however you need.
|
88
|
-
You'll probably have to shove this somewhere:
|
89
|
-
|
90
|
-
```ruby
|
91
|
-
use RequestStore::Middleware
|
92
|
-
```
|
93
|
-
|
94
|
-
#### No Rails + Rack::Test
|
95
|
-
|
96
|
-
In order to have `RequestStore` storage cleared between requests, add it to the
|
97
|
-
`app`:
|
98
|
-
|
99
|
-
```ruby
|
100
|
-
# spec_helper.rb
|
101
|
-
|
102
|
-
def app
|
103
|
-
Rack::Builder.new do
|
104
|
-
use RequestStore::Middleware
|
105
|
-
run MyApp
|
106
|
-
end
|
107
|
-
end
|
108
|
-
```
|
109
|
-
|
110
|
-
## Using with Sidekiq
|
111
|
-
|
112
|
-
This gem uses a Rack middleware to clear the store object after every request,
|
113
|
-
but that doesn't translate well to background processing with
|
114
|
-
[Sidekiq](https://github.com/mperham/sidekiq).
|
115
|
-
|
116
|
-
A companion library,
|
117
|
-
[request_store-sidekiq](https://rubygems.org/gems/request_store-sidekiq)
|
118
|
-
creates a Sidekiq middleware that will ensure the store is cleared after each
|
119
|
-
job is processed, for security and consistency with how this is done in Rack.
|
120
|
-
|
121
|
-
## Semantic Versioning
|
122
|
-
|
123
|
-
This project conforms to [semver](http://semver.org/). As a result of this
|
124
|
-
policy, you can (and should) specify a dependency on this gem using the
|
125
|
-
[Pessimistic Version Constraint](http://guides.rubygems.org/patterns/) with
|
126
|
-
two digits of precision. For example:
|
127
|
-
|
128
|
-
```ruby
|
129
|
-
spec.add_dependency 'request_store', '~> 1.0'
|
130
|
-
```
|
131
|
-
|
132
|
-
This means your project is compatible with request_store 1.0 up until 2.0.
|
133
|
-
You can also set a higher minimum version:
|
134
|
-
|
135
|
-
```ruby
|
136
|
-
spec.add_dependency 'request_store', '~> 1.1'
|
137
|
-
```
|
138
|
-
|
139
|
-
## Contributing
|
140
|
-
|
141
|
-
1. Fork it
|
142
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
143
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
144
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
145
|
-
5. Create new Pull Request
|
146
|
-
|
147
|
-
Don't forget to run the tests with `rake`.
|
1
|
+
# RequestStore [](https://github.com/steveklabnik/request_store/actions/workflows/ci.yml) [](https://codeclimate.com/github/steveklabnik/request_store)
|
2
|
+
|
3
|
+
Ever needed to use a global variable in Rails? Ugh, that's the worst. If you
|
4
|
+
need global state, you've probably reached for `Thread.current`. Like this:
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
def self.foo
|
8
|
+
Thread.current[:foo] ||= 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.foo=(value)
|
12
|
+
Thread.current[:foo] = value
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
Ugh! I hate it. But you gotta do what you gotta do...
|
17
|
+
|
18
|
+
### The problem
|
19
|
+
|
20
|
+
Everyone's worrying about concurrency these days. So people are using those
|
21
|
+
fancy threaded web servers, like Thin or Puma. But if you use `Thread.current`,
|
22
|
+
and you use one of those servers, watch out! Values can stick around longer
|
23
|
+
than you'd expect, and this can cause bugs. For example, if we had this in
|
24
|
+
our controller:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
def index
|
28
|
+
Thread.current[:counter] ||= 0
|
29
|
+
Thread.current[:counter] += 1
|
30
|
+
|
31
|
+
render :text => Thread.current[:counter]
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
If we ran this on MRI with Webrick, you'd get `1` as output, every time. But if
|
36
|
+
you run it with Thin, you get `1`, then `2`, then `3`...
|
37
|
+
|
38
|
+
### The solution
|
39
|
+
|
40
|
+
Add this line to your application's Gemfile:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
gem 'request_store'
|
44
|
+
```
|
45
|
+
|
46
|
+
And change the code to this:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
def index
|
50
|
+
RequestStore.store[:foo] ||= 0
|
51
|
+
RequestStore.store[:foo] += 1
|
52
|
+
|
53
|
+
render :text => RequestStore.store[:foo]
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
Yep, everywhere you used `Thread.current` just change it to
|
58
|
+
`RequestStore.store`. Now no matter what server you use, you'll get `1` every
|
59
|
+
time: the storage is local to that request.
|
60
|
+
|
61
|
+
### API
|
62
|
+
|
63
|
+
The `fetch` method returns the stored value if it already exists. If no stored value exists, it uses the provided block to add a new stored value.
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
top_posts = RequestStore.fetch(:top_posts) do
|
67
|
+
# code to obtain the top posts
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
### Rails 2 compatibility
|
72
|
+
|
73
|
+
The gem includes a Railtie that will configure everything properly for Rails 3+
|
74
|
+
apps, but if your app is tied to an older (2.x) version, you will have to
|
75
|
+
manually add the middleware yourself. Typically this should just be a matter
|
76
|
+
of adding:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
config.middleware.use RequestStore::Middleware
|
80
|
+
```
|
81
|
+
|
82
|
+
into your config/environment.rb.
|
83
|
+
|
84
|
+
### No Rails? No Problem!
|
85
|
+
|
86
|
+
A Railtie is added that configures the Middleware for you, but if you're not
|
87
|
+
using Rails, no biggie! Just use the Middleware yourself, however you need.
|
88
|
+
You'll probably have to shove this somewhere:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
use RequestStore::Middleware
|
92
|
+
```
|
93
|
+
|
94
|
+
#### No Rails + Rack::Test
|
95
|
+
|
96
|
+
In order to have `RequestStore` storage cleared between requests, add it to the
|
97
|
+
`app`:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
# spec_helper.rb
|
101
|
+
|
102
|
+
def app
|
103
|
+
Rack::Builder.new do
|
104
|
+
use RequestStore::Middleware
|
105
|
+
run MyApp
|
106
|
+
end
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
## Using with Sidekiq
|
111
|
+
|
112
|
+
This gem uses a Rack middleware to clear the store object after every request,
|
113
|
+
but that doesn't translate well to background processing with
|
114
|
+
[Sidekiq](https://github.com/mperham/sidekiq).
|
115
|
+
|
116
|
+
A companion library,
|
117
|
+
[request_store-sidekiq](https://rubygems.org/gems/request_store-sidekiq)
|
118
|
+
creates a Sidekiq middleware that will ensure the store is cleared after each
|
119
|
+
job is processed, for security and consistency with how this is done in Rack.
|
120
|
+
|
121
|
+
## Semantic Versioning
|
122
|
+
|
123
|
+
This project conforms to [semver](http://semver.org/). As a result of this
|
124
|
+
policy, you can (and should) specify a dependency on this gem using the
|
125
|
+
[Pessimistic Version Constraint](http://guides.rubygems.org/patterns/) with
|
126
|
+
two digits of precision. For example:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
spec.add_dependency 'request_store', '~> 1.0'
|
130
|
+
```
|
131
|
+
|
132
|
+
This means your project is compatible with request_store 1.0 up until 2.0.
|
133
|
+
You can also set a higher minimum version:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
spec.add_dependency 'request_store', '~> 1.1'
|
137
|
+
```
|
138
|
+
|
139
|
+
## Contributing
|
140
|
+
|
141
|
+
1. Fork it
|
142
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
143
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
144
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
145
|
+
5. Create new Pull Request
|
146
|
+
|
147
|
+
Don't forget to run the tests with `rake`.
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
|
3
|
-
require 'rake/testtask'
|
4
|
-
|
5
|
-
Rake::TestTask.new do |t|
|
6
|
-
t.libs << "lib"
|
7
|
-
t.test_files = FileList['test/*_test.rb']
|
8
|
-
t.ruby_opts = ['-r./test/test_helper.rb']
|
9
|
-
t.verbose = true
|
10
|
-
end
|
11
|
-
|
12
|
-
task :default => :test
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
Rake::TestTask.new do |t|
|
6
|
+
t.libs << "lib"
|
7
|
+
t.test_files = FileList['test/*_test.rb']
|
8
|
+
t.ruby_opts = ['-r./test/test_helper.rb']
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task :default => :test
|
@@ -1,36 +1,36 @@
|
|
1
|
-
require 'rack/body_proxy'
|
2
|
-
|
3
|
-
# A middleware that ensures the RequestStore stays around until
|
4
|
-
# the last part of the body is rendered. This is useful when
|
5
|
-
# using streaming.
|
6
|
-
#
|
7
|
-
# Uses Rack::BodyProxy, adapted from Rack::Lock's usage of the
|
8
|
-
# same pattern.
|
9
|
-
|
10
|
-
module RequestStore
|
11
|
-
class Middleware
|
12
|
-
def initialize(app)
|
13
|
-
@app = app
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(env)
|
17
|
-
RequestStore.begin!
|
18
|
-
|
19
|
-
status, headers, body = @app.call(env)
|
20
|
-
|
21
|
-
body = Rack::BodyProxy.new(body) do
|
22
|
-
RequestStore.end!
|
23
|
-
RequestStore.clear!
|
24
|
-
end
|
25
|
-
|
26
|
-
returned = true
|
27
|
-
|
28
|
-
[status, headers, body]
|
29
|
-
ensure
|
30
|
-
unless returned
|
31
|
-
RequestStore.end!
|
32
|
-
RequestStore.clear!
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
1
|
+
require 'rack/body_proxy'
|
2
|
+
|
3
|
+
# A middleware that ensures the RequestStore stays around until
|
4
|
+
# the last part of the body is rendered. This is useful when
|
5
|
+
# using streaming.
|
6
|
+
#
|
7
|
+
# Uses Rack::BodyProxy, adapted from Rack::Lock's usage of the
|
8
|
+
# same pattern.
|
9
|
+
|
10
|
+
module RequestStore
|
11
|
+
class Middleware
|
12
|
+
def initialize(app)
|
13
|
+
@app = app
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
RequestStore.begin!
|
18
|
+
|
19
|
+
status, headers, body = @app.call(env)
|
20
|
+
|
21
|
+
body = Rack::BodyProxy.new(body) do
|
22
|
+
RequestStore.end!
|
23
|
+
RequestStore.clear!
|
24
|
+
end
|
25
|
+
|
26
|
+
returned = true
|
27
|
+
|
28
|
+
[status, headers, body]
|
29
|
+
ensure
|
30
|
+
unless returned
|
31
|
+
RequestStore.end!
|
32
|
+
RequestStore.clear!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,21 +1,21 @@
|
|
1
|
-
module RequestStore
|
2
|
-
class Railtie < ::Rails::Railtie
|
3
|
-
initializer "request_store.insert_middleware" do |app|
|
4
|
-
if ActionDispatch.const_defined? :RequestId
|
5
|
-
app.config.middleware.insert_after ActionDispatch::RequestId, RequestStore::Middleware
|
6
|
-
else
|
7
|
-
app.config.middleware.insert_after Rack::MethodOverride, RequestStore::Middleware
|
8
|
-
end
|
9
|
-
|
10
|
-
if ActiveSupport.const_defined?(:Reloader) && ActiveSupport::Reloader.respond_to?(:to_complete)
|
11
|
-
ActiveSupport::Reloader.to_complete do
|
12
|
-
RequestStore.clear!
|
13
|
-
end
|
14
|
-
elsif ActionDispatch.const_defined?(:Reloader) && ActionDispatch::Reloader.respond_to?(:to_cleanup)
|
15
|
-
ActionDispatch::Reloader.to_cleanup do
|
16
|
-
RequestStore.clear!
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
1
|
+
module RequestStore
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
initializer "request_store.insert_middleware" do |app|
|
4
|
+
if ActionDispatch.const_defined? :RequestId
|
5
|
+
app.config.middleware.insert_after ActionDispatch::RequestId, RequestStore::Middleware
|
6
|
+
else
|
7
|
+
app.config.middleware.insert_after Rack::MethodOverride, RequestStore::Middleware
|
8
|
+
end
|
9
|
+
|
10
|
+
if ActiveSupport.const_defined?(:Reloader) && ActiveSupport::Reloader.respond_to?(:to_complete)
|
11
|
+
ActiveSupport::Reloader.to_complete do
|
12
|
+
RequestStore.clear!
|
13
|
+
end
|
14
|
+
elsif ActionDispatch.const_defined?(:Reloader) && ActionDispatch::Reloader.respond_to?(:to_cleanup)
|
15
|
+
ActionDispatch::Reloader.to_cleanup do
|
16
|
+
RequestStore.clear!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
module RequestStore
|
2
|
-
VERSION = "1.
|
3
|
-
end
|
1
|
+
module RequestStore
|
2
|
+
VERSION = "1.7.0"
|
3
|
+
end
|
data/lib/request_store.rb
CHANGED
@@ -1,68 +1,58 @@
|
|
1
|
-
require "request_store/version"
|
2
|
-
require "request_store/middleware"
|
3
|
-
require "request_store/railtie" if defined?(Rails::Railtie)
|
4
|
-
|
5
|
-
module RequestStore
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
def self.fetch(key)
|
61
|
-
store[key] = yield unless exist?(key)
|
62
|
-
store[key]
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.delete(key, &block)
|
66
|
-
store.delete(key, &block)
|
67
|
-
end
|
68
|
-
end
|
1
|
+
require "request_store/version"
|
2
|
+
require "request_store/middleware"
|
3
|
+
require "request_store/railtie" if defined?(Rails::Railtie)
|
4
|
+
|
5
|
+
module RequestStore
|
6
|
+
def self.store
|
7
|
+
Thread.current[:request_store] ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.store=(store)
|
11
|
+
Thread.current[:request_store] = store
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.clear!
|
15
|
+
Thread.current[:request_store] = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.begin!
|
19
|
+
Thread.current[:request_store_active] = true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.end!
|
23
|
+
Thread.current[:request_store_active] = false
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.active?
|
27
|
+
Thread.current[:request_store_active] || false
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.read(key)
|
31
|
+
store[key]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.[](key)
|
35
|
+
store[key]
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.write(key, value)
|
39
|
+
store[key] = value
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.[]=(key, value)
|
43
|
+
store[key] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.exist?(key)
|
47
|
+
store.key?(key)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.fetch(key)
|
51
|
+
store[key] = yield unless exist?(key)
|
52
|
+
store[key]
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.delete(key, &block)
|
56
|
+
store.delete(key, &block)
|
57
|
+
end
|
58
|
+
end
|
data/request_store.gemspec
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'request_store/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |gem|
|
7
|
-
gem.name = "request_store"
|
8
|
-
gem.version = RequestStore::VERSION
|
9
|
-
gem.authors = ["Steve Klabnik"]
|
10
|
-
gem.email = ["steve@steveklabnik.com"]
|
11
|
-
gem.description = %q{RequestStore gives you per-request global storage.}
|
12
|
-
gem.summary = %q{RequestStore gives you per-request global storage.}
|
13
|
-
gem.homepage = "https://github.com/steveklabnik/request_store"
|
14
|
-
gem.licenses = ["MIT"]
|
15
|
-
|
16
|
-
gem.files = `git ls-files`.split($/)
|
17
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
-
gem.require_paths = ["lib"]
|
19
|
-
|
20
|
-
gem.add_dependency "rack", ">= 1.4"
|
21
|
-
|
22
|
-
gem.add_development_dependency "rake"
|
23
|
-
gem.add_development_dependency "minitest", "~> 5.0"
|
24
|
-
end
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'request_store/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "request_store"
|
8
|
+
gem.version = RequestStore::VERSION
|
9
|
+
gem.authors = ["Steve Klabnik"]
|
10
|
+
gem.email = ["steve@steveklabnik.com"]
|
11
|
+
gem.description = %q{RequestStore gives you per-request global storage.}
|
12
|
+
gem.summary = %q{RequestStore gives you per-request global storage.}
|
13
|
+
gem.homepage = "https://github.com/steveklabnik/request_store"
|
14
|
+
gem.licenses = ["MIT"]
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "rack", ">= 1.4"
|
21
|
+
|
22
|
+
gem.add_development_dependency "rake"
|
23
|
+
gem.add_development_dependency "minitest", "~> 5.0"
|
24
|
+
end
|
data/test/middleware_test.rb
CHANGED
@@ -1,101 +1,101 @@
|
|
1
|
-
require 'minitest/test'
|
2
|
-
require 'minitest/autorun'
|
3
|
-
|
4
|
-
require 'request_store'
|
5
|
-
|
6
|
-
class MiddlewareTest < Minitest::Test
|
7
|
-
def setup
|
8
|
-
@app = RackApp.new
|
9
|
-
@middleware = RequestStore::Middleware.new(@app)
|
10
|
-
end
|
11
|
-
|
12
|
-
def call_middleware(opts = {})
|
13
|
-
_, _, proxy = @middleware.call(opts)
|
14
|
-
proxy.close
|
15
|
-
proxy
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_middleware_resets_store
|
19
|
-
2.times do
|
20
|
-
call_middleware
|
21
|
-
end
|
22
|
-
|
23
|
-
assert_equal 1, @app.last_value
|
24
|
-
assert_equal({}, RequestStore.store)
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_middleware_does_not_mutate_response_and_does_not_overflow_stack
|
28
|
-
10000.times do
|
29
|
-
call_middleware
|
30
|
-
end
|
31
|
-
|
32
|
-
resp = call_middleware
|
33
|
-
assert resp.is_a?(::Rack::BodyProxy)
|
34
|
-
assert_equal ["response"], resp.to_a
|
35
|
-
assert_equal ["response"], resp.instance_variable_get(:@body)
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_middleware_resets_store_on_error
|
39
|
-
e = assert_raises RuntimeError do
|
40
|
-
call_middleware({:error => true})
|
41
|
-
end
|
42
|
-
|
43
|
-
assert_equal 'FAIL', e.message
|
44
|
-
assert_equal({}, RequestStore.store)
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_middleware_begins_store
|
48
|
-
call_middleware
|
49
|
-
assert_equal true, @app.store_active
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_middleware_ends_store
|
53
|
-
call_middleware
|
54
|
-
|
55
|
-
assert_equal false, RequestStore.active?
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_middleware_ends_store_on_error
|
59
|
-
assert_raises RuntimeError do
|
60
|
-
call_middleware({:error => true})
|
61
|
-
end
|
62
|
-
|
63
|
-
assert_equal false, RequestStore.active?
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_middleware_stores_until_proxy_closes
|
67
|
-
_, _, proxy = @middleware.call({})
|
68
|
-
|
69
|
-
assert_equal 1, @app.last_value
|
70
|
-
assert RequestStore.active?
|
71
|
-
|
72
|
-
proxy.close
|
73
|
-
|
74
|
-
refute RequestStore.active?
|
75
|
-
refute RequestStore.store[:foo]
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
class MiddlewareWithConstResponseTest < Minitest::Test
|
80
|
-
def setup
|
81
|
-
@app = RackAppWithConstResponse.new
|
82
|
-
@middleware = RequestStore::Middleware.new(@app)
|
83
|
-
end
|
84
|
-
|
85
|
-
def call_middleware(opts = {})
|
86
|
-
_, _, proxy = @middleware.call(opts)
|
87
|
-
proxy.close
|
88
|
-
proxy
|
89
|
-
end
|
90
|
-
|
91
|
-
def test_middleware_does_not_mutate_response_and_does_not_overflow_stack
|
92
|
-
10000.times do
|
93
|
-
call_middleware
|
94
|
-
end
|
95
|
-
|
96
|
-
resp = call_middleware
|
97
|
-
assert resp.is_a?(::Rack::BodyProxy)
|
98
|
-
assert_equal ["response"], resp.to_a
|
99
|
-
assert_equal ["response"], resp.instance_variable_get(:@body)
|
100
|
-
end
|
101
|
-
end
|
1
|
+
require 'minitest/test'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
require 'request_store'
|
5
|
+
|
6
|
+
class MiddlewareTest < Minitest::Test
|
7
|
+
def setup
|
8
|
+
@app = RackApp.new
|
9
|
+
@middleware = RequestStore::Middleware.new(@app)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call_middleware(opts = {})
|
13
|
+
_, _, proxy = @middleware.call(opts)
|
14
|
+
proxy.close
|
15
|
+
proxy
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_middleware_resets_store
|
19
|
+
2.times do
|
20
|
+
call_middleware
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_equal 1, @app.last_value
|
24
|
+
assert_equal({}, RequestStore.store)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_middleware_does_not_mutate_response_and_does_not_overflow_stack
|
28
|
+
10000.times do
|
29
|
+
call_middleware
|
30
|
+
end
|
31
|
+
|
32
|
+
resp = call_middleware
|
33
|
+
assert resp.is_a?(::Rack::BodyProxy)
|
34
|
+
assert_equal ["response"], resp.to_a
|
35
|
+
assert_equal ["response"], resp.instance_variable_get(:@body)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_middleware_resets_store_on_error
|
39
|
+
e = assert_raises RuntimeError do
|
40
|
+
call_middleware({:error => true})
|
41
|
+
end
|
42
|
+
|
43
|
+
assert_equal 'FAIL', e.message
|
44
|
+
assert_equal({}, RequestStore.store)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_middleware_begins_store
|
48
|
+
call_middleware
|
49
|
+
assert_equal true, @app.store_active
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_middleware_ends_store
|
53
|
+
call_middleware
|
54
|
+
|
55
|
+
assert_equal false, RequestStore.active?
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_middleware_ends_store_on_error
|
59
|
+
assert_raises RuntimeError do
|
60
|
+
call_middleware({:error => true})
|
61
|
+
end
|
62
|
+
|
63
|
+
assert_equal false, RequestStore.active?
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_middleware_stores_until_proxy_closes
|
67
|
+
_, _, proxy = @middleware.call({})
|
68
|
+
|
69
|
+
assert_equal 1, @app.last_value
|
70
|
+
assert RequestStore.active?
|
71
|
+
|
72
|
+
proxy.close
|
73
|
+
|
74
|
+
refute RequestStore.active?
|
75
|
+
refute RequestStore.store[:foo]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class MiddlewareWithConstResponseTest < Minitest::Test
|
80
|
+
def setup
|
81
|
+
@app = RackAppWithConstResponse.new
|
82
|
+
@middleware = RequestStore::Middleware.new(@app)
|
83
|
+
end
|
84
|
+
|
85
|
+
def call_middleware(opts = {})
|
86
|
+
_, _, proxy = @middleware.call(opts)
|
87
|
+
proxy.close
|
88
|
+
proxy
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_middleware_does_not_mutate_response_and_does_not_overflow_stack
|
92
|
+
10000.times do
|
93
|
+
call_middleware
|
94
|
+
end
|
95
|
+
|
96
|
+
resp = call_middleware
|
97
|
+
assert resp.is_a?(::Rack::BodyProxy)
|
98
|
+
assert_equal ["response"], resp.to_a
|
99
|
+
assert_equal ["response"], resp.instance_variable_get(:@body)
|
100
|
+
end
|
101
|
+
end
|
data/test/request_store_test.rb
CHANGED
@@ -1,80 +1,80 @@
|
|
1
|
-
require 'minitest/autorun'
|
2
|
-
|
3
|
-
require 'request_store'
|
4
|
-
|
5
|
-
class RequestStoreTest < Minitest::Test
|
6
|
-
def setup
|
7
|
-
RequestStore.clear!
|
8
|
-
end
|
9
|
-
|
10
|
-
def teardown
|
11
|
-
RequestStore.clear!
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_initial_state
|
15
|
-
Thread.current[:request_store] = nil
|
16
|
-
assert_equal RequestStore.store, Hash.new
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_init_with_hash
|
20
|
-
assert_equal Hash.new, RequestStore.store
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_assign_store
|
24
|
-
store_obj = { test_key: 'test' }
|
25
|
-
RequestStore.store = store_obj
|
26
|
-
assert_equal 'test', RequestStore.store[:test_key]
|
27
|
-
assert_equal store_obj, RequestStore.store
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_clear
|
31
|
-
RequestStore.store[:foo] = 1
|
32
|
-
RequestStore.clear!
|
33
|
-
assert_equal Hash.new, RequestStore.store
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_quacks_like_hash
|
37
|
-
RequestStore.store[:foo] = 1
|
38
|
-
assert_equal 1, RequestStore.store[:foo]
|
39
|
-
assert_equal 1, RequestStore.store.fetch(:foo)
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_read
|
43
|
-
RequestStore.store[:foo] = 1
|
44
|
-
assert_equal 1, RequestStore.read(:foo)
|
45
|
-
assert_equal 1, RequestStore[:foo]
|
46
|
-
end
|
47
|
-
|
48
|
-
def test_write
|
49
|
-
RequestStore.write(:foo, 1)
|
50
|
-
assert_equal 1, RequestStore.store[:foo]
|
51
|
-
RequestStore[:foo] = 2
|
52
|
-
assert_equal 2, RequestStore.store[:foo]
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_fetch
|
56
|
-
assert_equal 2, RequestStore.fetch(:foo) { 1 + 1 }
|
57
|
-
assert_equal 2, RequestStore.fetch(:foo) { 2 + 2 }
|
58
|
-
end
|
59
|
-
|
60
|
-
def test_delete
|
61
|
-
assert_equal 2, RequestStore.fetch(:foo) { 1 + 1 }
|
62
|
-
assert_equal 2, RequestStore.delete(:foo) { 2 + 2 }
|
63
|
-
assert_equal 4, RequestStore.delete(:foo) { 2 + 2 }
|
64
|
-
end
|
65
|
-
|
66
|
-
def
|
67
|
-
RequestStore.store[:foo] = 1
|
68
|
-
assert_equal 1,
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_active_state
|
72
|
-
assert_equal false, RequestStore.active?
|
73
|
-
|
74
|
-
RequestStore.begin!
|
75
|
-
assert_equal true, RequestStore.active?
|
76
|
-
|
77
|
-
RequestStore.end!
|
78
|
-
assert_equal false, RequestStore.active?
|
79
|
-
end
|
80
|
-
end
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
require 'request_store'
|
4
|
+
|
5
|
+
class RequestStoreTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
RequestStore.clear!
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
RequestStore.clear!
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_initial_state
|
15
|
+
Thread.current[:request_store] = nil
|
16
|
+
assert_equal RequestStore.store, Hash.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_init_with_hash
|
20
|
+
assert_equal Hash.new, RequestStore.store
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_assign_store
|
24
|
+
store_obj = { test_key: 'test' }
|
25
|
+
RequestStore.store = store_obj
|
26
|
+
assert_equal 'test', RequestStore.store[:test_key]
|
27
|
+
assert_equal store_obj, RequestStore.store
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_clear
|
31
|
+
RequestStore.store[:foo] = 1
|
32
|
+
RequestStore.clear!
|
33
|
+
assert_equal Hash.new, RequestStore.store
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_quacks_like_hash
|
37
|
+
RequestStore.store[:foo] = 1
|
38
|
+
assert_equal 1, RequestStore.store[:foo]
|
39
|
+
assert_equal 1, RequestStore.store.fetch(:foo)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_read
|
43
|
+
RequestStore.store[:foo] = 1
|
44
|
+
assert_equal 1, RequestStore.read(:foo)
|
45
|
+
assert_equal 1, RequestStore[:foo]
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_write
|
49
|
+
RequestStore.write(:foo, 1)
|
50
|
+
assert_equal 1, RequestStore.store[:foo]
|
51
|
+
RequestStore[:foo] = 2
|
52
|
+
assert_equal 2, RequestStore.store[:foo]
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_fetch
|
56
|
+
assert_equal 2, RequestStore.fetch(:foo) { 1 + 1 }
|
57
|
+
assert_equal 2, RequestStore.fetch(:foo) { 2 + 2 }
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_delete
|
61
|
+
assert_equal 2, RequestStore.fetch(:foo) { 1 + 1 }
|
62
|
+
assert_equal 2, RequestStore.delete(:foo) { 2 + 2 }
|
63
|
+
assert_equal 4, RequestStore.delete(:foo) { 2 + 2 }
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_delegates_to_thread
|
67
|
+
RequestStore.store[:foo] = 1
|
68
|
+
assert_equal 1, Thread.current[:request_store][:foo]
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_active_state
|
72
|
+
assert_equal false, RequestStore.active?
|
73
|
+
|
74
|
+
RequestStore.begin!
|
75
|
+
assert_equal true, RequestStore.active?
|
76
|
+
|
77
|
+
RequestStore.end!
|
78
|
+
assert_equal false, RequestStore.active?
|
79
|
+
end
|
80
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
|
-
class RackApp
|
2
|
-
attr_reader :last_value, :store_active
|
3
|
-
|
4
|
-
def call(env)
|
5
|
-
RequestStore.store[:foo] ||= 0
|
6
|
-
RequestStore.store[:foo] += 1
|
7
|
-
@last_value = RequestStore.store[:foo]
|
8
|
-
@store_active = RequestStore.active?
|
9
|
-
raise 'FAIL' if env[:error]
|
10
|
-
|
11
|
-
[200, {}, ["response"]]
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class RackAppWithConstResponse
|
16
|
-
RESPONSE = [200, {}, ["response"]]
|
17
|
-
|
18
|
-
attr_reader :last_value, :store_active
|
19
|
-
|
20
|
-
def call(env)
|
21
|
-
RequestStore.store[:foo] ||= 0
|
22
|
-
RequestStore.store[:foo] += 1
|
23
|
-
@last_value = RequestStore.store[:foo]
|
24
|
-
@store_active = RequestStore.active?
|
25
|
-
raise 'FAIL' if env[:error]
|
26
|
-
|
27
|
-
RESPONSE
|
28
|
-
end
|
29
|
-
end
|
1
|
+
class RackApp
|
2
|
+
attr_reader :last_value, :store_active
|
3
|
+
|
4
|
+
def call(env)
|
5
|
+
RequestStore.store[:foo] ||= 0
|
6
|
+
RequestStore.store[:foo] += 1
|
7
|
+
@last_value = RequestStore.store[:foo]
|
8
|
+
@store_active = RequestStore.active?
|
9
|
+
raise 'FAIL' if env[:error]
|
10
|
+
|
11
|
+
[200, {}, ["response"]]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class RackAppWithConstResponse
|
16
|
+
RESPONSE = [200, {}, ["response"]]
|
17
|
+
|
18
|
+
attr_reader :last_value, :store_active
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
RequestStore.store[:foo] ||= 0
|
22
|
+
RequestStore.store[:foo] += 1
|
23
|
+
@last_value = RequestStore.store[:foo]
|
24
|
+
@store_active = RequestStore.active?
|
25
|
+
raise 'FAIL' if env[:error]
|
26
|
+
|
27
|
+
RESPONSE
|
28
|
+
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: request_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Klabnik
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -77,7 +77,7 @@ homepage: https://github.com/steveklabnik/request_store
|
|
77
77
|
licenses:
|
78
78
|
- MIT
|
79
79
|
metadata: {}
|
80
|
-
post_install_message:
|
80
|
+
post_install_message:
|
81
81
|
rdoc_options: []
|
82
82
|
require_paths:
|
83
83
|
- lib
|
@@ -92,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
94
|
requirements: []
|
95
|
-
rubygems_version: 3.
|
96
|
-
signing_key:
|
95
|
+
rubygems_version: 3.3.5
|
96
|
+
signing_key:
|
97
97
|
specification_version: 4
|
98
98
|
summary: RequestStore gives you per-request global storage.
|
99
99
|
test_files:
|