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 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,4 @@
1
+ ---
2
+ :patch: 1
3
+ :major: 0
4
+ :minor: 3
@@ -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
+