mynyml-rack-respond_to 0.9.5 → 0.9.6
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.
- 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
|