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 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,5 +1,5 @@
1
1
  Dir[File.dirname(__FILE__) + "/tasks/*.rake"].each { |file| load(file) }
2
2
 
3
- GithubGem::RakeTasks.new(:gem)
3
+ GithubGem::RakeTasks.new(:gem)
4
4
 
5
5
  task :default => :spec
@@ -1,17 +1,18 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'http_status_exceptions'
3
- s.version = "0.1.6"
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 = %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)
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
- # The numeric status code corresponding to this exception
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
- ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[@status]
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
- "#{@@template_path}/#{@status}"
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
- # The default handler for raised HTTP status exceptions.
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 'HTTPStatus#http_status_exception' do
3
+ describe HTTPStatus::Base do
4
4
  before(:each) do
5
- @controller_class = Class.new(ActionController::Base)
6
- @controller = @controller_class.new
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
- it "should respond to the :http_status_exception method" do
10
- @controller.should respond_to(:http_status_exception)
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
- ['NotFound', 'Forbidden', 'PaymentRequired'].each do |status_class|
14
- status_symbol = status_class.underscore.downcase.to_sym
15
-
16
- it "should create the HTTPStatus::#{status_class} class" do
17
- HTTPStatus.const_defined?(status_class).should be_true
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
- @controller.http_status_exception(HTTPStatus.const_get(status_class).new('test'))
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::Base do
35
- before(:each) { @status = HTTPStatus::Base.new }
36
-
37
- it "should set the status symbol bases on the class name" do
38
- @status.status.should == :base
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 check ActionController's status code list for the status code based on the class name" do
42
- ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.should_receive(:[]).with(:base)
43
- @status.status_code
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 use the HTTPStatus::Base.template_path setting to determine the error template" do
47
- HTTPStatus::Base.template_path = 'testing'
48
- @status.template.should == 'testing/base'
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.6
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