mynyml-rack-respond_to 0.9.5 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README +23 -7
- data/Rakefile +1 -1
- data/TODO +3 -3
- data/examples/recommended_use.ru +3 -2
- data/examples/simple_app.ru +2 -2
- data/lib/rack/respond_to.rb +70 -33
- data/rack-respond_to.gemspec +2 -2
- data/test/test_respond_to.rb +58 -42
- metadata +2 -2
data/README
CHANGED
@@ -1,7 +1,21 @@
|
|
1
1
|
===== Summary
|
2
2
|
|
3
3
|
Rack convenience middleware that allows triggering different actions based on
|
4
|
-
requested
|
4
|
+
requested media type. Standalone version of the equivalent Rails functionality.
|
5
|
+
|
6
|
+
RespondTo gets the requested media type from the Accept header, which contains
|
7
|
+
a list of media types accepted/requested by the client, ordered by level of
|
8
|
+
preference (see http://github.com/mynyml/rack-accept-media-types).
|
9
|
+
|
10
|
+
===== Features
|
11
|
+
|
12
|
+
* Based on familiar API (Rails)
|
13
|
+
* Cascades down priority list of accepted media types
|
14
|
+
* Simple to use
|
15
|
+
* Simple code (~50 LOCs)
|
16
|
+
* Flexible (standalone use)
|
17
|
+
* Decently documented (examples/ dir, source docs/rdocs)
|
18
|
+
* Compatible with other media type handling middleware (uses Rack::AcceptMediaTypes)
|
5
19
|
|
6
20
|
===== Installation
|
7
21
|
|
@@ -17,30 +31,32 @@ requested mime type. Standalone version of the equivalent Rails functionality.
|
|
17
31
|
include Rack::RespondTo
|
18
32
|
|
19
33
|
def call(env)
|
20
|
-
# Pass in the env, and RespondTo will retrieve the requested
|
34
|
+
# Pass in the env, and RespondTo will retrieve the requested media types
|
21
35
|
Rack::RespondTo.env = env
|
22
36
|
|
23
|
-
# Alternatively, to use standalone you can also assign the
|
37
|
+
# Alternatively, to use standalone you can also assign the media types
|
24
38
|
# directly (this will take precedence over the env)
|
25
|
-
#Rack::RespondTo.
|
39
|
+
#Rack::RespondTo.media_types = ['text/html']
|
26
40
|
|
27
41
|
body = respond_to do |format|
|
28
42
|
format.html { '<em>html</em>' }
|
29
43
|
format.xml { '<body>xml</body>' }
|
30
44
|
end
|
31
45
|
|
32
|
-
[200, {'Content-Type' => Rack::RespondTo.
|
46
|
+
[200, {'Content-Type' => Rack::RespondTo.selected_media_type}, [body]]
|
33
47
|
end
|
34
48
|
end
|
35
49
|
|
36
50
|
run App.new
|
37
51
|
|
52
|
+
See examples/simple_app.ru for an executable example.
|
53
|
+
|
38
54
|
===== Tips
|
39
55
|
|
40
56
|
Use together with Rack::AbstractFormat to respond to routes based on url
|
41
57
|
extensions. For example, if you want <tt>example.com/foo.xml</tt> to trigger
|
42
|
-
the <tt>format.xml</tt> block (Rack::AbstractFormat moves the extension
|
43
|
-
HTTP_ACCEPT).
|
58
|
+
the <tt>format.xml</tt> block (Rack::AbstractFormat moves the extension's media
|
59
|
+
type into HTTP_ACCEPT and makes it the highest ranked).
|
44
60
|
|
45
61
|
sudo gem install mynyml-rack-abstract-format --source=http://gems.github.com/
|
46
62
|
|
data/Rakefile
CHANGED
@@ -22,7 +22,7 @@ end
|
|
22
22
|
|
23
23
|
spec = Gem::Specification.new do |s|
|
24
24
|
s.name = 'rack-respond_to'
|
25
|
-
s.version = '0.9.
|
25
|
+
s.version = '0.9.6'
|
26
26
|
s.summary = "Rack middleware port of Rails's respond_to feature"
|
27
27
|
s.description = "Rack middleware port of Rails's respond_to feature"
|
28
28
|
s.author = "Martin Aumont"
|
data/TODO
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
o handle wildcard content-types
|
1
|
+
o handle wildcard content-types
|
2
2
|
e.g. */* matches first format block
|
3
3
|
|
4
4
|
Rack::RespondTo.mime_type = '*/*'
|
@@ -15,8 +15,8 @@ o handle wildcard content-types?
|
|
15
15
|
end
|
16
16
|
body #=> 'xml'
|
17
17
|
|
18
|
-
|
19
|
-
type. e.g:
|
18
|
+
x cascade down accept types priority instead of only responding to prefered
|
19
|
+
type. e.g:
|
20
20
|
|
21
21
|
env['HTTP_ACCEPT'] #=> 'text/plain,text/html;q=0.9,application/xml;q=0.8'
|
22
22
|
|
data/examples/recommended_use.ru
CHANGED
@@ -25,6 +25,8 @@ class App
|
|
25
25
|
request = Rack::Request.new(env)
|
26
26
|
|
27
27
|
body = case request.path_info
|
28
|
+
when '/'
|
29
|
+
"try foo<em>.html</em> and foo<em>.xml</em>"
|
28
30
|
when '/foo'
|
29
31
|
respond_to do |format|
|
30
32
|
format.html { '<em>html</em>' }
|
@@ -32,10 +34,9 @@ class App
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
[200, {'Content-Type' => Rack::RespondTo.
|
37
|
+
[200, {'Content-Type' => Rack::RespondTo.selected_media_type || 'text/html'}, [body]]
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
41
|
use Rack::AbstractFormat
|
40
42
|
run App.new
|
41
|
-
|
data/examples/simple_app.ru
CHANGED
@@ -13,7 +13,7 @@ class App
|
|
13
13
|
include Rack::RespondTo
|
14
14
|
|
15
15
|
def call(env)
|
16
|
-
Rack::RespondTo.
|
16
|
+
Rack::RespondTo.media_types = %w( application/xml )
|
17
17
|
|
18
18
|
body = case env['PATH_INFO']
|
19
19
|
when '/'
|
@@ -23,7 +23,7 @@ class App
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
[200, {'Content-Type' => Rack::RespondTo.
|
26
|
+
[200, {'Content-Type' => Rack::RespondTo.selected_media_type}, [body]]
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
data/lib/rack/respond_to.rb
CHANGED
@@ -8,26 +8,39 @@ module Rack
|
|
8
8
|
#
|
9
9
|
module RespondTo
|
10
10
|
class << self
|
11
|
-
# Assign the environment directly to fetch the
|
11
|
+
# Assign the environment directly to fetch the requested media types from
|
12
12
|
# env['HTTP_ACCEPT'] ('Accept:' request header).
|
13
13
|
#
|
14
14
|
# ===== Example
|
15
15
|
#
|
16
16
|
# def call(env)
|
17
17
|
# Rack::RespondTo.env = env
|
18
|
+
# #...
|
18
19
|
# end
|
19
20
|
#
|
20
21
|
attr_accessor :env
|
21
22
|
|
22
|
-
# If used completely standalone, you can assign the
|
23
|
+
# If used completely standalone, you can assign the requested media types
|
24
|
+
# directly.
|
23
25
|
#
|
24
26
|
# ===== Example
|
25
27
|
#
|
26
|
-
# RespondTo.
|
28
|
+
# RespondTo.media_types = ['application/xml']
|
27
29
|
#
|
28
|
-
attr_accessor :
|
29
|
-
alias :
|
30
|
-
alias :
|
30
|
+
attr_accessor :media_types
|
31
|
+
alias :mime_types= :media_types=
|
32
|
+
alias :mime_types :media_types
|
33
|
+
|
34
|
+
# Contains the media type that was responded to. Set after the respond_to
|
35
|
+
# block is called.
|
36
|
+
#
|
37
|
+
# Useful for setting the response's Content-Type:
|
38
|
+
#
|
39
|
+
# [200, {'Content-Type' => RespondTo.selected_media_type}, [body]]
|
40
|
+
#
|
41
|
+
attr_accessor :selected_media_type
|
42
|
+
alias :selected_mime_type= :selected_media_type=
|
43
|
+
alias :selected_mime_type :selected_media_type
|
31
44
|
|
32
45
|
def included(base) #:nodoc:
|
33
46
|
base.extend(ClassMethods)
|
@@ -36,34 +49,35 @@ module Rack
|
|
36
49
|
end
|
37
50
|
end
|
38
51
|
|
39
|
-
#
|
52
|
+
# Cast format to media type
|
40
53
|
#
|
41
|
-
#
|
54
|
+
# ===== Example
|
42
55
|
#
|
43
|
-
#
|
56
|
+
# RespondTo::MediaType('html') #=> 'text/html'
|
57
|
+
# RespondTo::MediaType('htm') #=> 'text/html'
|
44
58
|
#
|
45
|
-
def
|
46
|
-
|
59
|
+
def MediaType(format)
|
60
|
+
Rack::Mime.mime_type(format.sub(/^\./,'').insert(0,'.'))
|
47
61
|
end
|
62
|
+
alias :MimeType :MediaType
|
48
63
|
|
49
|
-
#
|
64
|
+
# Requested media types, in preferencial order
|
50
65
|
#
|
51
|
-
# =====
|
66
|
+
# ===== Examples
|
52
67
|
#
|
53
|
-
# RespondTo
|
68
|
+
# RespondTo.env['HTTP_ACCEPT'] #=> 'text/html,application/xml'
|
69
|
+
# RespondTo.media_types #=> ['text/html', 'application/xml']
|
54
70
|
#
|
55
|
-
|
56
|
-
|
71
|
+
# RespondTo.env['HTTP_ACCEPT'] #=> 'text/html;q=0.7,application/xml;q=0.9,application/json;q=0.8'
|
72
|
+
# RespondTo.media_types #=> ['application/xml', 'application/json', 'text/html']
|
73
|
+
#
|
74
|
+
def media_types
|
75
|
+
@media_types || accept_list
|
57
76
|
end
|
58
77
|
|
59
78
|
private
|
60
|
-
|
61
|
-
|
62
|
-
# ===== Returns
|
63
|
-
# String:: first mime type from header's list or nil if none
|
64
|
-
#
|
65
|
-
def accept
|
66
|
-
Rack::AcceptMediaTypes.new(self.env['HTTP_ACCEPT'] || '').prefered unless self.env.nil?
|
79
|
+
def accept_list
|
80
|
+
self.env.nil? ? [] : Rack::AcceptMediaTypes.new(self.env['HTTP_ACCEPT'] || '')
|
67
81
|
end
|
68
82
|
end
|
69
83
|
|
@@ -75,30 +89,53 @@ module Rack
|
|
75
89
|
end
|
76
90
|
|
77
91
|
module ClassMethods
|
92
|
+
|
78
93
|
# Allows defining different actions and returns the one which corresponds
|
79
|
-
# to the
|
94
|
+
# to the highest ranking value in the RespondTo.media_types list.
|
80
95
|
#
|
81
|
-
#
|
96
|
+
# If no handler is defined for the highest ranking value, respond_to will
|
97
|
+
# cascade down the RespondTo.media_types list until it finds a match.
|
98
|
+
# Returns nil if there is no match.
|
82
99
|
#
|
83
|
-
#
|
100
|
+
# ===== Examples
|
101
|
+
#
|
102
|
+
# RespondTo.media_types = ['text/html', 'application/xml']
|
84
103
|
#
|
85
104
|
# respond_to do |format|
|
86
|
-
# format.html { '
|
87
|
-
# format.xml { '
|
105
|
+
# format.html { 'html' }
|
106
|
+
# format.xml { 'xml' }
|
88
107
|
# end
|
89
|
-
# #=> '
|
108
|
+
# #=> 'html'
|
90
109
|
#
|
91
|
-
|
110
|
+
# RespondTo.media_types = ['text/html', 'application/xml']
|
111
|
+
#
|
112
|
+
# respond_to do |format|
|
113
|
+
# format.xml { 'xml' }
|
114
|
+
# format.txt { 'txt' }
|
115
|
+
# end
|
116
|
+
# #=> 'xml'
|
117
|
+
#
|
118
|
+
# RespondTo.media_types = ['text/html', 'application/json']
|
119
|
+
#
|
120
|
+
# respond_to do |format|
|
121
|
+
# format.xml { 'xml' }
|
122
|
+
# format.txt { 'txt' }
|
123
|
+
# end
|
124
|
+
# #=> nil
|
125
|
+
#
|
126
|
+
def respond_to
|
92
127
|
format = Format.new
|
93
|
-
|
94
|
-
|
128
|
+
yield format
|
129
|
+
type = RespondTo.media_types.detect {|type| format[type] }
|
130
|
+
RespondTo.selected_media_type = type
|
131
|
+
handler = format[type]
|
95
132
|
handler.nil? ? nil : handler.call
|
96
133
|
end
|
97
134
|
end
|
98
135
|
|
99
136
|
class Format < Hash #:nodoc:
|
100
137
|
def method_missing(format, *args, &handler)
|
101
|
-
self[RespondTo::
|
138
|
+
self[RespondTo::MediaType(format.to_s)] = handler
|
102
139
|
end
|
103
140
|
end
|
104
141
|
end
|
data/rack-respond_to.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-respond_to
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Aumont
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-09 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
data/test/test_respond_to.rb
CHANGED
@@ -7,7 +7,9 @@ end
|
|
7
7
|
class TestRespondTo < Test::Unit::TestCase
|
8
8
|
|
9
9
|
def setup
|
10
|
-
Rack::RespondTo.
|
10
|
+
Rack::RespondTo.selected_media_type = nil
|
11
|
+
Rack::RespondTo.media_types = nil
|
12
|
+
Rack::RespondTo.env = nil
|
11
13
|
end
|
12
14
|
|
13
15
|
## api
|
@@ -18,13 +20,21 @@ class TestRespondTo < Test::Unit::TestCase
|
|
18
20
|
assert_equal env, Rack::RespondTo.env
|
19
21
|
end
|
20
22
|
|
21
|
-
test "
|
22
|
-
Rack::RespondTo.
|
23
|
-
assert_equal
|
23
|
+
test "media types accessor" do
|
24
|
+
Rack::RespondTo.media_types = %w( application/xml )
|
25
|
+
assert_equal %w( application/xml ), Rack::RespondTo.media_types
|
24
26
|
|
25
27
|
# alias
|
26
|
-
Rack::RespondTo.
|
27
|
-
assert_equal
|
28
|
+
Rack::RespondTo.media_types = %w( application/xml )
|
29
|
+
assert_equal %w( application/xml ), Rack::RespondTo.media_types
|
30
|
+
end
|
31
|
+
|
32
|
+
test "selected media type reader" do
|
33
|
+
Rack::RespondTo.media_types = %w( application/xml )
|
34
|
+
body = App.respond_to do |format|
|
35
|
+
format.xml { 'xml' }
|
36
|
+
end
|
37
|
+
assert_equal 'application/xml', Rack::RespondTo.selected_media_type
|
28
38
|
end
|
29
39
|
|
30
40
|
test "mixin injects respond_to class method" do
|
@@ -35,59 +45,54 @@ class TestRespondTo < Test::Unit::TestCase
|
|
35
45
|
assert App.new.respond_to?(:respond_to)
|
36
46
|
end
|
37
47
|
|
38
|
-
##
|
48
|
+
## requested media types
|
39
49
|
|
40
|
-
test "
|
41
|
-
Rack::RespondTo.env = {'HTTP_ACCEPT' => 'text/html
|
42
|
-
|
43
|
-
|
44
|
-
Rack::RespondTo.env = {'HTTP_ACCEPT' => 'application/xml,text/html'}
|
45
|
-
assert_equal 'application/xml', Rack::RespondTo.mime_type
|
50
|
+
test "explicitly specified media types take precedence over header's" do
|
51
|
+
Rack::RespondTo.env = {'HTTP_ACCEPT' => 'text/html'}
|
52
|
+
Rack::RespondTo.media_types = %w( text/plain )
|
53
|
+
assert_equal %w( text/plain ), Rack::RespondTo.media_types
|
46
54
|
end
|
47
55
|
|
48
|
-
|
49
|
-
assert_nothing_raised do
|
50
|
-
Rack::RespondTo.env = {'HTTP_ACCEPT' => ''}
|
51
|
-
Rack::RespondTo.mime_type = nil
|
52
|
-
assert_equal nil, Rack::RespondTo.mime_type
|
53
|
-
end
|
54
|
-
end
|
56
|
+
## respond_to
|
55
57
|
|
56
|
-
test "
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
test "respond_to returns block for highest ranking format" do
|
59
|
+
Rack::RespondTo.env = {'HTTP_ACCEPT' => 'application/xml;q=0.8,text/plain;q=0.9'}
|
60
|
+
body = App.respond_to do |format|
|
61
|
+
format.xml { 'xml' }
|
62
|
+
format.txt { 'txt' }
|
61
63
|
end
|
64
|
+
assert_equal 'txt', body
|
62
65
|
end
|
63
66
|
|
64
|
-
test "
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
67
|
+
test "cascades down the Accept header's list to find suitable type" do
|
68
|
+
Rack::RespondTo.env = {'HTTP_ACCEPT' => 'text/html,text/plain;q=0.9'}
|
69
|
+
body = App.respond_to do |format|
|
70
|
+
format.xml { 'xml' }
|
71
|
+
format.txt { 'txt' }
|
69
72
|
end
|
73
|
+
assert_equal 'txt', body
|
70
74
|
end
|
71
75
|
|
72
|
-
test "
|
73
|
-
Rack::RespondTo.
|
74
|
-
|
75
|
-
|
76
|
+
test "respond_to with no matching format" do
|
77
|
+
Rack::RespondTo.media_types = %w( text/html )
|
78
|
+
body = App.respond_to do |format|
|
79
|
+
format.xml { 'xml' }
|
80
|
+
format.txt { 'txt' }
|
81
|
+
end
|
82
|
+
assert_equal nil, body
|
76
83
|
end
|
77
84
|
|
78
|
-
|
79
|
-
|
80
|
-
test "respond_to returns block for requested format" do
|
81
|
-
Rack::RespondTo.mime_type = 'application/xml'
|
85
|
+
test "respond_to with empty type list" do
|
86
|
+
Rack::RespondTo.media_types = []
|
82
87
|
body = App.respond_to do |format|
|
83
88
|
format.xml { 'xml' }
|
84
89
|
format.txt { 'txt' }
|
85
90
|
end
|
86
|
-
assert_equal
|
91
|
+
assert_equal nil, body
|
87
92
|
end
|
88
93
|
|
89
|
-
test "respond_to with
|
90
|
-
Rack::RespondTo.
|
94
|
+
test "respond_to with nil type list" do
|
95
|
+
Rack::RespondTo.media_types = nil
|
91
96
|
body = App.respond_to do |format|
|
92
97
|
format.xml { 'xml' }
|
93
98
|
format.txt { 'txt' }
|
@@ -96,7 +101,7 @@ class TestRespondTo < Test::Unit::TestCase
|
|
96
101
|
end
|
97
102
|
|
98
103
|
test "respond_to handles synonymous formats" do
|
99
|
-
Rack::RespondTo.
|
104
|
+
Rack::RespondTo.media_types = %w( text/html )
|
100
105
|
|
101
106
|
body = App.respond_to do |format|
|
102
107
|
format.htm { 'htm' } # htm/html
|
@@ -110,4 +115,15 @@ class TestRespondTo < Test::Unit::TestCase
|
|
110
115
|
end
|
111
116
|
assert_equal 'html', body
|
112
117
|
end
|
118
|
+
|
119
|
+
test "repond_to sets selected media type" do
|
120
|
+
Rack::RespondTo.media_types = %w( text/html text/plain )
|
121
|
+
assert_equal nil, Rack::RespondTo.selected_media_type
|
122
|
+
body = App.respond_to do |format|
|
123
|
+
format.xml { 'xml' }
|
124
|
+
format.txt { 'txt' }
|
125
|
+
end
|
126
|
+
assert_equal 'txt', body
|
127
|
+
assert_equal 'text/plain', Rack::RespondTo.selected_media_type
|
128
|
+
end
|
113
129
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mynyml-rack-respond_to
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Aumont
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-06-
|
12
|
+
date: 2009-06-08 21:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|