fractious-http_status_exceptions 0.1.4.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3 @@
1
+ Dir[File.dirname(__FILE__) + "/tasks/*.rake"].each { |file| load(file) }
2
+
3
+ #task :default => :spec
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
+