rackables 0.2.0 → 0.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 +7 -0
- data/lib/rackables.rb +2 -1
- data/lib/rackables/branch.rb +18 -2
- data/lib/rackables/cache_control.rb +16 -17
- data/lib/rackables/default_charset.rb +6 -4
- data/lib/rackables/response_headers.rb +25 -0
- data/lib/rackables/simple_endpoint.rb +78 -0
- data/lib/rackables/trailing_slash_redirect.rb +6 -4
- metadata +60 -57
- data/README.rdoc +0 -50
- data/Rakefile +0 -22
- data/VERSION +0 -1
- data/lib/rackables/get.rb +0 -45
- data/test/fixtures/custom_500.html +0 -1
- data/test/test_branch.rb +0 -26
- data/test/test_cache_control.rb +0 -57
- data/test/test_default_charset.rb +0 -27
- data/test/test_get.rb +0 -80
- data/test/test_hide_exceptions.rb +0 -30
- data/test/test_trailing_slash_redirect.rb +0 -39
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d191aa7afff2efbffbd223c9dfb3f6af2478bb1c
|
4
|
+
data.tar.gz: 0f1a3b94ea1abe80b4c3f009e018b123b1a73dd9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 31be665cf4d47cc8d2ae746f52314725cfc50c93562bb690fc1ea972c534135cf09d465c525abdab1f4c6e41451b5e72928dc1ebc21ad1301db6559cecb19548
|
7
|
+
data.tar.gz: 5f032269df7a43c136c6ebedde5ccf1b2c6310115133c17942631df1ae9bad68f93ecc61551221170a1e09f1d9c1680ca75a72f04cfa1c18a6e6bff04f217918
|
data/lib/rackables.rb
CHANGED
@@ -2,7 +2,8 @@ module Rackables
|
|
2
2
|
autoload :Branch, 'rackables/branch'
|
3
3
|
autoload :CacheControl, 'rackables/cache_control'
|
4
4
|
autoload :DefaultCharset, 'rackables/default_charset'
|
5
|
-
autoload :Get, 'rackables/get'
|
6
5
|
autoload :HideExceptions, 'rackables/hide_exceptions'
|
6
|
+
autoload :ResponseHeaders, 'rackables/response_headers'
|
7
|
+
autoload :SimpleEndpoint, 'rackables/simple_endpoint'
|
7
8
|
autoload :TrailingSlashRedirect, 'rackables/trailing_slash_redirect'
|
8
9
|
end
|
data/lib/rackables/branch.rb
CHANGED
@@ -25,6 +25,17 @@ module Rackables
|
|
25
25
|
# end
|
26
26
|
#
|
27
27
|
# run MyEndpointApp
|
28
|
+
#
|
29
|
+
# If the app returned from the block responds with an X-Cascade: pass header,
|
30
|
+
# control will be passed back to the main rack pipeline.
|
31
|
+
#
|
32
|
+
# In this contrived example, MyEndpointApp will always be called:
|
33
|
+
#
|
34
|
+
# use Rackables::Branch do |env|
|
35
|
+
# Proc.new { [404, 'X-Cascade' => 'pass', []] }
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# run MyEndpointApp
|
28
39
|
class Branch
|
29
40
|
def initialize(app, &block)
|
30
41
|
@app = app
|
@@ -32,8 +43,13 @@ module Rackables
|
|
32
43
|
end
|
33
44
|
|
34
45
|
def call(env)
|
35
|
-
|
36
|
-
|
46
|
+
if branch_app = @block.call(env)
|
47
|
+
response = branch_app.call(env)
|
48
|
+
cascade = response[1]['X-Cascade']
|
49
|
+
cascade == 'pass' ? @app.call(env) : response
|
50
|
+
else
|
51
|
+
@app.call(env)
|
52
|
+
end
|
37
53
|
end
|
38
54
|
end
|
39
55
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
1
3
|
module Rackables
|
2
4
|
class CacheControl
|
3
5
|
# Lets you set the Cache-Control response header from middleware. Does not overwrite
|
@@ -24,42 +26,39 @@ module Rackables
|
|
24
26
|
end
|
25
27
|
|
26
28
|
def call(env)
|
27
|
-
|
28
|
-
headers =
|
29
|
+
status, headers, body = @app.call(env)
|
30
|
+
headers = ::Rack::Utils::HeaderHash.new(headers)
|
29
31
|
unless headers.has_key?('Cache-Control')
|
30
|
-
|
31
|
-
headers['Cache-Control'] = value
|
32
|
+
headers['Cache-Control'] = directives
|
32
33
|
end
|
33
|
-
|
34
|
+
[status, headers, body]
|
34
35
|
end
|
35
|
-
|
36
|
+
|
36
37
|
private
|
37
38
|
def extract_hash!(array)
|
38
39
|
array.last.kind_of?(Hash) ? array.pop : {}
|
39
40
|
end
|
40
|
-
|
41
|
+
|
41
42
|
def extract_non_callable_values_from_hash!
|
42
43
|
@hash.reject! { |k,v| v == false }
|
43
44
|
@hash.reject! { |k,v| @directives << k if v == true }
|
44
45
|
@hash.reject! { |k,v| @directives << "#{k}=#{v.inspect}" if !v.respond_to?(:call) }
|
45
46
|
end
|
46
|
-
|
47
|
+
|
47
48
|
def stringify_hash_keys!
|
48
|
-
@hash.
|
49
|
-
@hash[stringify_directive(key)] = @hash.delete(key)
|
50
|
-
end
|
49
|
+
@hash = @hash.inject({}) {|memo, (k, v)| memo[stringify_directive(k)] = v; memo}
|
51
50
|
end
|
52
|
-
|
51
|
+
|
53
52
|
def stringify_directives!
|
54
53
|
@directives = @directives.map {|d| stringify_directive(d)}.join(', ')
|
55
54
|
end
|
56
|
-
|
57
|
-
def stringify_hash
|
58
|
-
@hash.inject([]) {|arr, (k, v)| arr << "#{k}=#{v.call.inspect}"}.join(', ')
|
59
|
-
end
|
60
|
-
|
55
|
+
|
61
56
|
def stringify_directive(directive)
|
62
57
|
directive.to_s.tr('_','-')
|
63
58
|
end
|
59
|
+
|
60
|
+
def directives
|
61
|
+
@hash.inject(@directives) {|str, (k, v)| "#{str}, #{k}=#{v.call.inspect}"}
|
62
|
+
end
|
64
63
|
end
|
65
64
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
1
3
|
module Rackables
|
2
4
|
# Adds the specified charset to the Content-Type header, if one isn't
|
3
5
|
# already there.
|
4
6
|
#
|
5
7
|
# Ideal for use with Sinatra, which by default doesn't set charset
|
6
8
|
class DefaultCharset
|
7
|
-
HAS_CHARSET =
|
9
|
+
HAS_CHARSET = /;\s*charset\s*=\s*/i
|
8
10
|
|
9
11
|
def initialize(app, value = 'utf-8')
|
10
12
|
@app = app
|
@@ -12,13 +14,13 @@ module Rackables
|
|
12
14
|
end
|
13
15
|
|
14
16
|
def call(env)
|
15
|
-
|
16
|
-
headers =
|
17
|
+
status, headers, body = @app.call(env)
|
18
|
+
headers = ::Rack::Utils::HeaderHash.new(headers)
|
17
19
|
content_type = headers['Content-Type']
|
18
20
|
if content_type && content_type !~ HAS_CHARSET
|
19
21
|
headers['Content-Type'] = "#{content_type}; charset=#{@value}"
|
20
22
|
end
|
21
|
-
|
23
|
+
[status, headers, body]
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
3
|
+
module Rackables
|
4
|
+
# Allows you to tap into the response headers. Yields a Rack::Utils::HeaderHash
|
5
|
+
# of current response headers to the block. Example:
|
6
|
+
#
|
7
|
+
# use Rackables::ResponseHeaders do |headers|
|
8
|
+
# headers['X-Foo'] = 'bar'
|
9
|
+
# headers.delete('X-Baz')
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
class ResponseHeaders
|
13
|
+
def initialize(app, &block)
|
14
|
+
@app = app
|
15
|
+
@block = block
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
status, headers, body = @app.call(env)
|
20
|
+
headers = ::Rack::Utils::HeaderHash.new(headers)
|
21
|
+
@block.call(headers)
|
22
|
+
[status, headers, body]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Rackables
|
4
|
+
# Simplest example:
|
5
|
+
#
|
6
|
+
# use Rackables::SimpleEndpoint, '/ping_monitor' do
|
7
|
+
# 'pong'
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# HTTP verb requirements can optionally be specified:
|
11
|
+
#
|
12
|
+
# use Rackables::SimpleEndpoint, '/ping_monitor' => :get do
|
13
|
+
# 'only GET requests will match'
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# use Rackables::SimpleEndpoint, '/ping_monitor' => [:get, :post] do
|
17
|
+
# 'only GET and POST requests will match'
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# Rack::Request Rack::Response objects are yielded to block:
|
21
|
+
#
|
22
|
+
# use Rackables::SimpleEndpoint, '/json' do |request, response|
|
23
|
+
# response['Content-Type'] = 'application/json'
|
24
|
+
# %({"foo": "#{request[:foo]}"})
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# Example with regular expression -- match data object is yielded as third argument to block
|
28
|
+
#
|
29
|
+
# use Rackables::SimpleEndpoint, %r{^/(john|paul|george|ringo)} do |request, response, match|
|
30
|
+
# "Hello, #{match[1]}"
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# A :pass symbol returned from block will not return a response; control will continue down the
|
34
|
+
# Rack stack:
|
35
|
+
#
|
36
|
+
# use Rackables::SimpleEndpoint, '/api_key' do |request, response|
|
37
|
+
# request.env['myapp.user'].authorized? ? '12345' : :pass
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # Unauthorized access to /api_key will receive a 404
|
41
|
+
# run NotFoundApp
|
42
|
+
class SimpleEndpoint
|
43
|
+
def initialize(app, arg, &block)
|
44
|
+
@app = app
|
45
|
+
@path = extract_path(arg)
|
46
|
+
@verbs = extract_verbs(arg)
|
47
|
+
@block = block
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(env)
|
51
|
+
match = match_path(env['PATH_INFO'])
|
52
|
+
if match && valid_method?(env['REQUEST_METHOD'])
|
53
|
+
request, response = ::Rack::Request.new(env), ::Rack::Response.new
|
54
|
+
response.body = @block.call(request, response, (match unless match == true))
|
55
|
+
response.body == :pass ? @app.call(env) : response.finish
|
56
|
+
else
|
57
|
+
@app.call(env)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def extract_path(arg)
|
63
|
+
arg.is_a?(Hash) ? arg.keys.first : arg
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_verbs(arg)
|
67
|
+
arg.is_a?(Hash) ? [arg.values.first].flatten.map {|verb| verb.to_s.upcase} : []
|
68
|
+
end
|
69
|
+
|
70
|
+
def match_path(path)
|
71
|
+
@path.is_a?(Regexp) ? @path.match(path.to_s) : @path == path.to_s
|
72
|
+
end
|
73
|
+
|
74
|
+
def valid_method?(method)
|
75
|
+
@verbs.empty? || @verbs.include?(method)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
1
3
|
module Rackables
|
2
4
|
# Request paths with a trailing slash are 301 redirected to the version without, e.g.:
|
3
5
|
#
|
@@ -10,10 +12,10 @@ module Rackables
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def call(env)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
[301, {"Location" =>
|
15
|
+
req = Rack::Request.new(env)
|
16
|
+
if req.path_info =~ HAS_TRAILING_SLASH
|
17
|
+
req.path_info = "/#{$1}"
|
18
|
+
[301, {"Location" => req.url}, []]
|
17
19
|
else
|
18
20
|
@app.call(env)
|
19
21
|
end
|
metadata
CHANGED
@@ -1,77 +1,80 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rackables
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
|
-
authors:
|
6
|
+
authors:
|
7
7
|
- Geoff Buesing
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
date: 2013-06-18 00:00:00.000000000 Z
|
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: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack-test
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description:
|
17
42
|
email: gbuesing@gmail.com
|
18
43
|
executables: []
|
19
|
-
|
20
44
|
extensions: []
|
21
|
-
|
22
|
-
|
23
|
-
- README.rdoc
|
24
|
-
files:
|
25
|
-
- README.rdoc
|
26
|
-
- Rakefile
|
27
|
-
- VERSION
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
28
47
|
- lib/rackables.rb
|
29
48
|
- lib/rackables/branch.rb
|
30
49
|
- lib/rackables/cache_control.rb
|
31
50
|
- lib/rackables/default_charset.rb
|
32
|
-
- lib/rackables/get.rb
|
33
51
|
- lib/rackables/hide_exceptions.rb
|
34
|
-
- lib/rackables/
|
52
|
+
- lib/rackables/response_headers.rb
|
53
|
+
- lib/rackables/simple_endpoint.rb
|
35
54
|
- lib/rackables/trailing_slash_redirect.rb
|
36
|
-
-
|
37
|
-
|
38
|
-
|
39
|
-
-
|
40
|
-
|
41
|
-
- test/test_hide_exceptions.rb
|
42
|
-
- test/test_trailing_slash_redirect.rb
|
43
|
-
has_rdoc: true
|
44
|
-
homepage: http://github.com/gbuesing/rackables
|
45
|
-
licenses: []
|
46
|
-
|
55
|
+
- lib/rackables/more/env_inquirer.rb
|
56
|
+
homepage: https://github.com/gbuesing/rackables
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
metadata: {}
|
47
60
|
post_install_message:
|
48
|
-
rdoc_options:
|
49
|
-
|
50
|
-
require_paths:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
51
63
|
- lib
|
52
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
-
requirements:
|
54
|
-
- -
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
version:
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
version: "0"
|
63
|
-
version:
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
64
74
|
requirements: []
|
65
|
-
|
66
75
|
rubyforge_project:
|
67
|
-
rubygems_version:
|
76
|
+
rubygems_version: 2.0.0
|
68
77
|
signing_key:
|
69
|
-
specification_version:
|
70
|
-
summary:
|
71
|
-
test_files:
|
72
|
-
- test/test_branch.rb
|
73
|
-
- test/test_cache_control.rb
|
74
|
-
- test/test_default_charset.rb
|
75
|
-
- test/test_get.rb
|
76
|
-
- test/test_hide_exceptions.rb
|
77
|
-
- test/test_trailing_slash_redirect.rb
|
78
|
+
specification_version: 4
|
79
|
+
summary: A collection of useful Rack middleware
|
80
|
+
test_files: []
|
data/README.rdoc
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
= Rackables
|
2
|
-
|
3
|
-
== Middleware
|
4
|
-
|
5
|
-
Rackables bundles the following Rack middlewares:
|
6
|
-
|
7
|
-
* Rackables::Branch - Conditionally re-routes the Rack stack at runtime to an alternate endpoint
|
8
|
-
* Rackables::CacheControl - Sets response Cache-Control header
|
9
|
-
* Rackables::DefaultCharset - Sets charset directive in Content-Type header
|
10
|
-
* Rackables::Get - Allows creation of simple endpoints and path routing with a syntax similar to Sinatra's get method
|
11
|
-
* Rackables::HideExceptions - Rescues exceptions with a static exception page
|
12
|
-
* Rackables::TrailingSlashRedirect - 301 Redirects requests paths with a trailing slash
|
13
|
-
|
14
|
-
== More
|
15
|
-
|
16
|
-
Rackables also bundles a Rack environment inquirer similar to Rails.env:
|
17
|
-
|
18
|
-
Rack.env # => "development"
|
19
|
-
Rack.env.development? # => true
|
20
|
-
|
21
|
-
== Use
|
22
|
-
|
23
|
-
Requiring 'rackables' will add autoloads for all Rackables middlewares. To use the Rack.env inquirer,
|
24
|
-
you must explicitly require "rackables/more/env_inquirer".
|
25
|
-
|
26
|
-
Example config.ru:
|
27
|
-
|
28
|
-
require 'rackables'
|
29
|
-
require 'rackables/more/env_inquirer'
|
30
|
-
require 'my_endpont_app'
|
31
|
-
|
32
|
-
if Rack.env.development?
|
33
|
-
use Rack::ShowExceptions
|
34
|
-
else
|
35
|
-
use Rackables::HideExceptions, 'public/500.html'
|
36
|
-
end
|
37
|
-
|
38
|
-
use Rackables::TrailingSlashRedirect
|
39
|
-
use Rackables::CacheControl, :public, :max_age => 60
|
40
|
-
use Rackables::DefaultCharset, 'utf-8'
|
41
|
-
|
42
|
-
use Rackables::Get, '/ping_monitor' do
|
43
|
-
"pong"
|
44
|
-
end
|
45
|
-
|
46
|
-
use Rackables::Branch do |env|
|
47
|
-
Rack::Lobster if env["PATH_INFO"] =~ /^\/lobster$/
|
48
|
-
end
|
49
|
-
|
50
|
-
run MyEndpointApp
|
data/Rakefile
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'rake/testtask'
|
2
|
-
|
3
|
-
Rake::TestTask.new do |t|
|
4
|
-
t.libs << "test"
|
5
|
-
t.test_files = FileList['test/test*.rb']
|
6
|
-
t.verbose = true
|
7
|
-
end
|
8
|
-
task :default => :test
|
9
|
-
|
10
|
-
begin
|
11
|
-
require 'jeweler'
|
12
|
-
Jeweler::Tasks.new do |gemspec|
|
13
|
-
gemspec.name = "rackables"
|
14
|
-
gemspec.summary = "Bundle of useful Rack middleware"
|
15
|
-
gemspec.description = "Bundles Rack middleware: CacheControl, DefaultCharset, PublicExceptionPage, TrailingSlashRedirect"
|
16
|
-
gemspec.email = "gbuesing@gmail.com"
|
17
|
-
gemspec.homepage = "http://github.com/gbuesing/rackables"
|
18
|
-
gemspec.authors = ["Geoff Buesing"]
|
19
|
-
end
|
20
|
-
rescue LoadError
|
21
|
-
puts "Jeweler not available. Install it with: gem install jeweler"
|
22
|
-
end
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.2.0
|
data/lib/rackables/get.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
module Rackables
|
2
|
-
# Simplest example:
|
3
|
-
#
|
4
|
-
# use Rackables::Get, '/ping_monitor' do
|
5
|
-
# 'pong'
|
6
|
-
# end
|
7
|
-
#
|
8
|
-
# Rack::Response object is yielded as second argument to block:
|
9
|
-
#
|
10
|
-
# use Rackables::Get, '/json' do |env, response|
|
11
|
-
# response['Content-Type'] = 'application/json'
|
12
|
-
# %({"foo": "bar"})
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# Example with regular expression -- match data object is yielded as third argument to block
|
16
|
-
#
|
17
|
-
# use Rackables::Get, %r{^/(john|paul|george|ringo)} do |env, response, match|
|
18
|
-
# "Hello, #{match[1]}"
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# A false/nil return from block will not return a response; control will continue down the
|
22
|
-
# Rack stack:
|
23
|
-
#
|
24
|
-
# use Rackables::Get, '/api_key' do |env, response|
|
25
|
-
# '12345' if env['myapp.user'].authorized?
|
26
|
-
# end
|
27
|
-
class Get
|
28
|
-
def initialize(app, path, &block)
|
29
|
-
@app = app
|
30
|
-
@path = path
|
31
|
-
@block = block
|
32
|
-
end
|
33
|
-
|
34
|
-
def call(env)
|
35
|
-
path, method = env['PATH_INFO'].to_s, env['REQUEST_METHOD']
|
36
|
-
if method == 'GET' && ((@path.is_a?(Regexp) && match = @path.match(path)) || @path == path)
|
37
|
-
response = ::Rack::Response.new
|
38
|
-
response.body = @block.call(env, response, match)
|
39
|
-
response.body ? response.finish : @app.call(env)
|
40
|
-
else
|
41
|
-
@app.call(env)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1 +0,0 @@
|
|
1
|
-
<h1>Custom 500 page</h1>
|
data/test/test_branch.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rackables'
|
3
|
-
|
4
|
-
class TestBranch < Test::Unit::TestCase
|
5
|
-
|
6
|
-
def test_calls_app_returned_from_block
|
7
|
-
app = Proc.new { [200, {}, ["Downstream app"]] }
|
8
|
-
blog = Proc.new { [200, {}, ["Blog"]] }
|
9
|
-
middleware = Rackables::Branch.new(app) do |env|
|
10
|
-
blog if env['PATH_INFO'] =~ /^\/blog/
|
11
|
-
end
|
12
|
-
status, headers, body = middleware.call('PATH_INFO' => '/blog')
|
13
|
-
assert_equal 'Blog', body[0]
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_calls_app_passed_in_to_initialize_when_block_returns_false
|
17
|
-
app = Proc.new { [200, {}, ["Downstream app"]] }
|
18
|
-
blog = Proc.new { [200, {}, ["Blog"]] }
|
19
|
-
middleware = Rackables::Branch.new(app) do |env|
|
20
|
-
blog if env['PATH_INFO'] =~ /^\/blog/
|
21
|
-
end
|
22
|
-
status, headers, body = middleware.call('PATH_INFO' => '/foo')
|
23
|
-
assert_equal 'Downstream app', body[0]
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
data/test/test_cache_control.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rackables'
|
3
|
-
|
4
|
-
class TestCacheControl < Test::Unit::TestCase
|
5
|
-
|
6
|
-
def test_sets_cache_control_with_value_set_as_integer
|
7
|
-
app = Proc.new { [200, {}, []]}
|
8
|
-
middleware = Rackables::CacheControl.new(app, :public, :max_age => 5)
|
9
|
-
status, headers, body = middleware.call({})
|
10
|
-
assert_equal 'public, max-age=5', headers['Cache-Control']
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_sets_cache_control_with_value_set_as_string
|
14
|
-
app = Proc.new { [200, {}, []]}
|
15
|
-
middleware = Rackables::CacheControl.new(app, :public, :community => "UCI")
|
16
|
-
status, headers, body = middleware.call({})
|
17
|
-
assert_equal %(public, community="UCI"), headers['Cache-Control']
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_sets_cache_control_with_value_specified_as_proc_which_is_called_at_runtime
|
21
|
-
app = Proc.new { [200, {}, []]}
|
22
|
-
value = 7 #compile-time value
|
23
|
-
middleware = Rackables::CacheControl.new(app, :public, :max_age => Proc.new {value})
|
24
|
-
value = 5 #runtime value
|
25
|
-
status, headers, body = middleware.call({})
|
26
|
-
assert_equal 'public, max-age=5', headers['Cache-Control']
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_sets_cache_control_with_multiple_values
|
30
|
-
app = Proc.new { [200, {}, []]}
|
31
|
-
middleware = Rackables::CacheControl.new(app, :private, :no_cache, :must_revalidate)
|
32
|
-
status, headers, body = middleware.call({})
|
33
|
-
assert_equal %(private, no-cache, must-revalidate), headers['Cache-Control']
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_sets_true_value
|
37
|
-
app = Proc.new { [200, {}, []]}
|
38
|
-
middleware = Rackables::CacheControl.new(app, :private, :must_revalidate => true)
|
39
|
-
status, headers, body = middleware.call({})
|
40
|
-
assert_equal 'private, must-revalidate', headers['Cache-Control']
|
41
|
-
end
|
42
|
-
|
43
|
-
def test_does_not_set_false_value
|
44
|
-
app = Proc.new { [200, {}, []]}
|
45
|
-
middleware = Rackables::CacheControl.new(app, :private, :must_revalidate => false)
|
46
|
-
status, headers, body = middleware.call({})
|
47
|
-
assert_equal 'private', headers['Cache-Control']
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_respects_existing_cache_control_header
|
51
|
-
app = Proc.new { [200, {'Cache-Control' => 'private'}, []]}
|
52
|
-
middleware = Rackables::CacheControl.new(app, :public, :max_age => 5)
|
53
|
-
status, headers, body = middleware.call({})
|
54
|
-
assert_equal 'private', headers['Cache-Control']
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rackables'
|
3
|
-
|
4
|
-
class TestDefaultCharset < Test::Unit::TestCase
|
5
|
-
|
6
|
-
def test_adds_utf8_charset_by_default
|
7
|
-
app = Proc.new { [200, {'Content-Type' => 'text/html'}, []]}
|
8
|
-
middleware = Rackables::DefaultCharset.new(app)
|
9
|
-
status, headers, body = middleware.call({})
|
10
|
-
assert_equal 'text/html; charset=utf-8', headers['Content-Type']
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_adds_specified_charset
|
14
|
-
app = Proc.new { [200, {'Content-Type' => 'text/html'}, []]}
|
15
|
-
middleware = Rackables::DefaultCharset.new(app, 'us-ascii')
|
16
|
-
status, headers, body = middleware.call({})
|
17
|
-
assert_equal 'text/html; charset=us-ascii', headers['Content-Type']
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_does_not_overwrite_existing_charset_value
|
21
|
-
app = Proc.new { [200, {'Content-Type' => 'text/html; charset=us-ascii'}, []]}
|
22
|
-
middleware = Rackables::DefaultCharset.new(app, 'iso-8859-2')
|
23
|
-
status, headers, body = middleware.call({})
|
24
|
-
assert_equal 'text/html; charset=us-ascii', headers['Content-Type']
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
data/test/test_get.rb
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rackables'
|
3
|
-
require 'rubygems'
|
4
|
-
require 'rack'
|
5
|
-
|
6
|
-
class TestGet < Test::Unit::TestCase
|
7
|
-
|
8
|
-
def setup
|
9
|
-
@app = Proc.new { [200, {}, ["Downstream app"]] }
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_calls_downstream_app_when_no_match
|
13
|
-
middleware = Rackables::Get.new(@app, '/foo') { 'bar' }
|
14
|
-
status, headers, body = middleware.call('PATH_INFO' => '/bar', 'REQUEST_METHOD' => 'GET')
|
15
|
-
assert_equal 200, status
|
16
|
-
assert_equal 'Downstream app', body[0]
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_calls_downstream_app_when_path_matches_but_request_method_is_not_get
|
20
|
-
middleware = Rackables::Get.new(@app, '/foo') { 'bar' }
|
21
|
-
status, headers, body = middleware.call('PATH_INFO' => '/foo', 'REQUEST_METHOD' => 'POST')
|
22
|
-
assert_equal 200, status
|
23
|
-
assert_equal 'Downstream app', body[0]
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_calls_downstream_app_when_path_matches_but_block_returns_nil
|
27
|
-
middleware = Rackables::Get.new(@app, '/foo') { }
|
28
|
-
status, headers, body = middleware.call('PATH_INFO' => '/foo', 'REQUEST_METHOD' => 'GET')
|
29
|
-
assert_equal 200, status
|
30
|
-
assert_equal 'Downstream app', body[0]
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_get_returns_response_when_string_path_arg_matches_path_info
|
34
|
-
middleware = Rackables::Get.new(@app, '/foo') { 'bar' }
|
35
|
-
status, headers, body = middleware.call('PATH_INFO' => '/foo', 'REQUEST_METHOD' => 'GET')
|
36
|
-
assert_equal 200, status
|
37
|
-
assert_equal 'bar', body.body
|
38
|
-
end
|
39
|
-
|
40
|
-
def test_get_returns_response_when_string_path_arg_matches_regex
|
41
|
-
middleware = Rackables::Get.new(@app, /foo/) { 'bar' }
|
42
|
-
status, headers, body = middleware.call('PATH_INFO' => '/bar/foo', 'REQUEST_METHOD' => 'GET')
|
43
|
-
assert_equal 200, status
|
44
|
-
assert_equal 'bar', body.body
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_block_yields_env
|
48
|
-
env = {'PATH_INFO' => '/foo', 'REQUEST_METHOD' => 'GET'}
|
49
|
-
middleware = Rackables::Get.new(@app, '/foo') do |e, resp|
|
50
|
-
assert_equal env, e
|
51
|
-
end
|
52
|
-
status, headers, body = middleware.call(env)
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_block_yields_response_obj
|
56
|
-
env = {'PATH_INFO' => '/foo', 'REQUEST_METHOD' => 'GET'}
|
57
|
-
middleware = Rackables::Get.new(@app, '/foo') do |e, resp|
|
58
|
-
assert_instance_of ::Rack::Response, resp
|
59
|
-
end
|
60
|
-
status, headers, body = middleware.call(env)
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_block_yields_match_data
|
64
|
-
env = {'PATH_INFO' => '/foobar', 'REQUEST_METHOD' => 'GET'}
|
65
|
-
middleware = Rackables::Get.new(@app, /foo(.+)/) do |e, resp, match|
|
66
|
-
assert_instance_of MatchData, match
|
67
|
-
assert_equal 'bar', match[1]
|
68
|
-
end
|
69
|
-
status, headers, body = middleware.call(env)
|
70
|
-
end
|
71
|
-
|
72
|
-
def test_response_honors_headers_set_in_block
|
73
|
-
middleware = Rackables::Get.new(@app, '/foo') {|e, r| r['X-Foo'] = 'bar'; 'baz' }
|
74
|
-
status, headers, body = middleware.call('PATH_INFO' => '/foo', 'REQUEST_METHOD' => 'GET')
|
75
|
-
assert_equal 200, status
|
76
|
-
assert_equal 'bar', headers['X-Foo']
|
77
|
-
assert_equal 'baz', body.body
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rackables'
|
3
|
-
|
4
|
-
class TestHideExceptions < Test::Unit::TestCase
|
5
|
-
|
6
|
-
def test_returns_downstream_app_response_when_no_exception_raised
|
7
|
-
app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
|
8
|
-
middleware = Rackables::HideExceptions.new(app)
|
9
|
-
status, headers, body = middleware.call({})
|
10
|
-
assert_equal 200, status
|
11
|
-
assert_equal ['Downstream app'], body
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_returns_500_with_default_exception_page_when_exception_raised_by_downstream_app
|
15
|
-
app = Proc.new { raise }
|
16
|
-
middleware = Rackables::HideExceptions.new(app)
|
17
|
-
status, headers, body = middleware.call({})
|
18
|
-
assert_equal 500, status
|
19
|
-
assert_match /We\'re sorry, but something went wrong/, body[0]
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_returns_500_with_custom_exception_page_when_file_path_specified
|
23
|
-
app = Proc.new { raise }
|
24
|
-
middleware = Rackables::HideExceptions.new(app, 'test/fixtures/custom_500.html')
|
25
|
-
status, headers, body = middleware.call({})
|
26
|
-
assert_equal 500, status
|
27
|
-
assert_match /Custom 500 page/, body[0]
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'rackables'
|
3
|
-
|
4
|
-
class TestTrailingSlashRedirect < Test::Unit::TestCase
|
5
|
-
|
6
|
-
def test_passes_to_downstream_app_when_no_trailing_slash_on_path_info
|
7
|
-
app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
|
8
|
-
middleware = Rackables::TrailingSlashRedirect.new(app)
|
9
|
-
status, headers, body = middleware.call({'PATH_INFO' => '/foo'})
|
10
|
-
assert_equal 200, status
|
11
|
-
assert_equal ['Downstream app'], body
|
12
|
-
assert_nil headers['Location']
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_returns_301_when_trailing_slash_on_path_info
|
16
|
-
app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
|
17
|
-
middleware = Rackables::TrailingSlashRedirect.new(app)
|
18
|
-
status, headers, body = middleware.call({'rack.url_scheme' => 'http', 'HTTP_HOST' => 'bar.com', 'PATH_INFO' => '/foo/'})
|
19
|
-
assert_equal 301, status
|
20
|
-
assert_equal 'http://bar.com/foo', headers['Location']
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_301_respects_query_string
|
24
|
-
app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
|
25
|
-
middleware = Rackables::TrailingSlashRedirect.new(app)
|
26
|
-
status, headers, body = middleware.call({'rack.url_scheme' => 'http', 'HTTP_HOST' => 'bar.com', 'PATH_INFO' => '/foo/', 'QUERY_STRING' => 'baz=hi'})
|
27
|
-
assert_equal 301, status
|
28
|
-
assert_equal 'http://bar.com/foo?baz=hi', headers['Location']
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_301_respects_https
|
32
|
-
app = Proc.new { [200, {'Content-Type' => 'text/html'}, ['Downstream app']]}
|
33
|
-
middleware = Rackables::TrailingSlashRedirect.new(app)
|
34
|
-
status, headers, body = middleware.call({'rack.url_scheme' => 'https', 'HTTP_HOST' => 'bar.com', 'PATH_INFO' => '/foo/', 'QUERY_STRING' => 'baz=hi'})
|
35
|
-
assert_equal 301, status
|
36
|
-
assert_equal 'https://bar.com/foo?baz=hi', headers['Location']
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|