merb 0.4.0 → 0.4.1
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 -160
- data/Rakefile +15 -14
- data/app_generators/merb/merb_generator.rb +4 -3
- data/app_generators/merb/templates/Rakefile +1 -6
- data/app_generators/merb/templates/app/mailers/views/layout/{application.erb → application.html.erb} +0 -0
- data/app_generators/merb/templates/app/mailers/views/layout/application.text.erb +1 -0
- data/app_generators/merb/templates/app/parts/views/layout/application.html.erb +1 -0
- data/app_generators/merb/templates/app/views/layout/application.html.erb +2 -2
- data/app_generators/merb/templates/config/dependencies.rb +1 -1
- data/app_generators/merb/templates/config/router.rb +4 -1
- data/app_generators/merb/templates/spec/spec_helper.rb +2 -3
- data/lib/autotest/merb_rspec.rb +1 -0
- data/lib/merb/abstract_controller.rb +31 -2
- data/lib/merb/controller.rb +5 -5
- data/lib/merb/core_ext/get_args.rb +5 -1
- data/lib/merb/exceptions.rb +17 -0
- data/lib/merb/generators/merb_app/merb_app.rb +4 -1
- data/lib/merb/generators/merb_plugin.rb +4 -1
- data/lib/merb/logger.rb +5 -1
- data/lib/merb/mail_controller.rb +1 -1
- data/lib/merb/mailer.rb +2 -2
- data/lib/merb/mixins/controller.rb +5 -1
- data/lib/merb/mixins/render.rb +57 -27
- data/lib/merb/part_controller.rb +1 -1
- data/lib/merb/request.rb +2 -2
- data/lib/merb/server.rb +33 -5
- data/lib/merb/template/erubis.rb +1 -1
- data/lib/merb.rb +15 -5
- data/merb_generators/resource/resource_generator.rb +9 -2
- data/spec/fixtures/config/merb.yml +18 -0
- data/spec/fixtures/controllers/dispatch_spec_controllers.rb +227 -0
- data/spec/fixtures/controllers/render_spec_controllers.rb +115 -0
- data/spec/fixtures/foo.rb +3 -0
- data/spec/fixtures/mailers/views/layout/application.html.erb +3 -0
- data/spec/fixtures/mailers/views/layout/application.text.erb +3 -0
- data/spec/fixtures/mailers/views/test_mail_controller/eighth.html.erb +1 -0
- data/spec/fixtures/mailers/views/test_mail_controller/eighth.text.erb +1 -0
- data/spec/fixtures/mailers/views/test_mail_controller/first.html.erb +1 -0
- data/spec/fixtures/mailers/views/test_mail_controller/first.text.erb +1 -0
- data/spec/fixtures/mailers/views/test_mail_controller/ninth.html.erb +1 -0
- data/spec/fixtures/mailers/views/test_mail_controller/ninth.text.erb +1 -0
- data/spec/fixtures/mailers/views/test_mail_controller/second.text.erb +1 -0
- data/spec/fixtures/mailers/views/test_mail_controller/third.html.erb +1 -0
- data/spec/fixtures/models/router_spec_models.rb +20 -0
- data/spec/fixtures/parts/views/layout/todo_part.html.erb +3 -0
- data/spec/fixtures/parts/views/layout/todo_part.xml.erb +3 -0
- data/spec/fixtures/parts/views/todo_part/formatted_output.html.erb +1 -0
- data/spec/fixtures/parts/views/todo_part/formatted_output.js.erb +1 -0
- data/spec/fixtures/parts/views/todo_part/formatted_output.xml.erb +1 -0
- data/spec/fixtures/parts/views/todo_part/list.html.erb +3 -0
- data/spec/fixtures/sample.txt +1 -0
- data/spec/fixtures/views/erubis.html.erb +1 -0
- data/spec/fixtures/views/examples/_erubis.html.erb +1 -0
- data/spec/fixtures/views/examples/_haml.html.haml +1 -0
- data/spec/fixtures/views/examples/_markaby.html.mab +1 -0
- data/spec/fixtures/views/examples/_throw_content.html.erb +6 -0
- data/spec/fixtures/views/examples/hello.xml.builder +1 -0
- data/spec/fixtures/views/examples/js.js.erb +1 -0
- data/spec/fixtures/views/examples/template_catch_content.html.erb +15 -0
- data/spec/fixtures/views/examples/template_catch_content_from_partial.html.erb +6 -0
- data/spec/fixtures/views/examples/template_throw_content.html.erb +10 -0
- data/spec/fixtures/views/exceptions/admin_access_required.html.erb +1 -0
- data/spec/fixtures/views/extension_template_controller/_nested_js.js.erb +1 -0
- data/spec/fixtures/views/extension_template_controller/_nested_xml.xml.erb +1 -0
- data/spec/fixtures/views/extension_template_controller/_render_partial_multiple_times.html.erb +1 -0
- data/spec/fixtures/views/extension_template_controller/erubis_templates.html.erb +1 -0
- data/spec/fixtures/views/extension_template_controller/erubis_templates.js.erb +1 -0
- data/spec/fixtures/views/extension_template_controller/erubis_templates.rhtml +1 -0
- data/spec/fixtures/views/extension_template_controller/erubis_templates.xml.erb +1 -0
- data/spec/fixtures/views/extension_template_controller/haml_index.html.haml +0 -0
- data/spec/fixtures/views/extension_template_controller/haml_templates.html.haml +1 -0
- data/spec/fixtures/views/extension_template_controller/haml_templates.js.haml +1 -0
- data/spec/fixtures/views/extension_template_controller/haml_templates.xml.haml +1 -0
- data/spec/fixtures/views/extension_template_controller/index.html.erb +0 -0
- data/spec/fixtures/views/extension_template_controller/markaby_index.html.mab +0 -0
- data/spec/fixtures/views/extension_template_controller/markaby_templates.html.mab +1 -0
- data/spec/fixtures/views/extension_template_controller/markaby_templates.js.mab +1 -0
- data/spec/fixtures/views/extension_template_controller/markaby_templates.xml.mab +1 -0
- data/spec/fixtures/views/extension_template_controller/render_multiple_partials.html.erb +4 -0
- data/spec/fixtures/views/extension_template_controller/render_nested_js.js.erb +1 -0
- data/spec/fixtures/views/extension_template_controller/render_nested_xml.xml.erb +1 -0
- data/spec/fixtures/views/haml.html.haml +1 -0
- data/spec/fixtures/views/haml.xml.haml +2 -0
- data/spec/fixtures/views/layout/application.html.erb +1 -0
- data/spec/fixtures/views/layout/application.xml.erb +1 -0
- data/spec/fixtures/views/layout/nested/example.html.erb +1 -0
- data/spec/fixtures/views/markaby.html.mab +1 -0
- data/spec/fixtures/views/nested/example/test.html.erb +1 -0
- data/spec/fixtures/views/partials/_erubis.html.erb +1 -0
- data/spec/fixtures/views/partials/_erubis_collection.html.erb +1 -0
- data/spec/fixtures/views/partials/_erubis_collection_with_locals.html.erb +1 -0
- data/spec/fixtures/views/partials/_erubis_new.html.erb +1 -0
- data/spec/fixtures/views/partials/_haml.html.haml +1 -0
- data/spec/fixtures/views/partials/_haml_collection.html.haml +1 -0
- data/spec/fixtures/views/partials/_haml_collection_with_locals.html.haml +1 -0
- data/spec/fixtures/views/partials/_haml_new.html.haml +1 -0
- data/spec/fixtures/views/partials/_markaby.html.mab +1 -0
- data/spec/fixtures/views/partials/_markaby_collection.html.mab +1 -0
- data/spec/fixtures/views/partials/_markaby_collection_with_locals.html.mab +1 -0
- data/spec/fixtures/views/partials/_markaby_new.html.mab +1 -0
- data/spec/fixtures/views/render_object_controller/render_object_with_template.html.erb +1 -0
- data/spec/fixtures/views/render_object_controller/render_object_with_template.js.erb +1 -0
- data/spec/fixtures/views/render_object_controller/render_object_with_template.xml.erb +1 -0
- data/spec/fixtures/views/template_views/interface__buffer_erubis.html.erb +4 -0
- data/spec/fixtures/views/template_views/interface__buffer_haml.html.haml +7 -0
- data/spec/fixtures/views/template_views/interface__buffer_markaby.html.mab +7 -0
- data/spec/fixtures/views/template_views/interface_capture_erubis.html.erb +15 -0
- data/spec/fixtures/views/template_views/interface_capture_haml.html.haml +15 -0
- data/spec/fixtures/views/template_views/interface_capture_markaby.html.mab +4 -0
- data/spec/fixtures/views/template_views/interface_concat_erubis.html.erb +12 -0
- data/spec/fixtures/views/template_views/interface_concat_haml.html.haml +11 -0
- data/spec/fixtures/views/template_views/interface_concat_markaby.html.mab +14 -0
- data/spec/fixtures/views/test.dir/the_template.html.erb +1 -0
- data/spec/merb/abstract_controller_spec.rb +37 -0
- data/spec/merb/caching_spec.rb +102 -0
- data/spec/merb/config_spec.rb +29 -0
- data/spec/merb/controller_filters_spec.rb +188 -0
- data/spec/merb/controller_spec.rb +144 -0
- data/spec/merb/cookie_store_spec.rb +85 -0
- data/spec/merb/core_ext_spec.rb +430 -0
- data/spec/merb/dispatch_spec.rb +514 -0
- data/spec/merb/fake_request_spec.rb +72 -0
- data/spec/merb/form_control_mixin_spec.rb +431 -0
- data/spec/merb/generator_spec.rb +121 -0
- data/spec/merb/handler_spec.rb +169 -0
- data/spec/merb/mail_controller_spec.rb +144 -0
- data/spec/merb/mailer_spec.rb +87 -0
- data/spec/merb/multipart_spec.rb +49 -0
- data/spec/merb/part_controller_spec.rb +92 -0
- data/spec/merb/plugins_spec.rb +80 -0
- data/spec/merb/render_spec.rb +378 -0
- data/spec/merb/request_spec.rb +243 -0
- data/spec/merb/responder_spec.rb +561 -0
- data/spec/merb/router_spec.rb +726 -0
- data/spec/merb/template_spec.rb +41 -0
- data/spec/merb/upload_handler_spec.rb +101 -0
- data/spec/merb/view_context_spec.rb +148 -0
- data/spec/spec_generator_helper.rb +19 -0
- data/spec/spec_helper.rb +88 -0
- metadata +203 -65
- data/lib/merb/caching/store/memcache.rb +0 -20
- data/script/destroy +0 -14
- data/script/generate +0 -14
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
|
2
|
+
|
|
3
|
+
module ResponderSpecModule
|
|
4
|
+
def new_mime(entry,index)
|
|
5
|
+
Merb::ResponderMixin::Rest::AcceptType.new(entry,index)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe "The Merb Module" do
|
|
10
|
+
|
|
11
|
+
after do
|
|
12
|
+
Merb.reset_default_mime_types!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should respond to add_mime_type" do
|
|
16
|
+
Merb.should respond_to(:add_mime_type)
|
|
17
|
+
end
|
|
18
|
+
it "should respond to remove_mime_type" do
|
|
19
|
+
Merb.should respond_to(:remove_mime_type)
|
|
20
|
+
end
|
|
21
|
+
it "should respond to available_mime_types" do
|
|
22
|
+
Merb.should respond_to(:available_mime_types)
|
|
23
|
+
end
|
|
24
|
+
it "should respond to outgoing_headers" do
|
|
25
|
+
Merb.should respond_to(:response_headers)
|
|
26
|
+
end
|
|
27
|
+
it "should respond to add_outgoing_headers!" do
|
|
28
|
+
Merb.should respond_to(:add_response_headers!)
|
|
29
|
+
end
|
|
30
|
+
it "should respond to remove_outgoing_headers!" do
|
|
31
|
+
Merb.should respond_to(:remove_response_headers!)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should give access to the available_mime_types" do
|
|
35
|
+
Merb.available_mime_types.should equal(Merb::ResponderMixin::Rest::TYPES)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should add a mime type to the TYPES array" do
|
|
39
|
+
Merb::ResponderMixin::Rest::TYPES.has_key?(:png).should be_false
|
|
40
|
+
Merb.add_mime_type(:png, :to_png, %w[image/png])
|
|
41
|
+
Merb::ResponderMixin::Rest::TYPES.has_key?(:png).should be_true
|
|
42
|
+
end
|
|
43
|
+
it "should only accept Symbols for add_mime_type's key argument" do
|
|
44
|
+
lambda{
|
|
45
|
+
Merb.add_mime_type('silly string', %w[string/silly])
|
|
46
|
+
}.should raise_error(ArgumentError)
|
|
47
|
+
end
|
|
48
|
+
it "should only accept an Array for add_mime_type's values argument" do
|
|
49
|
+
lambda{Merb.add_mime_type(:key, :to_key, 'Congos')}.should raise_error(ArgumentError)
|
|
50
|
+
end
|
|
51
|
+
it "should remove a mime type from the TYPES array" do
|
|
52
|
+
Merb.add_mime_type(:png, :to_png, %w[image/png])
|
|
53
|
+
Merb::ResponderMixin::Rest::TYPES.has_key?(:png).should be_true
|
|
54
|
+
Merb.remove_mime_type(:png)
|
|
55
|
+
Merb::ResponderMixin::Rest::TYPES.has_key?(:png).should be_false
|
|
56
|
+
end
|
|
57
|
+
it "should not allow removal of the special :all mime-type" do
|
|
58
|
+
Merb.remove_mime_type(:all).should be_false
|
|
59
|
+
Merb::ResponderMixin::Rest::TYPES.has_key?(:all).should be_true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should add a mime type with outgoing headers defined" do
|
|
63
|
+
Merb.available_mime_types.should_not have_key(:pdf)
|
|
64
|
+
Merb.response_headers.should_not have_key?(:pdf)
|
|
65
|
+
Merb.mime_transform_method(:pdf).should be_nil
|
|
66
|
+
Merb.add_mime_type(:pdf, :to_pdf, %w[application/pdf],{"Content-Encoding" => "gzip"})
|
|
67
|
+
Merb.available_mime_types.should have_key(:pdf)
|
|
68
|
+
Merb.available_mime_types[:pdf].should == %w[application/pdf]
|
|
69
|
+
Merb.response_headers.should have_key(:pdf)
|
|
70
|
+
Merb.response_headers[:pdf].should == { "Content-Encoding" => "gzip" }
|
|
71
|
+
Merb.mime_transform_method(:pdf).should == :to_pdf
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should add an outgoing header for an existing mime type" do
|
|
75
|
+
Merb.response_headers[:html].should be_empty
|
|
76
|
+
Merb.add_response_headers!(:html,{:header => "content"})
|
|
77
|
+
Merb.response_headers[:html].should == {:header => "content"}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should set the transform for the default html to nil" do
|
|
81
|
+
Merb.available_mime_types.should have_key(:html)
|
|
82
|
+
Merb.mime_transform_method(:html).should be_nil
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "should set xml to default to :Encoding => 'UTF-8'" do
|
|
87
|
+
Merb.response_headers[:xml].should == {:Encoding => "UTF-8"}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should set the xml transform method to :to_xml" do
|
|
91
|
+
Merb.mime_transform_method(:xml).should == :to_xml
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "should set the :js transform method to :to_json" do
|
|
95
|
+
Merb.mime_transform_method(:js).should == :to_json
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should replace any and all existing headers on an existing mime type" do
|
|
99
|
+
header = {:header => "content"}
|
|
100
|
+
Merb.response_headers[:xml].should_not be_empty
|
|
101
|
+
Merb.response_headers[:xml].should_not == header
|
|
102
|
+
Merb.add_response_headers!(:xml, header)
|
|
103
|
+
Merb.response_headers[:xml].should == header
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "the specs should not alter the outgoing headers between specs" do
|
|
107
|
+
Merb.response_headers[:xml].should == {:Encoding => "UTF-8"}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "should remove all existing headers for a given mime type" do
|
|
111
|
+
Merb.response_headers[:xml].should_not be_empty
|
|
112
|
+
Merb.remove_response_headers!(:xml)
|
|
113
|
+
Merb.response_headers[:xml].should be_empty
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe "A Merb Responder's AcceptType" do
|
|
118
|
+
include ResponderSpecModule
|
|
119
|
+
|
|
120
|
+
before :each do
|
|
121
|
+
@app_xhtml = new_mime('application/xhtml+xml',1)
|
|
122
|
+
@text_html = new_mime('text/html',5)
|
|
123
|
+
@app_html = new_mime('application/html;q=0.9',9)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "should initialize properly from mime description and index" do
|
|
127
|
+
acc_entry = new_mime(' application/html ; q=0.9 ',1)
|
|
128
|
+
acc_entry.media_range.should == 'application/html'
|
|
129
|
+
acc_entry.quality.should == 90
|
|
130
|
+
acc_entry.index.should == 1
|
|
131
|
+
acc_entry.synonyms.should ==
|
|
132
|
+
%w[text/html application/xhtml+xml application/html]
|
|
133
|
+
acc_entry.super_range.should == 'text/html'
|
|
134
|
+
acc_entry.to_s.should == acc_entry.media_range
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "should assign lowest quality to */* unless otherwise specified" do
|
|
138
|
+
new_mime('*/*',1).quality.should == 0
|
|
139
|
+
new_mime('*/*;q=1.0',1).quality.should == 100
|
|
140
|
+
new_mime('*/*;q=0.2',1).quality.should == 20
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "should be equal to another AcceptType in the same synonym group" do
|
|
144
|
+
@text_html.should == @app_html
|
|
145
|
+
@text_html.should eql(@app_html)
|
|
146
|
+
@text_html.hash.should == @app_html.hash
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "should share a super range with an AcceptType in the same synonym group" do
|
|
150
|
+
@text_html.synonyms.should == @app_html.synonyms
|
|
151
|
+
@text_html.super_range.should == @app_html.super_range
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it "should parse type and subtype" do
|
|
155
|
+
@app_xhtml.type.should == 'application'
|
|
156
|
+
@app_xhtml.sub_type.should == 'xhtml+xml'
|
|
157
|
+
@text_html.type.should == 'text'
|
|
158
|
+
@text_html.sub_type.should == 'html'
|
|
159
|
+
@app_html.type.should == 'application'
|
|
160
|
+
@app_html.sub_type.should == 'html'
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
describe "A Merb Responder's parsing of an Accept header" do
|
|
166
|
+
|
|
167
|
+
setup do
|
|
168
|
+
@acc_hdr = "text/xml,application/xml,application/xhtml+xml," \
|
|
169
|
+
"text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "should parse accept header string to Array of AcceptType instances" do
|
|
173
|
+
acc_hdr = Merb::ResponderMixin::Rest::Responder.parse(@acc_hdr)
|
|
174
|
+
acc_hdr.should be_kind_of(Array)
|
|
175
|
+
acc_hdr.all?{|e| e.kind_of?(Merb::ResponderMixin::Rest::AcceptType) }.should be_true
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it "should parse single entry accept headers" do
|
|
179
|
+
acc_hdr = Merb::ResponderMixin::Rest::Responder.parse('application/xml')
|
|
180
|
+
acc_hdr.should be_kind_of(Array)
|
|
181
|
+
acc_hdr.all?{|e| e.kind_of?(Merb::ResponderMixin::Rest::AcceptType) }.should be_true
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "should parse accept header into proper number of AcceptType instances" do
|
|
185
|
+
acc_hdr = 'foo/bar,baz/quuz,chimi/changa,cobra/khai'
|
|
186
|
+
acc_hdr = Merb::ResponderMixin::Rest::Responder.parse(acc_hdr)
|
|
187
|
+
acc_hdr.size.should == 4
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "should only return unique AcceptType instances" do
|
|
191
|
+
acc_hdr = 'text/html,application/xhtml+xml,application/html,text/xml,' \
|
|
192
|
+
'application/xml,application/x-xml'
|
|
193
|
+
acc_hdr = Merb::ResponderMixin::Rest::Responder.parse(acc_hdr)
|
|
194
|
+
acc_hdr.size.should == 2
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it "should sort AcceptType instances by quality" do
|
|
198
|
+
acc_hdr = 'foo/bar;q=0.1,donny/darko;q=0.9,tango/cash,water/melon;q=0.5'
|
|
199
|
+
acc_hdr = Merb::ResponderMixin::Rest::Responder.parse(acc_hdr)
|
|
200
|
+
acc_hdr.map!{|hdr| hdr.super_range }.should ==
|
|
201
|
+
%w[tango/cash donny/darko water/melon foo/bar]
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "should sort AcceptType instances by order" do
|
|
205
|
+
acc_hdr = 'foo/bar,baz/quuz,chimi/changa,cobra/khai'
|
|
206
|
+
acc_hdr = Merb::ResponderMixin::Rest::Responder.parse(acc_hdr)
|
|
207
|
+
acc_hdr.map!{|hdr| hdr.super_range }.should ==
|
|
208
|
+
%w[foo/bar baz/quuz chimi/changa cobra/khai]
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "should prefer alternate xml forms (foo+xml) over application/xml" do
|
|
212
|
+
acc_hdr = Merb::ResponderMixin::Rest::Responder.parse(@acc_hdr)
|
|
213
|
+
acc_hdr.first.super_range.should == 'text/html'
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it "should sort AcceptType instances by quality and order" do
|
|
217
|
+
acc_hdr = Merb::ResponderMixin::Rest::Responder.parse(@acc_hdr)
|
|
218
|
+
acc_hdr.map!{|hdr| hdr.super_range }.should ==
|
|
219
|
+
%w[text/html application/xml image/png text/plain */*]
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class ResponderSpecController < Merb::Controller
|
|
226
|
+
def index
|
|
227
|
+
only_provides :html, :xml, :yaml
|
|
228
|
+
content_type.to_s
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def create
|
|
232
|
+
only_provides :xml
|
|
233
|
+
render :nothing => 201
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
class CrazyResponderSpecController < Merb::Controller
|
|
238
|
+
def index
|
|
239
|
+
only_provides :donkey
|
|
240
|
+
content_type
|
|
241
|
+
"donkey"
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
Merb::Server.load_action_arguments
|
|
246
|
+
Merb::Server.load_controller_template_path_cache
|
|
247
|
+
|
|
248
|
+
describe "A Merb Responder's Content Negotiation" do
|
|
249
|
+
|
|
250
|
+
it "should set Content-Type by :format for supported type: xml" do
|
|
251
|
+
c = new_responder_spec_controller(:format => 'xml')
|
|
252
|
+
c.dispatch(:index)
|
|
253
|
+
c.status.should == 200
|
|
254
|
+
c.headers['Content-Type'].should == 'application/xml'
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it "should set Content-Type by :format for supported type: yaml" do
|
|
258
|
+
c = new_responder_spec_controller(:format => 'yaml')
|
|
259
|
+
c.dispatch(:index)
|
|
260
|
+
c.status.should == 200
|
|
261
|
+
c.headers['Content-Type'].should == 'application/x-yaml'
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
it "should set Content-Type by :format for supported type: html" do
|
|
265
|
+
c = new_responder_spec_controller(:format => 'html')
|
|
266
|
+
c.dispatch(:index)
|
|
267
|
+
c.status.should == 200
|
|
268
|
+
c.headers['Content-Type'].should == 'text/html'
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it "should set Content-Type by accept header for supported type: xml" do
|
|
272
|
+
c = new_responder_spec_controller(:http_accept => 'text/xml')
|
|
273
|
+
c.dispatch(:index)
|
|
274
|
+
c.status.should == 200
|
|
275
|
+
c.headers['Content-Type'].should == 'application/xml'
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it "should set Content-Type by accept header for supported type: yaml" do
|
|
279
|
+
c = new_responder_spec_controller(:http_accept => 'text/yaml')
|
|
280
|
+
c.dispatch(:index)
|
|
281
|
+
c.status.should == 200
|
|
282
|
+
c.headers['Content-Type'].should == 'application/x-yaml'
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it "should set Content-Type by accept header for supported type: html" do
|
|
286
|
+
c = new_responder_spec_controller(:http_accept => 'text/html')
|
|
287
|
+
c.dispatch(:index)
|
|
288
|
+
c.status.should == 200
|
|
289
|
+
c.headers['Content-Type'].should == 'text/html'
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it "should set Content-Type by :format in preference to accept headers when both are of a supported response type" do
|
|
293
|
+
c = new_responder_spec_controller(:http_accept => 'text/plain', :format => 'yaml')
|
|
294
|
+
c.dispatch(:index)
|
|
295
|
+
c.status.should == 200
|
|
296
|
+
c.headers['Content-Type'].should == 'application/x-yaml'
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
it "should set status 406 when format is of an unsupported response type" do
|
|
300
|
+
c = new_responder_spec_controller(:format => 'fromage')
|
|
301
|
+
lambda{c.dispatch(:index)}.should raise_error(Merb::ControllerExceptions::NotAcceptable)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "should set status 406 when no accept header is of a unsupported response type" do
|
|
305
|
+
c = new_responder_spec_controller(:http_accept => 'stale/crackers;q=0.7,camel/milk;q=1.0')
|
|
306
|
+
lambda{c.dispatch(:index)}.should raise_error(Merb::ControllerExceptions::NotAcceptable)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
it "should raise 406 when negotiated type is not in TYPES" do
|
|
310
|
+
r = Merb::Test::FakeRequest.new
|
|
311
|
+
c = CrazyResponderSpecController.build(r, r.body)
|
|
312
|
+
lambda{c.dispatch(:index)}.should raise_error(Merb::ControllerExceptions::NotAcceptable)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it "should call the block for the supported response type yaml" do
|
|
316
|
+
c = new_responder_spec_controller(:http_accept => 'text/yaml')
|
|
317
|
+
c.dispatch(:index)
|
|
318
|
+
c.body.should == "yaml"
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
it "should call the block for the supported response type xml" do
|
|
322
|
+
c = new_responder_spec_controller(:http_accept => 'text/xml')
|
|
323
|
+
c.dispatch(:index)
|
|
324
|
+
c.body.should == "xml"
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
it "should call the block for the supported response type html" do
|
|
328
|
+
c = new_responder_spec_controller(:http_accept => 'text/html')
|
|
329
|
+
c.dispatch(:index)
|
|
330
|
+
c.body.should == "html"
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it "should utilise format in preference to accept header" do
|
|
334
|
+
c = new_responder_spec_controller(:http_accept => 'text/html', :format => 'xml')
|
|
335
|
+
c.dispatch(:index)
|
|
336
|
+
c.status.should == 200
|
|
337
|
+
c.headers['Content-Type'].should == 'application/xml'
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it "should respond to the */* catchall accept header" do
|
|
341
|
+
c = new_responder_spec_controller(:http_accept => '*/*')
|
|
342
|
+
c.dispatch(:index)
|
|
343
|
+
c.status.should == 200
|
|
344
|
+
c.headers['Content-Type'].should == 'text/html'
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
it "should honor a return :nothing => status specified in the respond_to block" do
|
|
348
|
+
c = new_responder_spec_controller(:http_accept => 'application/xml')
|
|
349
|
+
c.dispatch(:create)
|
|
350
|
+
c.status.should == 201
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def new_responder_spec_controller(options={})
|
|
354
|
+
params = {:controller => 'ResponderSpecController', :action => 'index'}
|
|
355
|
+
params.update(:format => options.delete(:format)) if options[:format]
|
|
356
|
+
|
|
357
|
+
@request = Merb::Test::FakeRequest.new(options)
|
|
358
|
+
@request.params.merge!(params)
|
|
359
|
+
ResponderSpecController.build(@request, @request.body)
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
class SimpleResponder
|
|
364
|
+
include Merb::ResponderMixin
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
describe "Merb::ResponderMixin", "negotiating content_type" do
|
|
368
|
+
before(:each) do
|
|
369
|
+
@responder = SimpleResponder.new
|
|
370
|
+
@responder.stub!(:provided_formats).and_return([:html, :xml])
|
|
371
|
+
@responder.stub!(:params).and_return({:format => "html"})
|
|
372
|
+
@request = mock("request")
|
|
373
|
+
@request.stub!(:accept).and_return("text/html")
|
|
374
|
+
@responder.stub!(:request).and_return(@request)
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
it "should have a perform_content_negotiation" do
|
|
378
|
+
@responder.should respond_to(:perform_content_negotiation)
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
it "should use provided_formats when params[:format] is nil" do
|
|
382
|
+
@responder.stub!(:params).and_return({})
|
|
383
|
+
@responder.should_receive(:provided_formats).
|
|
384
|
+
at_least(:once).and_return([:html])
|
|
385
|
+
@responder.perform_content_negotiation
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
it "should use provided_formats when params[:format] is not nil" do
|
|
389
|
+
@responder.should_receive(:provided_formats).
|
|
390
|
+
at_least(:once).and_return([:html])
|
|
391
|
+
@responder.perform_content_negotiation
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
it "should use params[:format] when determining content_type" do
|
|
395
|
+
@responder.should_receive(:params).at_least(:once).
|
|
396
|
+
and_return({:format => "html"})
|
|
397
|
+
@responder.perform_content_negotiation
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
it "should use request.accept when params[:format] is nil" do
|
|
401
|
+
@responder.stub!(:params).and_return({})
|
|
402
|
+
@responder.should_receive(:request).once.and_return(@request)
|
|
403
|
+
@request.should_receive(:accept).once.and_return("text/html")
|
|
404
|
+
@responder.perform_content_negotiation
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
it "should not use request.accept when params[:format] is not nil" do
|
|
408
|
+
@responder.should_receive(:request).exactly(0).times
|
|
409
|
+
@responder.perform_content_negotiation
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it "should return :html when params[:format] = :html" do
|
|
413
|
+
@responder.perform_content_negotiation.should == :html
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it "should raise NotAcceptable when params[:format] = :html but :html is not provided" do
|
|
417
|
+
@responder.should_receive(:provided_formats).at_least(:once).
|
|
418
|
+
and_return([:xml])
|
|
419
|
+
lambda {@responder.perform_content_negotiation}.should raise_error(Merb::ControllerExceptions::NotAcceptable)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
it "should return :xml when it is the first provided and accepts is */*" do
|
|
423
|
+
@responder.stub!(:provided_formats).and_return([:xml, :html])
|
|
424
|
+
@responder.stub!(:params).and_return({})
|
|
425
|
+
@request.should_receive(:accept).once.and_return("*/*")
|
|
426
|
+
@responder.perform_content_negotiation.should == :xml
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
it "should return :xml when it is the first requested" do
|
|
430
|
+
@responder.stub!(:provided_formats).and_return([:html, :xml, :text])
|
|
431
|
+
@responder.stub!(:params).and_return({})
|
|
432
|
+
@request.should_receive(:accept).once.and_return("text/xml, text/html")
|
|
433
|
+
@responder.perform_content_negotiation.should == :xml
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
it "should raise NotAcceptable when accepts and provides do not intersect" do
|
|
437
|
+
@responder.stub!(:provided_formats).and_return([:html, :text])
|
|
438
|
+
@responder.stub!(:params).and_return({})
|
|
439
|
+
@request.should_receive(:accept).once.and_return("text/xml, text/json")
|
|
440
|
+
lambda {@responder.perform_content_negotiation}.should raise_error(Merb::ControllerExceptions::NotAcceptable)
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
it "should short circuit and raise NotAcceptable when provided_formats is empty" do
|
|
444
|
+
@responder.stub!(:provided_formats).and_return([])
|
|
445
|
+
@responder.should_receive(:params).exactly(0).times
|
|
446
|
+
@responder.should_receive(:request).exactly(0).times
|
|
447
|
+
lambda {@responder.perform_content_negotiation}.should raise_error(Merb::ControllerExceptions::NotAcceptable)
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
class DoubleProvides < Merb::Controller
|
|
452
|
+
def double_provides ; provides :xml; @_content_type = :html ; provides :txt ; end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
describe "Merb::ResponderMixin", "dealing with content_type variable" do
|
|
456
|
+
it "should raise an error if provides is called after content_type has been determined" do
|
|
457
|
+
c = new_controller("double_provides",DoubleProvides)
|
|
458
|
+
lambda { c.double_provides }.should raise_error
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
it "should return false for content_type_set? when @_content_type is nil" do
|
|
462
|
+
c = new_controller("double_provides",DoubleProvides)
|
|
463
|
+
c.should_not be_content_type_set
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
it "should return true for content_type_set? when @_content_type is not nil" do
|
|
467
|
+
c = new_controller("double_provides",DoubleProvides)
|
|
468
|
+
c.instance_variable_set("@_content_type",:html)
|
|
469
|
+
c.should be_content_type_set
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
it "should return @_content_type when content_type is called" do
|
|
473
|
+
c = new_controller("double_provides",DoubleProvides)
|
|
474
|
+
c.instance_variable_set("@_content_type",:html)
|
|
475
|
+
c.content_type.should == :html
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
it "should allow content_type to be set directly" do
|
|
479
|
+
c = new_controller()
|
|
480
|
+
c.content_type=:txt
|
|
481
|
+
c.content_type.should == :txt
|
|
482
|
+
end
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
class FormattedBasic < Merb::Controller ; end
|
|
486
|
+
class WithXml < Merb::Controller ; provides :xml ; end
|
|
487
|
+
class XmlOnly < Merb::Controller ; only_provides :xml ; end
|
|
488
|
+
class ProvidesNothing < Merb::Controller ; does_not_provide :html ; end
|
|
489
|
+
class HtmlAgain < Merb::Controller ; provides :html ; end
|
|
490
|
+
|
|
491
|
+
class ManyProvides < Merb::Controller
|
|
492
|
+
provides :html, :xml, :txt
|
|
493
|
+
def noextra ; end
|
|
494
|
+
def extra ; provides :json, :yaml ; end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
describe "Responder", "managing provided formats (class)" do
|
|
498
|
+
it "should have the default class_provided_formats of [:html]" do
|
|
499
|
+
c = new_controller("index",FormattedBasic)
|
|
500
|
+
c.class_provided_formats.should == [:html]
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
it "should add :xml to class_provided_formats when called with provides :xml" do
|
|
504
|
+
c = new_controller("index",WithXml)
|
|
505
|
+
c.class_provided_formats.should == [:html, :xml]
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
it "should only have :xml in class_provided_formats when called with only_provides :xml" do
|
|
509
|
+
c = new_controller("index",XmlOnly)
|
|
510
|
+
c.class_provided_formats.should == [:xml]
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
it "should have an empty class_provided_formats when called with does_not_provide :html" do
|
|
514
|
+
c = new_controller("index",ProvidesNothing)
|
|
515
|
+
c.class_provided_formats.should == []
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
it "should only have :html in class_provided_formats when called with provides :html (after other controllers have set it)" do
|
|
519
|
+
c = new_controller("index",HtmlAgain)
|
|
520
|
+
c.class_provided_formats.should == [:html]
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
it "should handle multiple provides added via class method" do
|
|
524
|
+
c = new_controller("noextra",ManyProvides)
|
|
525
|
+
c.provided_formats.should == [:html, :xml, :txt]
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
class ActionProvides < Merb::Controller
|
|
530
|
+
def basic ; end
|
|
531
|
+
def with_xml ; provides :xml ; end
|
|
532
|
+
def xml_only ; only_provides :xml ; end
|
|
533
|
+
def nothing ; does_not_provide :html ; end
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
describe "Responder", "managing provided formats (action)" do
|
|
537
|
+
it "should have the default provided_formats" do
|
|
538
|
+
c = new_controller("basic",ActionProvides)
|
|
539
|
+
c.basic
|
|
540
|
+
c.provided_formats.should == [:html]
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
it "should add :xml to provided_formats when called with provides :xml" do
|
|
544
|
+
c = new_controller("with_xml",ActionProvides)
|
|
545
|
+
c.with_xml
|
|
546
|
+
c.provided_formats.should == [:html, :xml]
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
it "should only have :xml in provided_formats when called with only_provides :xml" do
|
|
550
|
+
c = new_controller("xml_only",ActionProvides)
|
|
551
|
+
c.xml_only
|
|
552
|
+
c.provided_formats.should == [:xml]
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
it "should have an empty provided_formats when called with does_not_provide :html" do
|
|
556
|
+
c = new_controller("nothing",ActionProvides)
|
|
557
|
+
c.nothing
|
|
558
|
+
c.provided_formats.should be_empty
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
|