rack-freeze 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
  SHA1:
3
- metadata.gz: 8cdf04b44d618902787c84714c6cef7dded167a5
4
- data.tar.gz: d92e028054cdd5720b964b30af568e3e25ffc63b
3
+ metadata.gz: aee544065c394af39bb0593a17193538594a7c34
4
+ data.tar.gz: d82a8b27bc3277c9e030adddb4ac32ef5ff4f210
5
5
  SHA512:
6
- metadata.gz: 9e438394bf1cb5aa17b999cc38c6f770e1e1a2f2234c7fd038e572d2da34baa074e394ddea5ffdfa1c1844c1ef835eec8d81fb5cac3487b45677d7b2e4bf3ec4
7
- data.tar.gz: 074e09463194272f78e95d0ca47ab9a97bcd7862296837c632334b472832268e809c7898a3f679b22b60e74a797eb1d3b0cd96065d010caf5bb8c4014c16ba55
6
+ metadata.gz: d6998afca2847208bb4280501c9ac17dd8130704b9a4b3403595350ab03d1946387eca7ca8e62afe82d8a041b0fb566c45181b82556cc0ec629b1ec4727f6cab
7
+ data.tar.gz: 0d4f2e3f8223bf34cc90f9bf8c28ec428fda2d28a5ce259f27bdfaa00ac33603d32733e048be1371ae396a8843a73afa08c337774a2ef6d70f286df87fb369ba
data/.rspec CHANGED
@@ -1,2 +1,4 @@
1
1
  --format documentation
2
2
  --color
3
+ --require spec_helper
4
+ --warnings
data/README.md CHANGED
@@ -20,52 +20,41 @@ Add this line to your application's Gemfile:
20
20
  gem 'rack-freeze'
21
21
  ```
22
22
 
23
- And then execute:
24
-
25
- $ bundle
26
-
27
- Or install it yourself as:
28
-
29
- $ gem install rack-freeze
30
-
31
23
  ## Usage
32
24
 
33
- For existing rack middleware, simply wrap it:
25
+ Add this to your config.ru:
34
26
 
35
27
  ```ruby
36
- use Rack::Freeze[Rack::Logger]
28
+ require 'rack/freeze'
37
29
  ```
38
30
 
39
- This will make a subclass of `Rack::Logger` if required with a working implementation of `#freeze`.
40
-
41
- In your `config.ru`, you prepare your app using the `#warmup method`;
42
-
43
- ```ruby
44
- warmup do |app|
45
- # Recursively freeze all the middleware so that mutation bugs are detected.
46
- app.freeze
47
- end
48
- ```
31
+ Now all your middleware will be frozen by default.
49
32
 
50
33
  ### What bugs does this fix?
51
34
 
52
- So, instead of writing
35
+ It guarantees, within the limits of the freeze API, that middleware won't mutate during a request.
53
36
 
54
37
  ```ruby
55
- use External::Middleware
56
- ```
57
-
58
- you write
38
+ # This modifies `Rack::Builder#use` and `Rack::Builder#to_app` to generate a frozen stack of middleware.
39
+ require 'rack/freeze'
40
+
41
+ class NonThreadSafeMiddleware
42
+ def initialize(app)
43
+ @app = app
44
+ @state = 0
45
+ end
46
+
47
+ def call(env)
48
+ @state += 1
49
+
50
+ return @app.call(env)
51
+ end
52
+ end
59
53
 
60
- ```ruby
61
- use Rack::Freeze[External::Middleware]
54
+ use NonThreadSafeMiddleware
62
55
  ```
63
56
 
64
- That ensures that `External::Middleware` will correctly freeze itself and all subsequent apps. Additionally, if `External::Middleware` mutates it's state, it will throw an exception. In a multi-threaded web-server, unprotected mutation of internal state will lead to undefined behavior.
65
-
66
- ### Thar be the Monkeys
67
-
68
- Some Rack middleware is not easy to patch in a generic way, e.g. `Rack::URLMap`. As these are identified, they will be monkey patched by this gem automatically. Going forward, I hope to bring attention to this issue and ideally integrate these changes directly into Rack.
57
+ As `NonThreadSafeMiddleware` mutates it's state `@state += 1`, it will raise a `RuntimeError`. In a multi-threaded web-server, unprotected mutation of internal state will lead to undefined behavior.
69
58
 
70
59
  ## Contributing
71
60
 
@@ -20,34 +20,5 @@
20
20
 
21
21
  require_relative 'freeze/version'
22
22
 
