cehoffman-sinatra-respond_to 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +21 -0
- data/README.markdown +88 -0
- data/Rakefile +14 -0
- data/VERSION.yml +4 -0
- data/lib/sinatra/respond_to.rb +185 -0
- metadata +67 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Chris Hoffman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
## About
|
2
|
+
|
3
|
+
|
4
|
+
## Examples
|
5
|
+
|
6
|
+
require 'sinatra'
|
7
|
+
require 'sinatra/respond_to'
|
8
|
+
register Sinatra::RespondTo # => Due to bug in sinatra for classic applications and extensions, see Issues
|
9
|
+
|
10
|
+
get '/posts' do
|
11
|
+
@posts = Post.recent
|
12
|
+
|
13
|
+
respond_to do |wants|
|
14
|
+
wants.html { haml :posts } # => views/posts.html.haml, also sets content_type to text/html
|
15
|
+
wants.rss { haml :posts } # => views/posts.rss.haml, also sets content_type to application/rss+xml
|
16
|
+
wants.atom { haml :posts } # => views/posts.atom.haml, also sets content_type to appliation/atom+xml
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
get '/post/:id' do
|
21
|
+
@post = Post.find(params[:id])
|
22
|
+
|
23
|
+
respond_to do |wants|
|
24
|
+
wants.html { haml :post } # => views/post.html.haml, also sets content_type to text/html
|
25
|
+
wants.xhtml { haml :post } # => views/post.xhtml.haml, also sets content_type to application/xhtml+xml
|
26
|
+
wants.xml { @post.to_xml } # => sets content_type to application/xml
|
27
|
+
wants.js { erb :post } # => views/post.js.erb, also sets content_type to application/javascript
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
get '/comments/:id' do
|
32
|
+
@comment = Comment.find(params[:id])
|
33
|
+
|
34
|
+
respond_to do |wants|
|
35
|
+
wants.html { haml :comment } # => views/comment.html.haml, also sets content_type to text/html
|
36
|
+
wants.json { @comment.to_json } # => sets content_type to application/json
|
37
|
+
wants.js { erb :comment } # => views/comment.js.erb, also sets content_type to application/javascript
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
## Configuration
|
42
|
+
|
43
|
+
There a few options available for configuring the default behavior of respond_to using Sinatra's
|
44
|
+
<tt>set</tt> utility.
|
45
|
+
|
46
|
+
* <tt>default\_charset - utf-8</tt><br />
|
47
|
+
Assumes all text documents are encoded using this character set.
|
48
|
+
This can be overridden within the respond_to block for the appropriate format
|
49
|
+
* <tt>default\_content - :html</tt><br />
|
50
|
+
When a user vists a url without an extension, for example /post this will be
|
51
|
+
the assumed content to serve first. Expects a symbol as used in setting content_type.
|
52
|
+
* <tt>assume\_xhr\_is\_js - true</tt><br />
|
53
|
+
To avoid headaches with accept headers, and appending .js to urls, this will
|
54
|
+
cause the default format for all XmlHttpRequests to be classified as wanting Javascript
|
55
|
+
in the response.
|
56
|
+
|
57
|
+
## Installing
|
58
|
+
sudo gem install cehoffman-sinatra-respond_to --source=http://gems.github.com
|
59
|
+
|
60
|
+
## Cavaets
|
61
|
+
Due to the way respond\_to works, all incoming requests have the extension striped from the request.path\_info.
|
62
|
+
This causes routes like the following to fail.
|
63
|
+
|
64
|
+
get '/style.css' do
|
65
|
+
sass :style # => renders views/style.sass
|
66
|
+
end
|
67
|
+
|
68
|
+
They need to be changed to the following
|
69
|
+
|
70
|
+
get '/style' do
|
71
|
+
sass :style # => renders views/style.css.sass
|
72
|
+
end
|
73
|
+
|
74
|
+
If you want to ensure the route only gets called for css requests try this
|
75
|
+
|
76
|
+
get '/style', :provides => :css do
|
77
|
+
sass :style
|
78
|
+
end
|
79
|
+
|
80
|
+
## Issues
|
81
|
+
|
82
|
+
Sinatra has a bug that affects Classic style applications and extensions see [#215][215] and [#180][180].
|
83
|
+
For this reason you'll have explicitly register Sinatra::RespondTo for classic applications just like for
|
84
|
+
non-classic applications.
|
85
|
+
|
86
|
+
[215]: https://sinatra.lighthouseapp.com/projects/9779/tickets/215-extensions-cannot-define-before-filters-for-classic-apps "Extensions cannot define before filters for classic apps"
|
87
|
+
[180]: https://sinatra.lighthouseapp.com/projects/9779/tickets/180-better-route-inheritence "Better route inheritence"
|
88
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |spec|
|
4
|
+
spec.name = 'sinatra-respond_to'
|
5
|
+
spec.summary = 'A respond_to style Rails block for baked-in web service support in Sinatra'
|
6
|
+
spec.email = 'cehoffman@gmail.com'
|
7
|
+
spec.homepage = 'http://github.com/cehoffman/sinatra-respond_to'
|
8
|
+
spec.description = spec.summary
|
9
|
+
spec.authors = ["Chris Hoffman"]
|
10
|
+
spec.add_dependency('sinatra', '>=0.9.1.3')
|
11
|
+
end
|
12
|
+
rescue LoadError
|
13
|
+
puts "Jewler not available. Install it with sugo gem install technicalpickles-jeweler -s http://gems.github.com"
|
14
|
+
end
|
data/VERSION.yml
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
# Simple note, accept header parsing was looked at but deamed
|
2
|
+
# too much of an irregularity to deal with. Problems with the header
|
3
|
+
# differences from IE, Firefox, Safari, and every other UA causes
|
4
|
+
# problems with the expected output. The general expected behavior
|
5
|
+
# would be serve html when no extension provided, but most UAs say
|
6
|
+
# they will accept application/xml with out a quality indicator, meaning
|
7
|
+
# you'd get the xml block served insead. Just plain retarded, use the
|
8
|
+
# extension and you'll never be suprised.
|
9
|
+
|
10
|
+
module Sinatra
|
11
|
+
module RespondTo
|
12
|
+
class UnhandledFormat < Sinatra::NotFound; end
|
13
|
+
class MissingTemplate < Sinatra::NotFound
|
14
|
+
def code; 500 end
|
15
|
+
end
|
16
|
+
|
17
|
+
TEXT_MIME_TYPES = [:txt, :html, :js, :json, :xml, :rss, :atom, :css, :asm, :c, :cc, :conf,
|
18
|
+
:csv, :cxx, :diff, :dtd, :f, :f77, :f90, :for, :gemspec, :h, :hh, :htm,
|
19
|
+
:log, :mathml, :mml, :p, :pas, :pl, :pm, :py, :rake, :rb, :rdf, :rtf, :ru,
|
20
|
+
:s, :sgm, :sgml, :sh, :svg, :svgz, :text, :wsdl, :xhtml, :xsl, :xslt, :yaml,
|
21
|
+
:yml, :ics]
|
22
|
+
|
23
|
+
def self.registered(app)
|
24
|
+
app.helpers RespondTo::Helpers
|
25
|
+
|
26
|
+
app.set :default_charset, 'utf-8' unless app.respond_to?(:default_charset)
|
27
|
+
app.set :default_content, :html unless app.respond_to?(:default_content)
|
28
|
+
app.set :assume_xhr_is_js, true unless app.respond_to?(:assume_xhr_is_js)
|
29
|
+
|
30
|
+
# We remove the trailing extension so routes
|
31
|
+
# don't have to be of the style
|
32
|
+
#
|
33
|
+
# get '/resouce.:format'
|
34
|
+
#
|
35
|
+
# They can instead be of the style
|
36
|
+
#
|
37
|
+
# get '/resource'
|
38
|
+
#
|
39
|
+
# and the format will automatically be available in as <tt>format</tt>
|
40
|
+
app.before do
|
41
|
+
unless options.static? && options.public? && ["GET", "HEAD"].include?(request.request_method) && static_file?(unescape(request.path_info))
|
42
|
+
request.path_info.gsub! %r{\.([^\./]+)$}, ''
|
43
|
+
format $1 || options.default_content
|
44
|
+
|
45
|
+
# For the oh so common case of actually wanting Javascript from an XmlHttpRequest
|
46
|
+
format :js if request.xhr? && options.assume_xhr_is_js?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Replace all routes that have an ending extension with one that doesn't
|
51
|
+
# Most generally a fix for the __sinatra__ routes in development
|
52
|
+
# app.routes.each_pair do |verb, subroutes|
|
53
|
+
# subroutes.each do |subroute|
|
54
|
+
# subroute[0] = Regexp.new(subroute[0].source.gsub(/\\\.[^\.\/]+\$$/, '$'))
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
|
58
|
+
app.configure :development do
|
59
|
+
# Very, very, very hackish but only for development at least
|
60
|
+
# Modifies the regex matching /__sinatra__/:image.png to not have the extension
|
61
|
+
["GET", "HEAD"].each do |verb|
|
62
|
+
app.routes[verb][1][0] = Regexp.new(app.routes[verb][1][0].source.gsub(/\\\.[^\.\/]+\$$/, '$'))
|
63
|
+
end
|
64
|
+
|
65
|
+
app.error UnhandledFormat do
|
66
|
+
content_type :html, :charset => 'utf-8'
|
67
|
+
|
68
|
+
(<<-HTML).gsub(/^ {10}/, '')
|
69
|
+
<!DOCTYPE html>
|
70
|
+
<html>
|
71
|
+
<head>
|
72
|
+
<style type="text/css">
|
73
|
+
body { text-align:center;font-family:helvetica,arial;font-size:22px;
|
74
|
+
color:#888;margin:20px}
|
75
|
+
#c {margin:0 auto;width:500px;text-align:left}
|
76
|
+
</style>
|
77
|
+
</head>
|
78
|
+
<body>
|
79
|
+
<h2>Sinatra doesn't know this ditty.</h2>
|
80
|
+
<img src='/__sinatra__/404.png'>
|
81
|
+
<div id="c">
|
82
|
+
Try this:
|
83
|
+
<pre>#{request.request_method.downcase} '#{request.path_info}' do\n respond_to do |wants|\n wants.#{format} { "Hello World" }\n end\nend</pre>
|
84
|
+
</div>
|
85
|
+
</body>
|
86
|
+
</html>
|
87
|
+
HTML
|
88
|
+
end
|
89
|
+
|
90
|
+
app.error MissingTemplate do
|
91
|
+
content_type :html, :charset => 'utf-8'
|
92
|
+
|
93
|
+
engine = request.env['sinatra.error'].message[/\.([^\.]+)$/, 1]
|
94
|
+
path = request.path_info[/([^\/]+)$/, 1]
|
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.html.#{engine}</small>\n<pre>#{escape_html(layout)}</pre>" if layout
|
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 if layout}
|
122
|
+
<small>#{path}.html.#{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 lookup_template_with_format(*args)
|
137
|
+
args[1] = "#{args[1]}.#{format}".to_sym
|
138
|
+
lookup_template_without_format *args
|
139
|
+
rescue Errno::ENOENT
|
140
|
+
raise MissingTemplate, "#{args[1]}.#{args[0]}"
|
141
|
+
end
|
142
|
+
alias_method :lookup_template_without_format, :lookup_template
|
143
|
+
alias_method :lookup_template, :lookup_template_with_format
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
module Helpers
|
148
|
+
def format(val=nil)
|
149
|
+
request.env['sinatra.respond_to.format'] = val.to_sym unless val.nil?
|
150
|
+
request.env['sinatra.respond_to.format']
|
151
|
+
end
|
152
|
+
|
153
|
+
def static_file?(path)
|
154
|
+
return false unless path =~ /.*[^\/]$/
|
155
|
+
public_dir = File.expand_path(options.public)
|
156
|
+
path = File.expand_path(File.join(public_dir, unescape(request.path_info)))
|
157
|
+
return false if path[0, public_dir.length] != public_dir
|
158
|
+
return false unless File.file?(path)
|
159
|
+
true
|
160
|
+
end
|
161
|
+
|
162
|
+
def respond_to(&block)
|
163
|
+
wants = {}
|
164
|
+
def wants.method_missing(type, *args, &block)
|
165
|
+
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?
|
166
|
+
self[type] = block
|
167
|
+
end
|
168
|
+
|
169
|
+
yield wants
|
170
|
+
|
171
|
+
handler = wants[format]
|
172
|
+
raise UnhandledFormat if handler.nil?
|
173
|
+
|
174
|
+
opts = [format]
|
175
|
+
opts << {:charset => options.default_charset} if TEXT_MIME_TYPES.include? format && response['Content-Type'] !~ /charset=/
|
176
|
+
|
177
|
+
content_type *opts
|
178
|
+
|
179
|
+
handler.call
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
register RespondTo
|
185
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cehoffman-sinatra-respond_to
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Hoffman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-11 00:00:00 -07: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.1.3
|
24
|
+
version:
|
25
|
+
description: A respond_to style Rails block for baked-in web service support in Sinatra
|
26
|
+
email: cehoffman@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.markdown
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README.markdown
|
37
|
+
- Rakefile
|
38
|
+
- VERSION.yml
|
39
|
+
- lib/sinatra/respond_to.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/cehoffman/sinatra-respond_to
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options:
|
44
|
+
- --charset=UTF-8
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: A respond_to style Rails block for baked-in web service support in Sinatra
|
66
|
+
test_files: []
|
67
|
+
|