fractious-http_status_exceptions 0.1.4.2
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/MIT-LICENSE +20 -0
- data/README.rdoc +60 -0
- data/Rakefile +3 -0
- data/init.rb +1 -0
- data/lib/http_status_exceptions.rb +55 -0
- data/tasks/github-gem.rake +250 -0
- metadata +61 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Willem van Bergen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
= HTTP status exception
|
2
|
+
|
3
|
+
This simple plugin will register exception classes for all HTTP status. These exceptions can then be raised from your controllers, after
|
4
|
+
which a response will be send back to the client with the desired HTTP status, possible with some other content.
|
5
|
+
|
6
|
+
You can use this plugin to access control mechanisms. You can simply raise a HTTPStatus::Forbidden if a user is not allowed to
|
7
|
+
perform a certain action. A nice looking error page will be the result. See the example below
|
8
|
+
|
9
|
+
See the project wiki (http://github.com/wvanbergen/http_status_exceptions/wikis) for additional documentation.
|
10
|
+
|
11
|
+
== Installation
|
12
|
+
|
13
|
+
Installation is simple. Simply add the gem in your <tt>environment.rb</tt>:
|
14
|
+
|
15
|
+
Rails::Initializer.run do |config|
|
16
|
+
...
|
17
|
+
config.gem 'wvanbergen-http_status_exceptions', :lib => 'http_status_exceptions', :source => 'http://gems.github.com'
|
18
|
+
end
|
19
|
+
|
20
|
+
Run <tt>rake gems:install</tt> to install the gem if needed.
|
21
|
+
|
22
|
+
== Configuration
|
23
|
+
|
24
|
+
You can modify where HTTP status exception looks for its template files like so:
|
25
|
+
|
26
|
+
class ApplicationController < ActionController::Base
|
27
|
+
...
|
28
|
+
HTTPStatus::Base.template_path = 'path_to/http_status_templates'
|
29
|
+
end
|
30
|
+
|
31
|
+
You can also modify which layout is used when rendering a template by setting the <tt>template_layout</tt>:
|
32
|
+
|
33
|
+
class ApplicationController < ActionController::Base
|
34
|
+
...
|
35
|
+
HTTPStatus::Base.template_layout = 'exception'
|
36
|
+
end
|
37
|
+
|
38
|
+
If you don't set a template_layout the current layout for the requested action will be used.
|
39
|
+
|
40
|
+
== Usage
|
41
|
+
|
42
|
+
class BlogController < ApplicationController
|
43
|
+
|
44
|
+
def destroy
|
45
|
+
raise HTTPStatus::Forbidden, 'You cannot delete blogs!' unless current_user.can_delete_blogs?
|
46
|
+
@blog.destroy
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
By default, this will return an empty response with the "forbidden" status code (403). If you want to add content
|
51
|
+
to the response as well, create the following view: <tt>shared/http_status/forbidden.html.erb</tt>. You can use the
|
52
|
+
<tt>@exception</tt>-object in your view:
|
53
|
+
|
54
|
+
<h1>Forbidden</h1>
|
55
|
+
<p> <%= h(@exception.message) %> </p>
|
56
|
+
<hr />
|
57
|
+
<p>HTTP status code <small> <%= @exception.status_code %>: <%= @exception.status.to_s.humanize %></small></p>
|
58
|
+
|
59
|
+
The response will only be sent if the request format is HTML because of the name of the view file. In theory you
|
60
|
+
could make a response for XML requests as well by using <tt>shared/http_status/forbidden.xml.builder</tt> as filename
|
data/Rakefile
ADDED
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'http_status_exceptions.rb'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module HTTPStatus
|
2
|
+
|
3
|
+
class Base < StandardError
|
4
|
+
|
5
|
+
# The path from which the error documents are loaded.
|
6
|
+
cattr_accessor :template_path
|
7
|
+
@@template_path = 'shared/http_status'
|
8
|
+
|
9
|
+
# The layout in which the error documents are rendered
|
10
|
+
cattr_accessor :template_layout
|
11
|
+
|
12
|
+
attr_reader :status, :details
|
13
|
+
|
14
|
+
# Creates the exception with a message and some optional other info.
|
15
|
+
def initialize(message = nil, details = nil)
|
16
|
+
@status = self.class.to_s.split("::").last.underscore.to_sym rescue :internal_server_error
|
17
|
+
@details = details
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
|
21
|
+
# The numeric status code corresponding to this exception
|
22
|
+
def status_code
|
23
|
+
ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[@status]
|
24
|
+
end
|
25
|
+
|
26
|
+
# The name of the template that should be used as error page for this exception
|
27
|
+
def template
|
28
|
+
"#{@@template_path}/#{@status}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Creates all the exception classes based on Rails's list of available status code and
|
33
|
+
# registers the exception handler using the rescue_from method.
|
34
|
+
def self.included(base)
|
35
|
+
ActionController::StatusCodes::STATUS_CODES.each do |code, name|
|
36
|
+
const_set(name.to_s.gsub(/[^A-Za-z]/, '').camelize, Class.new(HTTPStatus::Base)) if code >= 400
|
37
|
+
end
|
38
|
+
|
39
|
+
base.send(:rescue_from, HTTPStatus::Base, :with => :http_status_exception)
|
40
|
+
end
|
41
|
+
|
42
|
+
# The default handler for raised HTTP status exceptions.
|
43
|
+
# It will render a template if available, or respond with an empty response
|
44
|
+
# with the HTTP status correspodning to the exception.
|
45
|
+
def http_status_exception(exception)
|
46
|
+
@exception = exception
|
47
|
+
render_options = {:template => exception.template, :status => exception.status}
|
48
|
+
render_options[:layout] = exception.template_layout if exception.template_layout
|
49
|
+
render(render_options)
|
50
|
+
rescue ActionView::MissingTemplate
|
51
|
+
head(exception.status)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
ActionController::Base.send(:include, HTTPStatus)
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubyforge'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/tasklib'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
module Rake
|
8
|
+
|
9
|
+
class GithubGem < TaskLib
|
10
|
+
|
11
|
+
attr_accessor :name
|
12
|
+
attr_accessor :specification
|
13
|
+
|
14
|
+
def self.define_tasks!
|
15
|
+
gem_task_builder = Rake::GithubGem.new
|
16
|
+
gem_task_builder.register_all_tasks!
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
reload_gemspec!
|
22
|
+
end
|
23
|
+
|
24
|
+
def register_all_tasks!
|
25
|
+
namespace(:gem) do
|
26
|
+
desc "Updates the file lists for this gem"
|
27
|
+
task(:manifest) { manifest_task }
|
28
|
+
|
29
|
+
desc "Releases a new version of #{@name}"
|
30
|
+
task(:build => [:manifest]) { build_task }
|
31
|
+
|
32
|
+
|
33
|
+
release_dependencies = [:check_clean_master_branch, :version, :build, :create_tag]
|
34
|
+
release_dependencies.push 'doc:publish' if has_rdoc?
|
35
|
+
release_dependencies.unshift 'test' if has_tests?
|
36
|
+
release_dependencies.unshift 'spec' if has_specs?
|
37
|
+
|
38
|
+
desc "Releases a new version of #{@name}"
|
39
|
+
task(:release => release_dependencies) { release_task }
|
40
|
+
|
41
|
+
# helper task for releasing
|
42
|
+
task(:check_clean_master_branch) { verify_clean_status('master') }
|
43
|
+
task(:check_version) { verify_version(ENV['VERSION'] || @specification.version) }
|
44
|
+
task(:version => [:check_version]) { set_gem_version! }
|
45
|
+
task(:create_tag) { create_version_tag! }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Register RDoc tasks
|
49
|
+
if has_rdoc?
|
50
|
+
require 'rake/rdoctask'
|
51
|
+
|
52
|
+
namespace(:doc) do
|
53
|
+
desc 'Generate documentation for request-log-analyzer'
|
54
|
+
Rake::RDocTask.new(:compile) do |rdoc|
|
55
|
+
rdoc.rdoc_dir = 'doc'
|
56
|
+
rdoc.title = @name
|
57
|
+
rdoc.options += @specification.rdoc_options
|
58
|
+
rdoc.rdoc_files.include(@specification.extra_rdoc_files)
|
59
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "Publish RDoc files for #{@name} to Github"
|
63
|
+
task(:publish => :compile) do
|
64
|
+
sh 'git checkout gh-pages'
|
65
|
+
sh 'git pull origin gh-pages'
|
66
|
+
sh 'cp -rf doc/* .'
|
67
|
+
sh "git commit -am \"Publishing newest RDoc documentation for #{@name}\""
|
68
|
+
sh "git push origin gh-pages"
|
69
|
+
sh "git checkout master"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Setup :spec task if RSpec files exist
|
75
|
+
if has_specs?
|
76
|
+
require 'spec/rake/spectask'
|
77
|
+
|
78
|
+
desc "Run all specs for #{@name}"
|
79
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
80
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Setup :test task if unit test files exist
|
85
|
+
if has_tests?
|
86
|
+
require 'rake/testtask'
|
87
|
+
|
88
|
+
desc "Run all unit tests for #{@name}"
|
89
|
+
Rake::TestTask.new(:test) do |t|
|
90
|
+
t.pattern = 'test/**/*_test.rb'
|
91
|
+
t.verbose = true
|
92
|
+
t.libs << 'test'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def has_rdoc?
|
100
|
+
@specification.has_rdoc
|
101
|
+
end
|
102
|
+
|
103
|
+
def has_specs?
|
104
|
+
Dir['spec/**/*_spec.rb'].any?
|
105
|
+
end
|
106
|
+
|
107
|
+
def has_tests?
|
108
|
+
Dir['test/**/*_test.rb'].any?
|
109
|
+
end
|
110
|
+
|
111
|
+
def reload_gemspec!
|
112
|
+
raise "No gemspec file found!" if gemspec_file.nil?
|
113
|
+
spec = File.read(gemspec_file)
|
114
|
+
@specification = eval(spec)
|
115
|
+
@name = specification.name
|
116
|
+
end
|
117
|
+
|
118
|
+
def run_command(command)
|
119
|
+
lines = []
|
120
|
+
IO.popen(command) { |f| lines = f.readlines }
|
121
|
+
return lines
|
122
|
+
end
|
123
|
+
|
124
|
+
def git_modified?(file)
|
125
|
+
return !run_command('git status').detect { |line| Regexp.new(Regexp.quote(file)) =~ line }.nil?
|
126
|
+
end
|
127
|
+
|
128
|
+
def git_commit_file(file, message, branch = nil)
|
129
|
+
verify_current_branch(branch) unless branch.nil?
|
130
|
+
if git_modified?(file)
|
131
|
+
sh "git add #{file}"
|
132
|
+
sh "git commit -m \"#{message}\""
|
133
|
+
else
|
134
|
+
raise "#{file} is not modified and cannot be committed!"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def git_create_tag(tag_name, message)
|
139
|
+
sh "git tag -a \"#{tag_name}\" -m \"#{message}\""
|
140
|
+
end
|
141
|
+
|
142
|
+
def git_push(remote = 'origin', branch = 'master', options = [])
|
143
|
+
verify_clean_status(branch)
|
144
|
+
options_str = options.map { |o| "--#{o}"}.join(' ')
|
145
|
+
sh "git push #{options_str} #{remote} #{branch}"
|
146
|
+
end
|
147
|
+
|
148
|
+
def gemspec_version=(new_version)
|
149
|
+
spec = File.read(gemspec_file)
|
150
|
+
spec.gsub!(/^(\s*s\.version\s*=\s*)('|")(.+)('|")(\s*)$/) { "#{$1}'#{new_version}'#{$5}" }
|
151
|
+
spec.gsub!(/^(\s*s\.date\s*=\s*)('|")(.+)('|")(\s*)$/) { "#{$1}'#{Date.today.strftime('%Y-%m-%d')}'#{$5}" }
|
152
|
+
File.open(gemspec_file, 'w') { |f| f << spec }
|
153
|
+
reload_gemspec!
|
154
|
+
end
|
155
|
+
|
156
|
+
def gemspec_date=(new_date)
|
157
|
+
spec = File.read(gemspec_file)
|
158
|
+
spec.gsub!(/^(\s*s\.date\s*=\s*)('|")(.+)('|")(\s*)$/) { "#{$1}'#{new_date.strftime('%Y-%m-%d')}'#{$5}" }
|
159
|
+
File.open(gemspec_file, 'w') { |f| f << spec }
|
160
|
+
reload_gemspec!
|
161
|
+
end
|
162
|
+
|
163
|
+
def gemspec_file
|
164
|
+
@gemspec_file ||= Dir['*.gemspec'].first
|
165
|
+
end
|
166
|
+
|
167
|
+
def verify_current_branch(branch)
|
168
|
+
run_command('git branch').detect { |line| /^\* (.+)/ =~ line }
|
169
|
+
raise "You are currently not working in the master branch!" unless branch == $1
|
170
|
+
end
|
171
|
+
|
172
|
+
def verify_clean_status(on_branch = nil)
|
173
|
+
sh "git fetch"
|
174
|
+
lines = run_command('git status')
|
175
|
+
raise "You don't have the most recent version available. Run git pull first." if /^\# Your branch is behind/ =~ lines[1]
|
176
|
+
raise "You are currently not working in the #{on_branch} branch!" unless on_branch.nil? || (/^\# On branch (.+)/ =~ lines.first && $1 == on_branch)
|
177
|
+
raise "Your master branch contains modifications!" unless /^nothing to commit \(working directory clean\)/ =~ lines.last
|
178
|
+
end
|
179
|
+
|
180
|
+
def verify_version(new_version)
|
181
|
+
newest_version = run_command('git tag').map { |tag| tag.split(name + '-').last }.compact.map { |v| Gem::Version.new(v) }.max
|
182
|
+
raise "This version number (#{new_version}) is not higher than the highest tagged version (#{newest_version})" if !newest_version.nil? && newest_version >= Gem::Version.new(new_version.to_s)
|
183
|
+
end
|
184
|
+
|
185
|
+
def set_gem_version!
|
186
|
+
# update gemspec file
|
187
|
+
self.gemspec_version = ENV['VERSION'] if Gem::Version.correct?(ENV['VERSION'])
|
188
|
+
self.gemspec_date = Date.today
|
189
|
+
end
|
190
|
+
|
191
|
+
def manifest_task
|
192
|
+
verify_current_branch('master')
|
193
|
+
|
194
|
+
list = Dir['**/*'].sort
|
195
|
+
list -= [gemspec_file]
|
196
|
+
|
197
|
+
if File.exist?('.gitignore')
|
198
|
+
File.read('.gitignore').each_line do |glob|
|
199
|
+
glob = glob.chomp.sub(/^\//, '')
|
200
|
+
list -= Dir[glob]
|
201
|
+
list -= Dir["#{glob}/**/*"] if File.directory?(glob) and !File.symlink?(glob)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# update the spec file
|
206
|
+
spec = File.read(gemspec_file)
|
207
|
+
spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do
|
208
|
+
assignment = $1
|
209
|
+
bunch = $2 ? list.grep(/^(test.*_test\.rb|spec.*_spec.rb)$/) : list
|
210
|
+
'%s%%w(%s)' % [assignment, bunch.join(' ')]
|
211
|
+
end
|
212
|
+
|
213
|
+
File.open(gemspec_file, 'w') { |f| f << spec }
|
214
|
+
reload_gemspec!
|
215
|
+
end
|
216
|
+
|
217
|
+
def build_task
|
218
|
+
sh "gem build #{gemspec_file}"
|
219
|
+
Dir.mkdir('pkg') unless File.exist?('pkg')
|
220
|
+
sh "mv #{name}-#{specification.version}.gem pkg/#{name}-#{specification.version}.gem"
|
221
|
+
end
|
222
|
+
|
223
|
+
def install_task
|
224
|
+
raise "#{name} .gem file not found" unless File.exist?("pkg/#{name}-#{specification.version}.gem")
|
225
|
+
sh "gem install pkg/#{name}-#{specification.version}.gem"
|
226
|
+
end
|
227
|
+
|
228
|
+
def uninstall_task
|
229
|
+
raise "#{name} .gem file not found" unless File.exist?("pkg/#{name}-#{specification.version}.gem")
|
230
|
+
sh "gem uninstall #{name}"
|
231
|
+
end
|
232
|
+
|
233
|
+
def create_version_tag!
|
234
|
+
# commit the gemspec file
|
235
|
+
git_commit_file(gemspec_file, "Updated #{gemspec_file} for release of version #{@specification.version}") if git_modified?(gemspec_file)
|
236
|
+
|
237
|
+
# create tag and push changes
|
238
|
+
git_create_tag("#{@name}-#{@specification.version}", "Tagged version #{@specification.version}")
|
239
|
+
git_push('origin', 'master', [:tags])
|
240
|
+
end
|
241
|
+
|
242
|
+
def release_task
|
243
|
+
puts
|
244
|
+
puts '------------------------------------------------------------'
|
245
|
+
puts "Released #{@name} - version #{@specification.version}"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
Rake::GithubGem.define_tasks!
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fractious-http_status_exceptions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.4.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Willem van Bergen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-20 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Clean up your controller code by raising exceptions that generate responses with different HTTP status codes.
|
17
|
+
email:
|
18
|
+
- willem@vanbergen.org
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- init.rb
|
30
|
+
- lib
|
31
|
+
- lib/http_status_exceptions.rb
|
32
|
+
- tasks
|
33
|
+
- tasks/github-gem.rake
|
34
|
+
has_rdoc: false
|
35
|
+
homepage: http://github.com/wvanbergen/http_status_exceptions/wikis
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.2.0
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: A Rails plugin to use exceptions for generating HTTP status responses
|
60
|
+
test_files: []
|
61
|
+
|