23
- require_relative 'freeze/sendfile'
24
- require_relative 'freeze/show_exceptions'
25
- require_relative 'freeze/urlmap'
26
-
27
- module Rack
28
- module Freeze
29
- # Check if the given klass overrides `Kernel#freeze`.
30
- def self.implements_freeze?(klass)
31
- klass.instance_method(:freeze).owner != Kernel
32
- end
33
-
34
- # Generate a subclass with a generic #freeze method to freeze all instance variables.
35
- def self.[] klass
36
- # Check if the class already has a custom implementation of #freeze.. which we assume works correctly.
37
- return klass if implements_freeze?(klass)
38
-
39
- subclass = Class.new(klass) do
40
- def freeze
41
- # This ensures that all class variables are frozen.
42
- self.instance_variables.each do |name|
43
- self.instance_variable_get(name).freeze
44
- end
45
-
46
- super
47
- end
48
- end
49
-
50
- return subclass
51
- end
52
- end
53
- end
23
+ require_relative 'freeze/freezer'
24
+ require_relative 'freeze/builder'
@@ -18,15 +18,21 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
+ require 'rack/builder'
22
+ require_relative 'freezer'
23
+
21
24
  module Rack
22
- class URLMap
23
- def freeze
24
- @map.each do |location, app|
25
- location.freeze
26
- app.freeze
25
+ module Freeze
26
+ module Builder
27
+ def use(klass, *args, &block)
28
+ super(Freeze[klass], *args, &block)
27
29
  end
28
30
 
29
- super
31
+ def to_app
32
+ super.freeze
33
+ end
30
34
  end
31
35
  end
36
+
37
+ Builder.prepend(Freeze::Builder)
32
38
  end
@@ -19,13 +19,29 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Rack
22
- class Sendfile
23
- def freeze
24
- @app.freeze
25
- @variation.freeze
26
- @mappings.freeze
22
+ module Freeze
23
+ # Check if the given klass overrides `Kernel#freeze`.
24
+ def self.implements_freeze?(klass)
25
+ klass.instance_method(:freeze).owner != Kernel
26
+ end
27
+
28
+ # Generate a subclass with a generic #freeze method to freeze all instance variables.
29
+ def self.[] klass
30
+ # Check if the class already has a custom implementation of #freeze.. which we assume works correctly.
31
+ return klass if implements_freeze?(klass)
32
+
33
+ subclass = Class.new(klass) do
34
+ def freeze
35
+ # This ensures that all class variables are frozen.
36
+ self.instance_variables.each do |name|
37
+ self.instance_variable_get(name).freeze
38
+ end
39
+
40
+ super
41
+ end
42
+ end
27
43
 
28
- super
44
+ return subclass
29
45
  end
30
46
  end
31
47
  end
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Rack
22
22
  module Freeze
23
- VERSION = "1.0.0"
23
+ VERSION = "1.1.0"
24
24
  end
25
25
  end
@@ -2,20 +2,22 @@
2
2
  require_relative 'lib/rack/freeze/version'
3
3
 
4
4
  Gem::Specification.new do |spec|
5
- spec.name = "rack-freeze"
6
- spec.version = Rack::Freeze::VERSION
7
- spec.authors = ["Samuel Williams"]
8
- spec.email = ["samuel.williams@oriontransfer.co.nz"]
5
+ spec.name = "rack-freeze"
6
+ spec.version = Rack::Freeze::VERSION
7
+ spec.authors = ["Samuel Williams"]
8
+ spec.email = ["samuel.williams@oriontransfer.co.nz"]
9
9
 
10
- spec.summary = "Provides a policy for frozen rack middleware."
11
- spec.homepage = "https://github.com/ioquatix/rack-freeze"
10
+ spec.summary = "Provides a policy for frozen rack middleware."
11
+ spec.homepage = "https://github.com/ioquatix/rack-freeze"
12
12
 
13
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
14
- f.match(%r{^(test|spec|features)/})
15
- end
16
- spec.require_paths = ["lib"]
17
-
18
- spec.add_development_dependency "bundler", "~> 1.14"
19
- spec.add_development_dependency "rake", "~> 10.0"
20
- spec.add_development_dependency "rspec", "~> 3.0"
13
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
14
+ f.match(%r{^(test|spec|features)/})
15
+ end
16
+ spec.require_paths = ["lib"]
17
+
18
+ spec.add_dependency "rack", "~> 2.0"
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.14"
21
+ spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "rspec", "~> 3.0"
21
23
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-freeze
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
@@ -10,6 +10,20 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2017-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -67,9 +81,8 @@ files:
67
81
  - README.md
68
82
  - Rakefile
69
83
  - lib/rack/freeze.rb
70
- - lib/rack/freeze/sendfile.rb
71
- - lib/rack/freeze/show_exceptions.rb
72
- - lib/rack/freeze/urlmap.rb
84
+ - lib/rack/freeze/builder.rb
85
+ - lib/rack/freeze/freezer.rb
73
86
  - lib/rack/freeze/version.rb
74
87
  - rack-freeze.gemspec
75
88
  homepage: https://github.com/ioquatix/rack-freeze
@@ -1,29 +0,0 @@
1
- # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- module Rack
22
- class ShowExceptions
23
- def freeze
24
- @app.freeze
25
-
26
- super
27
- end
28
- end
29
- end