wvanbergen-http_status_exceptions 0.1.6 → 0.1.7
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/README.rdoc +5 -5
- data/Rakefile +1 -1
- data/http_status_exceptions.gemspec +7 -6
- data/lib/http_status_exceptions.rb +51 -15
- data/spec/http_status_exception_spec.rb +74 -32
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -4,14 +4,14 @@ This simple plugin will register exception classes for all HTTP status. These ex
|
|
4
4
|
which a response will be send back to the client with the desired HTTP status, possible with some other content.
|
5
5
|
|
6
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
|
7
|
+
perform a certain action. A nice looking error page will be the result. See the example below:
|
8
8
|
|
9
9
|
See the project wiki (http://github.com/wvanbergen/http_status_exceptions/wikis) for additional documentation.
|
10
10
|
|
11
11
|
== Installation
|
12
12
|
|
13
13
|
Installation is simple. Simply add the gem in your <tt>environment.rb</tt>:
|
14
|
-
|
14
|
+
|
15
15
|
Rails::Initializer.run do |config|
|
16
16
|
...
|
17
17
|
config.gem 'wvanbergen-http_status_exceptions', :lib => 'http_status_exceptions', :source => 'http://gems.github.com'
|
@@ -22,12 +22,12 @@ Run <tt>rake gems:install</tt> to install the gem if needed.
|
|
22
22
|
== Configuration
|
23
23
|
|
24
24
|
You can modify where HTTP status exception looks for its template files like so:
|
25
|
-
|
25
|
+
|
26
26
|
class ApplicationController < ActionController::Base
|
27
27
|
...
|
28
28
|
HTTPStatus::Base.template_path = 'path_to/http_status_templates'
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
You can also modify which layout is used when rendering a template by setting the <tt>template_layout</tt>:
|
32
32
|
|
33
33
|
class ApplicationController < ActionController::Base
|
@@ -56,5 +56,5 @@ to the response as well, create the following view: <tt>shared/http_status/forbi
|
|
56
56
|
<hr />
|
57
57
|
<p>HTTP status code <small> <%= @exception.status_code %>: <%= @exception.status.to_s.humanize %></small></p>
|
58
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
|
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
60
|
could make a response for XML requests as well by using <tt>shared/http_status/forbidden.xml.builder</tt> as filename
|
data/Rakefile
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'http_status_exceptions'
|
3
|
-
s.version = "0.1.
|
3
|
+
s.version = "0.1.7"
|
4
4
|
s.date = "2009-09-26"
|
5
|
-
|
5
|
+
|
6
6
|
s.summary = "A Rails plugin to use exceptions for generating HTTP status responses"
|
7
7
|
s.description = "Clean up your controller code by raising exceptions that generate responses with different HTTP status codes."
|
8
|
-
|
8
|
+
|
9
9
|
s.add_runtime_dependency('action_controller')
|
10
10
|
s.add_development_dependency('rspec')
|
11
|
-
|
11
|
+
|
12
12
|
s.authors = ['Willem van Bergen']
|
13
13
|
s.email = ['willem@vanbergen.org']
|
14
14
|
s.homepage = 'http://github.com/wvanbergen/http_status_exceptions/wikis'
|
15
|
-
|
16
|
-
s.files
|
15
|
+
|
16
|
+
s.files = %w(spec/spec_helper.rb http_status_exceptions.gemspec .gitignore init.rb lib/http_status_exceptions.rb Rakefile MIT-LICENSE tasks/github-gem.rake README.rdoc spec/http_status_exception_spec.rb)
|
17
|
+
s.test_files = %w(spec/http_status_exception_spec.rb)
|
17
18
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
module HTTPStatus
|
2
|
-
|
2
|
+
|
3
|
+
# The Base HTTP status exception class is used as superclass for every
|
4
|
+
# exception class that is constructed. It implements some shared functionality
|
5
|
+
# for finding the status code and determining the template path to render.
|
3
6
|
class Base < StandardError
|
4
7
|
|
5
8
|
# The path from which the error documents are loaded.
|
@@ -8,38 +11,70 @@ module HTTPStatus
|
|
8
11
|
|
9
12
|
# The layout in which the error documents are rendered
|
10
13
|
cattr_accessor :template_layout
|
14
|
+
@@template_path = nil # Use the standard layout template setting by default.
|
15
|
+
|
16
|
+
attr_reader :details
|
11
17
|
|
12
|
-
attr_reader :status, :details
|
13
|
-
|
14
18
|
# Creates the exception with a message and some optional other info.
|
15
19
|
def initialize(message = nil, details = nil)
|
16
|
-
@status = self.class.to_s.split("::").last.underscore.to_sym rescue :internal_server_error
|
17
20
|
@details = details
|
18
21
|
super(message)
|
19
22
|
end
|
20
|
-
|
21
|
-
#
|
23
|
+
|
24
|
+
# Returns the HTTP status symbol (as defined by Rails) corresponding to this class.
|
25
|
+
# This method should be overridden by subclasses
|
26
|
+
def self.status
|
27
|
+
:internal_server_error
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the HTTP status symbol (as defined by Rails) corresponding to this instance.
|
31
|
+
# By default, it calls the class method of the same name.
|
32
|
+
def status
|
33
|
+
self.class.status
|
34
|
+
end
|
35
|
+
|
36
|
+
# The numeric status code corresponding to this exception class.
|
37
|
+
# Uses the status code map provided by Rails.
|
38
|
+
def self.status_code
|
39
|
+
ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[self.status]
|
40
|
+
end
|
41
|
+
|
42
|
+
# The numeric status code corresponding to this exception.
|
43
|
+
# By default, it calls the class method of the same name.
|
22
44
|
def status_code
|
23
|
-
|
45
|
+
self.class.status_code
|
46
|
+
end
|
47
|
+
|
48
|
+
# The name of the template that should be used as error page for this exception class.
|
49
|
+
def self.template
|
50
|
+
"#{template_path}/#{status}"
|
24
51
|
end
|
25
|
-
|
26
|
-
# The name of the template that should be used as error page for this exception
|
52
|
+
|
53
|
+
# The name of the template that should be used as error page for this exception.
|
54
|
+
# By default, it calls the class method of the same name.
|
27
55
|
def template
|
28
|
-
|
56
|
+
self.class.template
|
29
57
|
end
|
30
58
|
end
|
31
59
|
|
32
60
|
# Creates all the exception classes based on Rails's list of available status code and
|
33
61
|
# registers the exception handler using the rescue_from method.
|
34
62
|
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
63
|
base.send(:rescue_from, HTTPStatus::Base, :with => :http_status_exception)
|
40
64
|
end
|
41
65
|
|
42
|
-
#
|
66
|
+
# Generates a HTTPStatus::Base subclass for every subclass that is found
|
67
|
+
def self.const_missing(const)
|
68
|
+
status_symbol = const.to_s.underscore.to_sym
|
69
|
+
raise "Unrecognized HTTP Status name!" unless ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.has_key?(status_symbol)
|
70
|
+
klass = Class.new(HTTPStatus::Base)
|
71
|
+
klass.cattr_accessor(:status)
|
72
|
+
klass.status = status_symbol
|
73
|
+
const_set(const, klass)
|
74
|
+
return const_get(const)
|
75
|
+
end
|
76
|
+
|
77
|
+
# The default handler for raised HTTP status exceptions.
|
43
78
|
# It will render a template if available, or respond with an empty response
|
44
79
|
# with the HTTP status correspodning to the exception.
|
45
80
|
def http_status_exception(exception)
|
@@ -52,4 +87,5 @@ module HTTPStatus
|
|
52
87
|
end
|
53
88
|
end
|
54
89
|
|
90
|
+
# Include the HTTPStatus module into ActionController to enable its functionality
|
55
91
|
ActionController::Base.send(:include, HTTPStatus)
|
@@ -1,51 +1,93 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe HTTPStatus::Base do
|
4
4
|
before(:each) do
|
5
|
-
|
6
|
-
@
|
5
|
+
ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.stub!(:has_key?).with(:testing_status).and_return(true)
|
6
|
+
@status_exception_class = HTTPStatus::TestingStatus
|
7
7
|
end
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
HTTPStatus::Base.template_path = 'shared/http_status'
|
11
|
+
HTTPStatus.send :remove_const, 'TestingStatus'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set the status symbol based on the class name" do
|
15
|
+
@status_exception_class.status.should == :testing_status
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should check ActionController's status code list for the status code based on the class name" do
|
19
|
+
ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.should_receive(:[]).with(:testing_status)
|
20
|
+
@status_exception_class.status_code
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should use the HTTPStatus::Base.template_path setting to determine the error template" do
|
24
|
+
HTTPStatus::Base.template_path = 'testing'
|
25
|
+
@status_exception_class.template.should == 'testing/testing_status'
|
11
26
|
end
|
12
27
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
28
|
+
it "should raise an exception when the class name does not correspond to a HTTP status code" do
|
29
|
+
lambda { HTTPStatus::Nonsense }.should raise_error
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Run some tests for different valid subclasses.
|
34
|
+
{ 'NotFound' => 404, 'Forbidden' => 403, 'PaymentRequired' => 402, 'InternalServerError' => 500}.each do |status_class, status_code|
|
35
|
+
|
36
|
+
describe "HTTPStatus::#{status_class}" do
|
37
|
+
it "should generate the HTTPStatus::#{status_class} class successfully" do
|
38
|
+
lambda { HTTPStatus.const_get(status_class) }.should_not raise_error
|
18
39
|
end
|
19
|
-
|
40
|
+
|
20
41
|
it "should create a subclass of HTTPStatus::Base for the #{status_class.underscore.humanize.downcase} status" do
|
21
42
|
HTTPStatus.const_get(status_class).ancestors.should include(HTTPStatus::Base)
|
22
43
|
end
|
23
|
-
|
24
|
-
it "should call render with the correct #{status_class.underscore.humanize.downcase} view and correct HTTP status" do
|
25
|
-
@controller.should_receive(:render).with(hash_including(
|
26
|
-
:status => status_symbol,
|
27
|
-
:template => "shared/http_status/#{status_symbol}"))
|
28
44
|
|
29
|
-
|
45
|
+
it "should return the correct status code (#{status_code}) when using the class" do
|
46
|
+
HTTPStatus.const_get(status_class).status_code.should == status_code
|
30
47
|
end
|
48
|
+
|
49
|
+
it "should return the correct status code (#{status_code}) when using the instance" do
|
50
|
+
HTTPStatus.const_get(status_class).new.status_code.should == status_code
|
51
|
+
end
|
31
52
|
end
|
32
53
|
end
|
33
54
|
|
34
|
-
describe HTTPStatus
|
35
|
-
before(:each) { @
|
36
|
-
|
37
|
-
|
38
|
-
|
55
|
+
describe 'HTTPStatus#http_status_exception' do
|
56
|
+
before(:each) { @controller = Class.new(ActionController::Base).new }
|
57
|
+
after(:each) { HTTPStatus::Base.template_layout = nil}
|
58
|
+
|
59
|
+
it "should create the :http_status_exception method in ActionController" do
|
60
|
+
@controller.should respond_to(:http_status_exception)
|
39
61
|
end
|
40
|
-
|
41
|
-
it "should
|
42
|
-
|
43
|
-
@
|
62
|
+
|
63
|
+
it "should call :http_status_exception when an exception is raised when handling the action" do
|
64
|
+
exception = HTTPStatus::Base.new('test')
|
65
|
+
@controller.stub!(:perform_action_without_rescue).and_raise(exception)
|
66
|
+
@controller.should_receive(:http_status_exception).with(exception)
|
67
|
+
@controller.send(:perform_action)
|
44
68
|
end
|
45
|
-
|
46
|
-
it "should
|
47
|
-
|
48
|
-
|
69
|
+
|
70
|
+
it "should call render with the correct view and correct HTTP status" do
|
71
|
+
@controller.should_receive(:render).with(hash_including(
|
72
|
+
:status => :internal_server_error, :template => "shared/http_status/internal_server_error"))
|
73
|
+
|
74
|
+
@controller.http_status_exception(HTTPStatus::Base.new('test'))
|
49
75
|
end
|
50
|
-
end
|
51
76
|
|
77
|
+
it "should not call render with a layout by default" do
|
78
|
+
@controller.should_not_receive(:render).with(hash_including(:layout => 'testing'))
|
79
|
+
@controller.http_status_exception(HTTPStatus::Base.new('test'))
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should call render with a layout set when this property is set on the exception class" do
|
83
|
+
@controller.should_receive(:render).with(hash_including(:layout => 'testing'))
|
84
|
+
HTTPStatus::Base.template_layout = 'testing'
|
85
|
+
@controller.http_status_exception(HTTPStatus::Base.new('test'))
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should call head with the correct status code if render cannot found a template" do
|
89
|
+
@controller.stub!(:render).and_raise(ActionView::MissingTemplate.new([], 'template.htm.erb'))
|
90
|
+
@controller.should_receive(:head).with(:internal_server_error)
|
91
|
+
@controller.http_status_exception(HTTPStatus::Base.new('test'))
|
92
|
+
end
|
93
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wvanbergen-http_status_exceptions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Willem van Bergen
|
@@ -79,5 +79,5 @@ rubygems_version: 1.3.5
|
|
79
79
|
signing_key:
|
80
80
|
specification_version: 2
|
81
81
|
summary: A Rails plugin to use exceptions for generating HTTP status responses
|
82
|
-
test_files:
|
83
|
-
|
82
|
+
test_files:
|
83
|
+
- spec/http_status_exception_spec.rb
|