cehoffman-sinatra-respond_to 0.3.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/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
|
+
|