sinatra-respond_to 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog.rdoc ADDED
@@ -0,0 +1,62 @@
1
+ === 0.3.8 / 2010-01-30
2
+
3
+ * Need to bump because of wrong gem name
4
+ * Fix some issues in the README
5
+
6
+ === 0.3.7 / 2010-01-30
7
+
8
+ * Update builder template for how sinatra handles this now
9
+ * Update spec tests for 1.9
10
+ * Update XMLHttpResponse test for new rack-test
11
+ * Regenerated gemspec for version 0.3.6
12
+
13
+ === 0.3.6 / 2009-07-31
14
+
15
+ * Version bump to 0.3.6
16
+ * solving incompatibility between 1.9 to fully qualify TEXT_MIME_TYPES check
17
+
18
+ === 0.3.5 / 2009-05-14
19
+
20
+ * Regenerated gemspec for version 0.3.5
21
+ * Version bump to 0.3.5
22
+ * better testing of environment expectations, workarounds for sinatra environment switching
23
+ * problem in spec, wasn't checking for right thing
24
+ * spec for reaching the /__sinatra__/*.png images
25
+ * couple more tests for charset and format helpers
26
+ * reduce regex use and simplify others
27
+ * some more code cleaning
28
+ * simplification and readability
29
+ * add some more specification for respond_to
30
+
31
+ === 0.3.4 / 2009-05-13
32
+
33
+ * updated gemspec
34
+ * Version bump to 0.3.4
35
+ * updated readme
36
+ * passing code for tests
37
+ * tests and tests
38
+ * typo in readme
39
+ * allow for content_type setting automatically when not using respond_to
40
+ * make it a bit clearer in readme that outside of respond_to content_type is not set
41
+ * bumped gem version in gemspec
42
+ * noted the change in classic applications, the gem now works around this but not following extension writing guidelines
43
+
44
+ === 0.3.3 / 2009-05-12
45
+
46
+ * Version bump to 0.3.3
47
+ * Version bump to 0.3.2
48
+ * spec referenced file not in repository
49
+
50
+ === 0.3.1 / 2009-05-11
51
+
52
+ * Version bump to 0.3.1
53
+ * add sinatra as a dependency
54
+ * allow overriding default charset in respond_to
55
+ * install instructions
56
+ * first gem
57
+ * Version bump to 0.0.0
58
+ * missing end in example
59
+ * add caveats about existing routes
60
+ * fix a little error in example
61
+ * updated readme and license
62
+
data/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ Changelog.rdoc
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ lib/sinatra/respond_to.rb
6
+ lib/sinatra/respond_to/version.rb
7
+ spec/spec_helper.rb
8
+ spec/extension_spec.rb
9
+ spec/app/production_error_app.rb
10
+ spec/app/test_app.rb
11
+ spec/app/unreachable_static.txt
12
+ spec/app/public/static.txt
13
+ spec/app/public/static folder/.keep
14
+ spec/app/views/layout.html.haml
15
+ spec/app/views/resource.html.haml
16
+ spec/app/views/resource.js.erb
17
+ spec/app/views/resource.xml.builder
data/README.rdoc ADDED
@@ -0,0 +1,151 @@
1
+ = sinatra-respond_to
2
+
3
+ * http://www.github.com/cehoffman/sinatra-respond_to
4
+
5
+ == DESCRIPTION:
6
+
7
+ A respond_to style Rails block for baked-in web service support in Sinatra
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * Handles setting charset for appropriate types
12
+ * Handles setting the content type depending on what is being served
13
+ * Automatically can adjust XMLHttpRequests to return Javascript
14
+
15
+ == SYNOPSIS:
16
+
17
+ require 'sinatra'
18
+ require 'sinatra/respond_to'
19
+
20
+ get '/posts' do
21
+ @posts = Post.recent
22
+
23
+ respond_to do |wants|
24
+ wants.html { haml :posts } # => views/posts.html.haml, also sets content_type to text/html
25
+ wants.rss { haml :posts } # => views/posts.rss.haml, also sets content_type to application/rss+xml
26
+ wants.atom { haml :posts } # => views/posts.atom.haml, also sets content_type to appliation/atom+xml
27
+ end
28
+ end
29
+
30
+ get '/post/:id' do
31
+ @post = Post.find(params[:id])
32
+
33
+ respond_to do |wants|
34
+ wants.html { haml :post } # => views/post.html.haml, also sets content_type to text/html
35
+ wants.xhtml { haml :post } # => views/post.xhtml.haml, also sets content_type to application/xhtml+xml
36
+ wants.xml { @post.to_xml } # => sets content_type to application/xml
37
+ wants.js { erb :post } # => views/post.js.erb, also sets content_type to application/javascript
38
+ end
39
+ end
40
+
41
+ get '/comments/:id' do
42
+ @comment = Comment.find(params[:id])
43
+
44
+ respond_to do |wants|
45
+ wants.html { haml :comment } # => views/comment.html.haml, also sets content_type to text/html
46
+ wants.json { @comment.to_json } # => sets content_type to application/json
47
+ wants.js { erb :comment } # => views/comment.js.erb, also sets content_type to application/javascript
48
+ end
49
+ end
50
+
51
+ To change the character set of the response, there is a <tt>charset</tt> helper. For example
52
+
53
+ get '/iso-8859-1' do
54
+ charset 'iso-8859-1'
55
+ "This is now sent using iso-8859-1 character set"
56
+ end
57
+
58
+ get '/respond_to-mixed' do
59
+ respond_to do |wants|
60
+ wants.html { charset 'iso-8859-1'; "Some html in iso-8859-1" }
61
+ wants.xml { builder :utf-8-xml } # => this is returned in the default character set
62
+ end
63
+ end
64
+
65
+ == CONFIGURATION:
66
+
67
+ There a few options available for configuring the default behavior of respond_to using Sinatra's
68
+ <tt>set</tt> utility.
69
+
70
+ * <tt>default\_charset - utf-8</tt>
71
+ Assumes all text documents are encoded using this character set.
72
+ This can be overridden within the respond_to block for the appropriate format
73
+ * <tt>default\_content - :html</tt>
74
+ When a user vists a url without an extension, for example /post this will be
75
+ the assumed content to serve first. Expects a symbol as used in setting content_type.
76
+ * <tt>assume\_xhr\_is\_js - true</tt>
77
+ To avoid headaches with accept headers, and appending .js to urls, this will
78
+ cause the default format for all XmlHttpRequests to be classified as wanting Javascript
79
+ in the response.
80
+
81
+ == REQUIREMENTS:
82
+
83
+ * sinatra 0.9.4 - 0.10
84
+
85
+ == INSTALL:
86
+
87
+ * gem install sinatra-respond_to
88
+
89
+ == CAVEATS:
90
+ Due to the way respond\_to works, all incoming requests have the extension striped from the request.path\_info.
91
+ This causes routes like the following to fail.
92
+
93
+ get '/style.css' do
94
+ content_type :css, :charset => 'utf-8'
95
+ sass :style # => renders views/style.sass
96
+ end
97
+
98
+ They need to be changed to the following. Note that you no longer have to set the content\_type or charset.
99
+
100
+ get '/style' do
101
+ sass :style # => renders views/style.css.sass
102
+ end
103
+
104
+ If you want to ensure the route only gets called for css requests try this. This will use sinatra's built in accept header matching.
105
+
106
+ get '/style', :provides => :css do
107
+ sass :style
108
+ end
109
+
110
+ == DEVELOPERS:
111
+
112
+ After checking out the source, run:
113
+
114
+ $ rake newb
115
+
116
+ This task will install any missing dependencies, run the tests/specs,
117
+ and generate the RDoc.
118
+
119
+ == ISSUES
120
+
121
+ Sinatra has a bug that affects Classic style applications and extensions see 215[https://sinatra.lighthouseapp.com/projects/9779/tickets/215-extensions-cannot-define-before-filters-for-classic-apps] and 180[https://sinatra.lighthouseapp.com/projects/9779/tickets/180-better-route-inheritence].
122
+ I have worked around this by explicitly registering RespondTo with the top level Sinatra::Application when
123
+ requiring sinatra/respond\_to.
124
+
125
+ * {Extensions cannot define before filters for classic apps}[https://sinatra.lighthouseapp.com/projects/9779/tickets/215-extensions-cannot-define-before-filters-for-classic-apps]
126
+ * {Better route inheritence}[https://sinatra.lighthouseapp.com/projects/9779/tickets/180-better-route-inheritence]
127
+
128
+ == LICENSE:
129
+
130
+ (The MIT License)
131
+
132
+ Copyright (c) 2009-2010 Chris Hoffman
133
+
134
+ Permission is hereby granted, free of charge, to any person obtaining
135
+ a copy of this software and associated documentation files (the
136
+ 'Software'), to deal in the Software without restriction, including
137
+ without limitation the rights to use, copy, modify, merge, publish,
138
+ distribute, sublicense, and/or sell copies of the Software, and to
139
+ permit persons to whom the Software is furnished to do so, subject to
140
+ the following conditions:
141
+
142
+ The above copyright notice and this permission notice shall be
143
+ included in all copies or substantial portions of the Software.
144
+
145
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
146
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
147
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
148
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
149
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
150
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
151
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require File.expand_path(File.join('.', 'lib', 'sinatra', 'respond_to', 'version'))
6
+
7
+ Hoe.plugin :gemcutter
8
+ Hoe.plugin :clean
9
+ Hoe.plugin :git
10
+
11
+ Hoe.spec 'sinatra-respond_to' do
12
+ developer('Chris Hoffman', 'cehoffman@gmail.com')
13
+ extra_deps << ['sinatra', '>= 0.9.4']
14
+ extra_dev_deps << ['hoe', '>= 2.5.0']
15
+ extra_dev_deps << ['rspec', '>= 1.3.0']
16
+ extra_dev_deps << ['rcov', '>= 0.9.7.1']
17
+ extra_dev_deps << ['rack-test', '>= 0.5.3']
18
+ extra_dev_deps << ['haml', ">= 2.0"]
19
+ extra_dev_deps << ['builder', '>= 2.0']
20
+ self.readme_file = 'README.rdoc'
21
+ self.history_file = 'Changelog.rdoc'
22
+ self.test_globs = 'spec/*_spec.rb'
23
+ self.version = ::Sinatra::RespondTo::Version
24
+ end
25
+
26
+ begin
27
+ require 'spec/rake/spectask'
28
+ desc "Run specs"
29
+ Spec::Rake::SpecTask.new do |t|
30
+ t.spec_files = FileList['spec/*_spec.rb']
31
+ t.spec_opts = %w(-fp --color)
32
+
33
+ t.rcov = true
34
+ t.rcov_opts << '--text-summary'
35
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
36
+ t.rcov_opts << '--exclude' << 'pkg,spec'
37
+ end
38
+ rescue LoadError
39
+ puts "RSpec not available. Install it with sudo gem install rspec."
40
+ end
41
+
42
+ # vim: syntax=ruby
@@ -0,0 +1,206 @@
1
+ require 'sinatra/base'
2
+
3
+ # Accept header parsing was looked at but deemed
4
+ # too much of an irregularity to deal with. Problems with the header
5
+ # differences from IE, Firefox, Safari, and every other UA causes
6
+ # problems with the expected output. The general expected behavior
7
+ # would be serve html when no extension provided, but most UAs say
8
+ # they will accept application/xml with out a quality indicator, meaning
9
+ # you'd get the xml block served insead. Just plain retarded, use the
10
+ # extension and you'll never be suprised.
11
+
12
+ module Sinatra
13
+ module RespondTo
14
+ class UnhandledFormat < Sinatra::NotFound; end
15
+ class MissingTemplate < Sinatra::NotFound
16
+ def code; 500 end
17
+ end
18
+
19
+ TEXT_MIME_TYPES = [:txt, :html, :js, :json, :xml, :rss, :atom, :css, :asm, :c, :cc, :conf,
20
+ :csv, :cxx, :diff, :dtd, :f, :f77, :f90, :for, :gemspec, :h, :hh, :htm,
21
+ :log, :mathml, :mml, :p, :pas, :pl, :pm, :py, :rake, :rb, :rdf, :rtf, :ru,
22
+ :s, :sgm, :sgml, :sh, :svg, :svgz, :text, :wsdl, :xhtml, :xsl, :xslt, :yaml,
23
+ :yml, :ics]
24
+
25
+ def self.registered(app)
26
+ app.helpers RespondTo::Helpers
27
+
28
+ app.set :default_charset, 'utf-8'
29
+ app.set :default_content, :html
30
+ app.set :assume_xhr_is_js, true
31
+
32
+ # We remove the trailing extension so routes
33
+ # don't have to be of the style
34
+ #
35
+ # get '/resouce.:format'
36
+ #
37
+ # They can instead be of the style
38
+ #
39
+ # get '/resource'
40
+ #
41
+ # and the format will automatically be available in <tt>format</tt>
42
+ app.before do
43
+ unless options.static? && options.public? && (request.get? || request.head?) && static_file?(request.path_info)
44
+ request.path_info.sub! %r{\.([^\./]+)$}, ''
45
+
46
+ format request.xhr? && options.assume_xhr_is_js? ? :js : $1 || options.default_content
47
+
48
+ charset options.default_charset if Sinatra::RespondTo::TEXT_MIME_TYPES.include? format
49
+ end
50
+ end
51
+
52
+ app.configure :development do |dev|
53
+ # Very, very, very hackish but only for development at least
54
+ # Modifies the regex matching /__sinatra__/:image.png to not have the extension
55
+ ["GET", "HEAD"].each do |verb|
56
+ dev.routes[verb][1][0] = Regexp.new(dev.routes[verb][1][0].source.gsub(/\\\.[^\.\/]+\$$/, '$'))
57
+ end
58
+
59
+ dev.error UnhandledFormat do
60
+ content_type :html, :charset => 'utf-8'
61
+
62
+ (<<-HTML).gsub(/^ {10}/, '')
63
+ <!DOCTYPE html>
64
+ <html>
65
+ <head>
66
+ <style type="text/css">
67
+ body { text-align:center;font-family:helvetica,arial;font-size:22px;
68
+ color:#888;margin:20px}
69
+ #c {margin:0 auto;width:500px;text-align:left}
70
+ </style>
71
+ </head>
72
+ <body>
73
+ <h2>Sinatra doesn't know this ditty.</h2>
74
+ <img src='/__sinatra__/404.png'>
75
+ <div id="c">
76
+ Try this:
77
+ <pre>#{request.request_method.downcase} '#{request.path_info}' do\n respond_to do |wants|\n wants.#{format} { "Hello World" }\n end\nend</pre>
78
+ </div>
79
+ </body>
80
+ </html>
81
+ HTML
82
+ end
83
+
84
+ dev.error MissingTemplate do
85
+ content_type :html, :charset => 'utf-8'
86
+ response.status = request.env['sinatra.error'].code
87
+
88
+ engine = request.env['sinatra.error'].message.split('.').last
89
+ engine = 'haml' unless ['haml', 'builder', 'erb'].include? engine
90
+
91
+ path = File.basename(request.path_info)
92
+ path = "root" if path.nil? || path.empty?
93
+
94
+ format = engine == 'builder' ? 'xml' : 'html'
95
+
96
+ layout = case engine
97
+ when 'haml' then "!!!\n%html\n %body= yield"
98
+ when 'erb' then "<html>\n <body>\n <%= yield %>\n </body>\n</html>"
99
+ when 'builder' then "builder do |xml|\n xml << yield\nend"
100
+ end
101
+
102
+ layout = "<small>app.#{format}.#{engine}</small>\n<pre>#{escape_html(layout)}</pre>"
103
+
104
+ (<<-HTML).gsub(/^ {10}/, '')
105
+ <!DOCTYPE html>
106
+ <html>
107
+ <head>
108
+ <style type="text/css">
109
+ body { text-align:center;font-family:helvetica,arial;font-size:22px;
110
+ color:#888;margin:20px}
111
+ #c {margin:0 auto;width:500px;text-align:left;}
112
+ small {float:right;clear:both;}
113
+ pre {clear:both;}
114
+ </style>
115
+ </head>
116
+ <body>
117
+ <h2>Sinatra can't find #{request.env['sinatra.error'].message}</h2>
118
+ <img src='/__sinatra__/500.png'>
119
+ <div id="c">
120
+ Try this:<br />
121
+ #{layout}
122
+ <small>#{path}.#{format}.#{engine}</small>
123
+ <pre>Hello World!</pre>
124
+ <small>application.rb</small>
125
+ <pre>#{request.request_method.downcase} '#{request.path_info}' do\n respond_to do |wants|\n wants.#{engine == 'builder' ? 'xml' : 'html'} { #{engine} :#{path}#{",\n#{' '*32}layout => :app" if layout} }\n end\nend</pre>
126
+ </div>
127
+ </body>
128
+ </html>
129
+ HTML
130
+ end
131
+
132
+ end
133
+
134
+ app.class_eval do
135
+ private
136
+ def render_with_format(*args)
137
+ args[1] = "#{args[1]}.#{format}".to_sym if args[1].is_a?(::Symbol)
138
+ render_without_format *args
139
+ rescue Errno::ENOENT
140
+ raise MissingTemplate, "#{args[1]}.#{args[0]}"
141
+ end
142
+ alias_method :render_without_format, :render
143
+ alias_method :render, :render_with_format
144
+
145
+ def lookup_layout_with_format(*args)
146
+ args[1] = "#{args[1]}.#{format}".to_sym if args[1].is_a?(::Symbol)
147
+ lookup_layout_without_format *args
148
+ end
149
+ alias_method :lookup_layout_without_format, :lookup_layout
150
+ alias_method :lookup_layout, :lookup_layout_with_format
151
+ end
152
+ end
153
+
154
+ module Helpers
155
+ def format(val=nil)
156
+ unless val.nil?
157
+ mime_type = media_type(val)
158
+ fail "Unknown media type #{val}\nTry registering the extension with a mime type" if mime_type.nil?
159
+
160
+ @format = val.to_sym
161
+ response['Content-Type'].sub!(/^[^;]+/, mime_type)
162
+ end
163
+
164
+ @format
165
+ end
166
+
167
+ # This is mostly just a helper so request.path_info isn't changed when
168
+ # serving files from the public directory
169
+ def static_file?(path)
170
+ public_dir = File.expand_path(options.public)
171
+ path = File.expand_path(File.join(public_dir, unescape(path)))
172
+
173
+ path[0, public_dir.length] == public_dir && File.file?(path)
174
+ end
175
+
176
+ def charset(val=nil)
177
+ fail "Content-Type must be set in order to specify a charset" if response['Content-Type'].nil?
178
+
179
+ if response['Content-Type'] =~ /charset=[^;]+/
180
+ response['Content-Type'].sub!(/charset=[^;]+/, (val == '' && '') || "charset=#{val}")
181
+ else
182
+ response['Content-Type'] += ";charset=#{val}"
183
+ end unless val.nil?
184
+
185
+ response['Content-Type'][/charset=([^;]+)/, 1]
186
+ end
187
+
188
+ def respond_to(&block)
189
+ wants = {}
190
+ def wants.method_missing(type, *args, &handler)
191
+ Sinatra::Base.send(:fail, "Unknown media type for respond_to: #{type}\nTry registering the extension with a mime type") if Sinatra::Base.media_type(type).nil?
192
+ self[type] = handler
193
+ end
194
+
195
+ yield wants
196
+
197
+ raise UnhandledFormat if wants[format].nil?
198
+ wants[format].call
199
+ end
200
+ end
201
+ end
202
+
203
+ # Get around before filter problem for classic applications by registering
204
+ # with the context they are run in explicitly instead of Sinatra::Default
205
+ Sinatra::Application.register RespondTo
206
+ end
@@ -0,0 +1,5 @@
1
+ module Sinatra
2
+ module RespondTo
3
+ Version = '0.3.8'
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ class ProductionErrorApp < Sinatra::Base
2
+ set :environment, :production
3
+ register Sinatra::RespondTo
4
+ get '/missing-template' do
5
+ respond_to do |wants|
6
+ wants.html { haml :missing }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ A static file
@@ -0,0 +1,53 @@
1
+ require 'sinatra/base'
2
+ require 'erb'
3
+ require 'haml'
4
+ require 'builder'
5
+
6
+ class TestApp < Sinatra::Base
7
+ register Sinatra::RespondTo
8
+
9
+ set :views, File.join(File.dirname(__FILE__), 'views')
10
+ set :public, File.join(File.dirname(__FILE__), 'public')
11
+
12
+ get '/resource' do
13
+ respond_to do |wants|
14
+ wants.html { haml :resource }
15
+ wants.json { "We got some json" }
16
+ wants.xml { builder :resource }
17
+ wants.js { erb :resource }
18
+ wants.png { }
19
+ end
20
+ end
21
+
22
+ get '/default_charset' do
23
+ respond_to do |wants|
24
+ wants.html { "Should set charcter set to default_charset" }
25
+ end
26
+ end
27
+
28
+ get '/iso-8859-1' do
29
+ respond_to do |wants|
30
+ wants.html { charset 'iso-8859-1'; "Should have character set of iso-8859-1" }
31
+ end
32
+ end
33
+
34
+ get '/normal-no-respond_to' do
35
+ "Just some plain old text"
36
+ end
37
+
38
+ get '/style.css' do
39
+ "This route should fail"
40
+ end
41
+
42
+ get '/style-no-extension', :provides => :css do
43
+ "Should succeed only when browser accepts text/css"
44
+ end
45
+
46
+ get '/missing-template' do
47
+ respond_to do |wants|
48
+ wants.html { haml :missing }
49
+ wants.xml { builder :missing }
50
+ wants.js { erb :missing }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1 @@
1
+ Unreachable static file
@@ -0,0 +1,2 @@
1
+ %html
2
+ %body= yield
@@ -0,0 +1 @@
1
+ Hello from HTML
@@ -0,0 +1,3 @@
1
+ $(function () {
2
+ return '<%= "Hiya from javascript" %>'
3
+ });
@@ -0,0 +1 @@
1
+ xml.root "Some XML"
@@ -0,0 +1,393 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Sinatra::RespondTo do
4
+ def media_type(sym)
5
+ Sinatra::Base.media_type(sym)
6
+ end
7
+
8
+ describe "options" do
9
+ it "should initialize with :default_charset set to 'utf-8'" do
10
+ TestApp.default_charset.should == 'utf-8'
11
+ end
12
+
13
+ it "should initialize with :default_content set to :html" do
14
+ TestApp.default_content.should == :html
15
+ end
16
+
17
+ it "should initialize with :assume_xhr_is_js set to true" do
18
+ TestApp.assume_xhr_is_js == true
19
+ end
20
+ end
21
+
22
+ describe "assume_xhr_is_js" do
23
+ it "should set the content type to application/javascript for an XMLHttpRequest" do
24
+ header 'X_REQUESTED_WITH', 'XMLHttpRequest'
25
+
26
+ get '/resource'
27
+
28
+ last_response['Content-Type'].should =~ %r{#{media_type(:js)}}
29
+ end
30
+
31
+ it "should not set the content type to application/javascript for an XMLHttpRequest when assume_xhr_is_js is false" do
32
+ TestApp.disable :assume_xhr_is_js
33
+ header 'X_REQUESTED_WITH', 'XMLHttpRequest'
34
+ get '/resource'
35
+
36
+ last_response['Content-Type'].should_not =~ %r{#{media_type(:js)}}
37
+
38
+ # Put back the option, no side effects here
39
+ TestApp.enable :assume_xhr_is_js
40
+ end
41
+ end
42
+
43
+ describe "extension routing" do
44
+ it "breaks routes expecting an extension" do
45
+ # In test_app.rb the route is defined as get '/style.css' instead of get '/style'
46
+ get "/style.css"
47
+
48
+ last_response.should_not be_ok
49
+ end
50
+
51
+ it "should pick the default content option for routes with out an extension, and render haml templates" do
52
+ get "/resource"
53
+
54
+ last_response.body.should =~ %r{\s*<html>\s*<body>Hello from HTML</body>\s*</html>\s*}
55
+ end
56
+
57
+ it "should render for a template using builder" do
58
+ get "/resource.xml"
59
+
60
+ last_response.body.should =~ %r{\s*<root>Some XML</root>\s*}
61
+ end
62
+
63
+ it "should render for a template using erb" do
64
+ get "/resource.js"
65
+
66
+ last_response.body.should =~ %r{'Hiya from javascript'}
67
+ end
68
+
69
+ it "should return string literals in block" do
70
+ get "/resource.json"
71
+
72
+ last_response.body.should =~ %r{We got some json}
73
+ end
74
+
75
+ # This will fail if the above is failing
76
+ it "should set the appropriate content-type for route with an extension" do
77
+ get "/resource.xml"
78
+
79
+ last_response['Content-Type'].should =~ %r{#{media_type(:xml)}}
80
+ end
81
+
82
+ it "should set the character set to the default character set" do
83
+ get "/default_charset"
84
+
85
+ last_response['Content-Type'].should =~ %r{charset=#{TestApp.default_charset}}
86
+ end
87
+
88
+ it "should honor a change in character set in block" do
89
+ get "/iso-8859-1"
90
+
91
+ last_response['Content-Type'].should =~ %r{charset=iso-8859-1}
92
+ end
93
+
94
+ it "should not set the character set when requesting a non text resource" do
95
+ get "/resource.png"
96
+
97
+ last_response['Content-Type'].should_not =~ /charset/
98
+ end
99
+
100
+ it "should return not found when path does not exist" do
101
+ get "/nonexistant-path.txt"
102
+
103
+ last_response.status.should == 404
104
+ end
105
+
106
+ describe "for static files" do
107
+ before(:all) do
108
+ TestApp.enable :static
109
+ end
110
+
111
+ after(:all) do
112
+ TestApp.disable :static
113
+ end
114
+
115
+ it "should allow serving static files from public directory" do
116
+ get '/static.txt'
117
+
118
+ last_response.body.should == "A static file"
119
+ end
120
+
121
+ it "should only serve files when static routing is enabled" do
122
+ TestApp.disable :static
123
+ get '/static.txt'
124
+
125
+ last_response.should_not be_ok
126
+ last_response.body.should_not == "A static file"
127
+
128
+ TestApp.enable :static
129
+ end
130
+
131
+ it "should not allow serving static files from outside the public directory" do
132
+ get '/../unreachable_static.txt'
133
+
134
+ last_response.should_not be_ok
135
+ last_response.body.should_not == "Unreachable static file"
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "routes not using respond_to" do
141
+ it "should set the default content type when no extension" do
142
+ get "/normal-no-respond_to"
143
+
144
+ last_response['Content-Type'].should =~ %r{#{media_type(TestApp.default_content)}}
145
+ end
146
+
147
+ it "should set the default character when no extension" do
148
+ get "/normal-no-respond_to"
149
+
150
+ last_response['Content-Type'].should =~ %r{charset=#{TestApp.default_charset}}
151
+ end
152
+
153
+ it "should set the appropriate content type when given an extension" do
154
+ get "/normal-no-respond_to.css"
155
+
156
+ last_response['Content-Type'].should =~ %r{#{media_type(:css)}}
157
+ end
158
+
159
+ it "should set the default charset when given an extension" do
160
+ get "/normal-no-respond_to.css"
161
+
162
+ last_response['Content-Type'].should =~ %r{charset=#{TestApp.default_charset}}
163
+ end
164
+ end
165
+
166
+ describe "error pages in production" do
167
+ before(:each) do
168
+ @app = Rack::Builder.new { run ::ProductionErrorApp }
169
+ end
170
+
171
+ describe Sinatra::RespondTo::MissingTemplate do
172
+ it "should return 404 status when looking for a missing template in production" do
173
+ get '/missing-template'
174
+
175
+ last_response.status.should == 404
176
+ last_response.body.should_not =~ /Sinatra can't find/
177
+ end
178
+ end
179
+
180
+ describe Sinatra::RespondTo::UnhandledFormat do
181
+ it "should return with a 404 when an extension is not supported in production" do
182
+ get '/missing-template.txt'
183
+
184
+ last_response.status.should == 404
185
+ last_response.body.should_not =~ /respond_to/
186
+ end
187
+ end
188
+ end
189
+
190
+ describe "error pages in development:" do
191
+
192
+ it "should allow access to the /__sinatra__/*.png images" do
193
+ get '/__sinatra__/404.png'
194
+
195
+ last_response.should be_ok
196
+ end
197
+
198
+ describe Sinatra::RespondTo::MissingTemplate do
199
+ it "should return 500 status when looking for a missing template" do
200
+ get '/missing-template'
201
+
202
+ last_response.status.should == 500
203
+ end
204
+
205
+ it "should provide a helpful error message for a missing template when in development" do
206
+ get '/missing-template'
207
+
208
+ last_response.body.should =~ /missing\.html\.haml/
209
+ end
210
+
211
+ it "should show the /__sinatra__/500.png" do
212
+ get '/missing-template'
213
+
214
+ last_response.body.should =~ %r{src='/__sinatra__/500.png'}
215
+ end
216
+
217
+ it "should provide a contextual code example for the template engine" do
218
+ # Haml
219
+ get '/missing-template'
220
+
221
+ last_response.body.should =~ %r{app.html.haml}
222
+ last_response.body.should =~ %r{missing-template.html.haml}
223
+ last_response.body.should =~ %r{get '/missing-template' do respond_to do |wants| wants.html \{ haml :missing-template, layout => :app \} end end}
224
+
225
+ # ERB
226
+ get '/missing-template.js'
227
+
228
+ last_response.body.should =~ %r{app.html.erb}
229
+ last_response.body.should =~ %r{missing-template.html.erb}
230
+ last_response.body.should =~ %r{get '/missing-template' do respond_to do |wants| wants.html \{ erb :missing-template, layout => :app \} end end}
231
+
232
+ # Builder
233
+ get '/missing-template.xml'
234
+
235
+ last_response.body.should =~ %r{app.xml.builder}
236
+ last_response.body.should =~ %r{missing-template.xml.builder}
237
+ last_response.body.should =~ %r{get '/missing-template' do respond_to do |wants| wants.xml \{ builder :missing-template, layout => :app \} end end}
238
+ end
239
+ end
240
+
241
+ describe Sinatra::RespondTo::UnhandledFormat do
242
+ it "should return with a 404 when an extension is not supported" do
243
+ get '/missing-template.txt'
244
+
245
+ last_response.status.should == 404
246
+ end
247
+
248
+ it "should provide a helpful error message for an unhandled format" do
249
+ get '/missing-template.txt'
250
+
251
+ last_response.body.should =~ %r{get '/missing-template' do respond_to do |wants| wants.txt \{ "Hello World" \} end end}
252
+ end
253
+
254
+ it "should show the /__sinatra__/404.png" do
255
+ get '/missing-template.txt'
256
+
257
+ last_response.body.should =~ %r{src='/__sinatra__/404.png'}
258
+ end
259
+ end
260
+ end
261
+
262
+ describe "helpers:" do
263
+ include Sinatra::RespondTo::Helpers
264
+
265
+ before(:each) do
266
+ stub!(:response).and_return({'Content-Type' => 'text/html'})
267
+ end
268
+
269
+ describe "charset" do
270
+ it "should set the working charset when called with a non blank string" do
271
+ response['Content-Type'].should_not =~ /charset/
272
+
273
+ charset 'utf-8'
274
+
275
+ response['Content-Type'].split(';').should include("charset=utf-8")
276
+ end
277
+
278
+ it "should remove the charset when called with a blank string" do
279
+ charset 'utf-8'
280
+ charset ''
281
+
282
+ response['Content-Type'].should_not =~ /charset/
283
+ end
284
+
285
+ it "should return the current charset when called with nothing" do
286
+ charset 'utf-8'
287
+
288
+ charset.should == 'utf-8'
289
+ end
290
+
291
+ it "should fail when the response does not have a Content-Type" do
292
+ response.delete('Content-Type')
293
+
294
+ lambda { charset }.should raise_error
295
+ end
296
+
297
+ it "should not modify the Content-Type when given no argument" do
298
+ response['Content-Type'] = "text/html;charset=iso-8859-1"
299
+
300
+ charset
301
+
302
+ response['Content-Type'].should == "text/html;charset=iso-8859-1"
303
+ end
304
+ end
305
+
306
+ describe "format" do
307
+ before(:each) do
308
+ stub!(:request).and_return(Sinatra::Request.new({}))
309
+ end
310
+
311
+ it "should set the correct mime type when given an extension" do
312
+ format :xml
313
+
314
+ response['Content-Type'].split(';').should include(media_type(:xml))
315
+ end
316
+
317
+ it "should fail when set to an unknown extension type" do
318
+ lambda { format :bogus }.should raise_error
319
+ end
320
+
321
+ it "should return the current mime type extension" do
322
+ format :js
323
+
324
+ format.should == :js
325
+ end
326
+
327
+ it "should not modify the Content-Type when given no argument" do
328
+ response['Content-Type'] = "application/xml;charset=utf-8"
329
+
330
+ format
331
+
332
+ response['Content-Type'].should == "application/xml;charset=utf-8"
333
+ end
334
+ end
335
+
336
+ describe "static_file?" do
337
+ before(:all) do
338
+ TestApp.enable :static
339
+ @static_folder = "/static folder/"
340
+ @reachable_static_file = "/static.txt"
341
+ @unreachable_static_file = "/../unreachable_static.txt"
342
+ end
343
+
344
+ after(:all) do
345
+ TestApp.disable :static
346
+ end
347
+
348
+ def options
349
+ TestApp
350
+ end
351
+
352
+ def unescape(path)
353
+ Rack::Utils.unescape(path)
354
+ end
355
+
356
+ it "should return true if the request path points to a file in the public directory" do
357
+ static_file?(@reachable_static_file).should be_true
358
+ end
359
+
360
+ it "should return false when pointing to files outside of the public directory" do
361
+ static_file?(@unreachable_static_file).should be_false
362
+ end
363
+
364
+ it "should return false when the path is for a folder" do
365
+ static_file?(@static_folder).should be_false
366
+ end
367
+ end
368
+
369
+ describe "respond_to" do
370
+ before(:each) do
371
+ stub!(:request).and_return(Sinatra::Request.new({}))
372
+ end
373
+
374
+ it "should fail for an unknown extension" do
375
+ lambda do
376
+ respond_to do |wants|
377
+ wants.bogus
378
+ end
379
+ end.should raise_error
380
+ end
381
+
382
+ it "should call the block corresponding to the current format" do
383
+ format :html
384
+
385
+ respond_to do |wants|
386
+ wants.js { "Some JS" }
387
+ wants.html { "Some HTML" }
388
+ wants.xml { "Some XML" }
389
+ end.should == "Some HTML"
390
+ end
391
+ end
392
+ end
393
+ end
@@ -0,0 +1,19 @@
1
+ #$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
2
+
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'rack/test'
6
+
7
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'sinatra', 'respond_to')
8
+ require File.join(File.dirname(__FILE__), 'app', 'test_app')
9
+ require File.join(File.dirname(__FILE__), 'app', 'production_error_app')
10
+
11
+ Spec::Runner.configure do |config|
12
+ def app
13
+ @app ||= ::Rack::Builder.new do
14
+ run ::TestApp
15
+ end
16
+ end
17
+
18
+ config.include ::Rack::Test::Methods
19
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-respond_to
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.8
5
+ platform: ruby
6
+ authors:
7
+ - Chris Hoffman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-30 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sinatra
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.4
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rubyforge
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.3
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: gemcutter
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.3.0
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: hoe
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.5.0
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.3.0
64
+ version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: rcov
67
+ type: :development
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.9.7.1
74
+ version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: rack-test
77
+ type: :development
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.5.3
84
+ version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: haml
87
+ type: :development
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "2.0"
94
+ version:
95
+ - !ruby/object:Gem::Dependency
96
+ name: builder
97
+ type: :development
98
+ version_requirement:
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: "2.0"
104
+ version:
105
+ - !ruby/object:Gem::Dependency
106
+ name: hoe
107
+ type: :development
108
+ version_requirement:
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 2.5.0
114
+ version:
115
+ description: A respond_to style Rails block for baked-in web service support in Sinatra
116
+ email:
117
+ - cehoffman@gmail.com
118
+ executables: []
119
+
120
+ extensions: []
121
+
122
+ extra_rdoc_files:
123
+ - Manifest.txt
124
+ files:
125
+ - Changelog.rdoc
126
+ - Manifest.txt
127
+ - README.rdoc
128
+ - Rakefile
129
+ - lib/sinatra/respond_to.rb
130
+ - lib/sinatra/respond_to/version.rb
131
+ - spec/spec_helper.rb
132
+ - spec/extension_spec.rb
133
+ - spec/app/production_error_app.rb
134
+ - spec/app/test_app.rb
135
+ - spec/app/unreachable_static.txt
136
+ - spec/app/public/static.txt
137
+ - spec/app/public/static folder/.keep
138
+ - spec/app/views/layout.html.haml
139
+ - spec/app/views/resource.html.haml
140
+ - spec/app/views/resource.js.erb
141
+ - spec/app/views/resource.xml.builder
142
+ has_rdoc: true
143
+ homepage: http://www.github.com/cehoffman/sinatra-respond_to
144
+ licenses: []
145
+
146
+ post_install_message:
147
+ rdoc_options:
148
+ - --main
149
+ - README.rdoc
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ version: "0"
157
+ version:
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: "0"
163
+ version:
164
+ requirements: []
165
+
166
+ rubyforge_project: sinatra-respond_to
167
+ rubygems_version: 1.3.5
168
+ signing_key:
169
+ specification_version: 3
170
+ summary: A respond_to style Rails block for baked-in web service support in Sinatra
171
+ test_files:
172
+ - spec/extension_spec.rb