http_status_exceptions 0.1.9

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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ http_status_exceptions-*.gem
2
+ /tmp
3
+ /doc
4
+ /pkg
5
+ /coverage
6
+ .DS_Store
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 20082-2009 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,68 @@
1
+ <b>WARNING:</b> the gem version that Github currently serves is faulty. The issue
2
+ is already fixes in the repository, but Github is not yet building new gem
3
+ versions. As soon as this is fixed, I will release a new version that resolves
4
+ the issue. For now, install version 0.1.5 which is unaffected:
5
+
6
+ sudo gem install wvanbergen-http_status_exceptions \
7
+ --source http://gems.github.com --version "= 0.1.5"
8
+
9
+ = HTTP status exception
10
+
11
+ This simple plugin will register exception classes for all HTTP status. These exceptions can then be raised from your controllers, after
12
+ which a response will be send back to the client with the desired HTTP status, possible with some other content.
13
+
14
+ You can use this plugin to access control mechanisms. You can simply raise a HTTPStatus::Forbidden if a user is not allowed to
15
+ perform a certain action. A nice looking error page will be the result. See the example below:
16
+
17
+ See the project wiki (http://github.com/wvanbergen/http_status_exceptions/wikis) for additional documentation.
18
+
19
+ == Installation
20
+
21
+ Installation is simple. Simply add the gem in your <tt>environment.rb</tt>:
22
+
23
+ Rails::Initializer.run do |config|
24
+ ...
25
+ config.gem 'wvanbergen-http_status_exceptions', :lib => 'http_status_exceptions', :source => 'http://gems.github.com'
26
+ end
27
+
28
+ Run <tt>rake gems:install</tt> to install the gem if needed.
29
+
30
+ == Configuration
31
+
32
+ You can modify where HTTP status exception looks for its template files like so:
33
+
34
+ class ApplicationController < ActionController::Base
35
+ ...
36
+ HTTPStatus::Base.template_path = 'path_to/http_status_templates'
37
+ end
38
+
39
+ You can also modify which layout is used when rendering a template by setting the <tt>template_layout</tt>:
40
+
41
+ class ApplicationController < ActionController::Base
42
+ ...
43
+ HTTPStatus::Base.template_layout = 'exception'
44
+ end
45
+
46
+ If you don't set a template_layout the current layout for the requested action will be used.
47
+
48
+ == Usage
49
+
50
+ class BlogController < ApplicationController
51
+
52
+ def destroy
53
+ raise HTTPStatus::Forbidden, 'You cannot delete blogs!' unless current_user.can_delete_blogs?
54
+ @blog.destroy
55
+ end
56
+ end
57
+
58
+ By default, this will return an empty response with the "forbidden" status code (403). If you want to add content
59
+ to the response as well, create the following view: <tt>shared/http_status/forbidden.html.erb</tt>. You can use the
60
+ <tt>@exception</tt>-object in your view:
61
+
62
+ <h1>Forbidden</h1>
63
+ <p> <%= h(@exception.message) %> </p>
64
+ <hr />
65
+ <p>HTTP status code <small> <%= @exception.status_code %>: <%= @exception.status.to_s.humanize %></small></p>
66
+
67
+ The response will only be sent if the request format is HTML because of the name of the view file. In theory you
68
+ 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,5 @@
1
+ Dir[File.dirname(__FILE__) + "/tasks/*.rake"].each { |file| load(file) }
2
+
3
+ GithubGem::RakeTasks.new(:gem)
4
+
5
+ task :default => :spec
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'http_status_exceptions'
3
+
4
+ # Do not update the version and date values by hand.
5
+ # This will be done automatically by the gem release script.
6
+ s.version = "0.1.9"
7
+ s.date = "2009-10-01"
8
+
9
+ s.summary = "A Rails plugin to use exceptions for generating HTTP status responses"
10
+ s.description = "Clean up your controller code by raising exceptions that generate responses with different HTTP status codes."
11
+
12
+ s.add_runtime_dependency('actionpack', '>= 2.1.0')
13
+ s.add_development_dependency('rspec')
14
+
15
+ s.authors = ['Willem van Bergen']
16
+ s.email = ['willem@vanbergen.org']
17
+ s.homepage = 'http://github.com/wvanbergen/http_status_exceptions/wikis'
18
+
19
+ # Do not update the files and test_files values by hand.
20
+ # This will be done automatically by the gem release script.
21
+ 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)
22
+ s.test_files = %w(spec/http_status_exception_spec.rb)
23
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'http_status_exceptions.rb'
@@ -0,0 +1,146 @@
1
+ # The HTTPStatus module is the core of the http_status_exceptions gem and
2
+ # contains all functionality.
3
+ #
4
+ # The module contains <tt>HTTPStatus::Base</tt> class, which is used as a
5
+ # superclass for every HTTPStatus exception. Subclasses, like
6
+ # <tt>HTTPStatus::Forbidden</tt> or <tt>HTTPStatus::NotFound</tt> will be
7
+ # generated on demand by the <tt>HTTPStatus.const_missing</tt> method.
8
+ #
9
+ # Moreover, it contains methods to handle these exceptions and integrate this
10
+ # functionality into <tt>ActionController::Base</tt>. When this module is in
11
+ # included in the <tt>ActionController::Base</tt> class, it will call
12
+ # <tt>rescue_from</tt> on it to handle all <tt>HTTPStatus::Base</tt>
13
+ # exceptions with the <tt>HTTPStatus#http_status_exceptions</tt> method.
14
+ #
15
+ # The exception handler will try to render a response with the correct
16
+ # HTTPStatus. When no suitable template is found to render the exception with,
17
+ # it will simply respond with an empty HTTP status code.
18
+ module HTTPStatus
19
+
20
+ # The current gem release version. Do not set this value by hand, it will
21
+ # be done automatically by them gem release script.
22
+ VERSION = "0.1.9"
23
+
24
+ # The Base HTTP status exception class is used as superclass for every
25
+ # exception class that is constructed. It implements some shared
26
+ # functionality for finding the status code and determining the template
27
+ # path to render.
28
+ #
29
+ # Subclasses of this class will be generated on demand when a non-exisiting
30
+ # constant of the <tt>HTTPStatus</tt> module is requested. This is
31
+ # implemented in the <tt>HTTPStatus.const_missing</tt> method.
32
+ class Base < StandardError
33
+
34
+ # The path from which the error documents are loaded.
35
+ cattr_accessor :template_path
36
+ @@template_path = 'shared/http_status'
37
+
38
+ # The layout in which the error documents are rendered
39
+ cattr_accessor :template_layout
40
+ @@template_layout = nil # Use the standard layout template setting by default.
41
+
42
+ attr_reader :details
43
+
44
+ # Initializes the exception instance.
45
+ # <tt>message</tt>:: The exception message.
46
+ # <tt>details</tt>:: An object with details about the exception.
47
+ def initialize(message = nil, details = nil)
48
+ @details = details
49
+ super(message)
50
+ end
51
+
52
+ # Returns the HTTP status symbol corresponding to this class. This is one
53
+ # of the symbols that can be found in the map that can be found in
54
+ # <tt>ActionController::StatusCodes</tt>.
55
+ #
56
+ # This method should be overridden by subclasses, as it returns
57
+ # <tt>:internal_server_error</tt> by default. This is done automatically
58
+ # when a new exception class is being generated by
59
+ # <tt>HTTPStatus.const_missing</tt>.
60
+ def self.status
61
+ :internal_server_error
62
+ end
63
+
64
+ # Returns the HTTP status symbol (as defined by Rails) corresponding to
65
+ # this instance. By default, it calls the class method of the same name.
66
+ def status
67
+ self.class.status
68
+ end
69
+
70
+ # The numeric status code corresponding to this exception class. Uses the
71
+ # status symbol to code map in <tt>ActionController::StatusCodes</tt>.
72
+ def self.status_code
73
+ ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE[self.status]
74
+ end
75
+
76
+ # The numeric status code corresponding to this exception. By default, it
77
+ # calls the class method of the same name.
78
+ def status_code
79
+ self.class.status_code
80
+ end
81
+
82
+ # The name of the template that should be used as error page for this
83
+ # exception class.
84
+ def self.template
85
+ "#{template_path}/#{status}"
86
+ end
87
+
88
+ # The name of the template that should be used as error page for this
89
+ # exception. By default, it calls the class method of the same name.
90
+ def template
91
+ self.class.template
92
+ end
93
+ end
94
+
95
+ # This function will install a rescue_from handler for HTTPStatus::Base
96
+ # exceptions in the class in which this module is included.
97
+ #
98
+ # <tt>base</tt>:: The class in which the module is included. Should be
99
+ # <tt>ActionController::Base</tt> during the initialization of the gem.
100
+ def self.included(base)
101
+ base.send(:rescue_from, HTTPStatus::Base, :with => :http_status_exception)
102
+ end
103
+
104
+ # Generates a <tt>HTTPStatus::Base</tt> subclass on demand based on the
105
+ # constant name. The constant name should correspond to one of the status
106
+ # symbols defined in <tt>ActionController::StatusCodes</tt>. The function
107
+ # will raise an exception if the constant name cannot be mapped onto one of
108
+ # the status symbols.
109
+ #
110
+ # This method will create a new subclass of <tt>HTTPStatus::Base</tt> and
111
+ # overrides the status class method of the class to return the correct
112
+ # status symbol.
113
+ #
114
+ # <tt>const</tt>:: The name of the missing constant, for which an exception
115
+ # class should be generated.
116
+ def self.const_missing(const)
117
+ status_symbol = const.to_s.underscore.to_sym
118
+ raise "Unrecognized HTTP Status name!" unless ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.has_key?(status_symbol)
119
+ klass = Class.new(HTTPStatus::Base)
120
+ klass.cattr_accessor(:status)
121
+ klass.status = status_symbol
122
+ const_set(const, klass)
123
+ return const_get(const)
124
+ end
125
+
126
+ # The default handler for raised HTTP status exceptions. It will render a
127
+ # template if available, or respond with an empty response with the HTTP
128
+ # status corresponding to the exception.
129
+ #
130
+ # You can override this method in your <tt>ApplicationController</tt> to
131
+ # handle the exceptions yourself.
132
+ #
133
+ # <tt>exception</tt>:: The HTTP status exception to handle.
134
+ def http_status_exception(exception)
135
+ @exception = exception
136
+ render_options = {:template => exception.template, :status => exception.status}
137
+ render_options[:layout] = exception.template_layout if exception.template_layout
138
+ render(render_options)
139
+ rescue ActionView::MissingTemplate
140
+ head(exception.status)
141
+ end
142
+ end
143
+
144
+ # Include the HTTPStatus module into <tt>ActionController::Base</tt> to enable
145
+ # the <tt>http_status_exception</tt> exception handler.
146
+ ActionController::Base.send(:include, HTTPStatus)
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe HTTPStatus::Base, 'class inheritance' do
4
+ before(:all) do
5
+ ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.stub!(:has_key?).with(:testing_status).and_return(true)
6
+ @status_exception_class = HTTPStatus::TestingStatus
7
+ end
8
+
9
+ after(:all) 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 use 'shared/http_status' as default view path" do
19
+ @status_exception_class.template.should == 'shared/http_status/testing_status'
20
+ end
21
+
22
+ it "should check ActionController's status code list for the status code based on the class name" do
23
+ ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE.should_receive(:[]).with(:testing_status)
24
+ @status_exception_class.status_code
25
+ end
26
+
27
+ it "should use the HTTPStatus::Base.template_path setting to determine the error template" do
28
+ HTTPStatus::Base.template_path = 'testing'
29
+ @status_exception_class.template.should == 'testing/testing_status'
30
+ end
31
+
32
+ it "should raise an exception when the class name does not correspond to a HTTP status code" do
33
+ lambda { HTTPStatus::Nonsense }.should raise_error
34
+ end
35
+ end
36
+
37
+ # Run some tests for different valid subclasses.
38
+ { 'NotFound' => 404, 'Forbidden' => 403, 'PaymentRequired' => 402, 'InternalServerError' => 500}.each do |status_class, status_code|
39
+
40
+ describe "HTTPStatus::#{status_class}" do
41
+ it "should generate the HTTPStatus::#{status_class} class successfully" do
42
+ lambda { HTTPStatus.const_get(status_class) }.should_not raise_error
43
+ end
44
+
45
+ it "should create a subclass of HTTPStatus::Base for the #{status_class.underscore.humanize.downcase} status" do
46
+ HTTPStatus.const_get(status_class).ancestors.should include(HTTPStatus::Base)
47
+ end
48
+
49
+ it "should return the correct status code (#{status_code}) when using the class" do
50
+ HTTPStatus.const_get(status_class).status_code.should == status_code
51
+ end
52
+
53
+ it "should return the correct status code (#{status_code}) when using the instance" do
54
+ HTTPStatus.const_get(status_class).new.status_code.should == status_code
55
+ end
56
+ end
57
+ end
58
+
59
+ describe 'HTTPStatus#http_status_exception' do
60
+ before(:each) { @controller = Class.new(ActionController::Base).new }
61
+ after(:each) { HTTPStatus::Base.template_layout = nil}
62
+
63
+ it "should create the :http_status_exception method in ActionController" do
64
+ @controller.should respond_to(:http_status_exception)
65
+ end
66
+
67
+ it "should call :http_status_exception when an exception is raised when handling the action" do
68
+ exception = HTTPStatus::Base.new('test')
69
+ @controller.stub!(:perform_action_without_rescue).and_raise(exception)
70
+ @controller.should_receive(:http_status_exception).with(exception)
71
+ @controller.send(:perform_action)
72
+ end
73
+
74
+ it "should call render with the correct view and correct HTTP status" do
75
+ @controller.should_receive(:render).with(hash_including(
76
+ :status => :internal_server_error, :template => "shared/http_status/internal_server_error"))
77
+
78
+ @controller.http_status_exception(HTTPStatus::Base.new('test'))
79
+ end
80
+
81
+ it "should not call render with a layout by default" do
82
+ @controller.should_not_receive(:render).with(hash_including(:layout => 'testing'))
83
+ @controller.http_status_exception(HTTPStatus::Base.new('test'))
84
+ end
85
+
86
+ it "should call render with a layout set when this property is set on the exception class" do
87
+ @controller.should_receive(:render).with(hash_including(:layout => 'testing'))
88
+ HTTPStatus::Base.template_layout = 'testing'
89
+ @controller.http_status_exception(HTTPStatus::Base.new('test'))
90
+ end
91
+
92
+ it "should call head with the correct status code if render cannot found a template" do
93
+ @controller.stub!(:render).and_raise(ActionView::MissingTemplate.new([], 'template.html.erb'))
94
+ @controller.should_receive(:head).with(:internal_server_error)
95
+ @controller.http_status_exception(HTTPStatus::Base.new('test'))
96
+ end
97
+ end
@@ -0,0 +1,17 @@
1
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
2
+
3
+ require 'rubygems'
4
+ require 'spec/autorun'
5
+
6
+ require 'action_controller'
7
+
8
+ require 'http_status_exceptions'
9
+
10
+ # Include all files in the spec_helper directory
11
+ Dir[File.dirname(__FILE__) + "/lib/**/*.rb"].each do |file|
12
+ require file
13
+ end
14
+
15
+ Spec::Runner.configure do |config|
16
+ # nothing special
17
+ end
@@ -0,0 +1,323 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/tasklib'
4
+ require 'date'
5
+ require 'git'
6
+
7
+ module GithubGem
8
+
9
+ # Detects the gemspc file of this project using heuristics.
10
+ def self.detect_gemspec_file
11
+ FileList['*.gemspec'].first
12
+ end
13
+
14
+ # Detects the main include file of this project using heuristics
15
+ def self.detect_main_include
16
+ if detect_gemspec_file =~ /^(\.*)\.gemspec$/ && File.exist?("lib/#{$1}.rb")
17
+ "lib/#{$1}.rb"
18
+ elsif FileList['lib/*.rb'].length == 1
19
+ FileList['lib/*.rb'].first
20
+ else
21
+ nil
22
+ end
23
+ end
24
+
25
+ class RakeTasks
26
+
27
+ attr_reader :gemspec, :modified_files, :git
28
+ attr_accessor :gemspec_file, :task_namespace, :main_include, :root_dir, :spec_pattern, :test_pattern, :remote, :remote_branch, :local_branch
29
+
30
+ # Initializes the settings, yields itself for configuration
31
+ # and defines the rake tasks based on the gemspec file.
32
+ def initialize(task_namespace = :gem)
33
+ @gemspec_file = GithubGem.detect_gemspec_file
34
+ @task_namespace = task_namespace
35
+ @main_include = GithubGem.detect_main_include
36
+ @modified_files = []
37
+ @root_dir = Dir.pwd
38
+ @test_pattern = 'test/**/*_test.rb'
39
+ @spec_pattern = 'spec/**/*_spec.rb'
40
+ @local_branch = 'master'
41
+ @remote = 'origin'
42
+ @remote_branch = 'master'
43
+
44
+ yield(self) if block_given?
45
+
46
+ @git = Git.open(@root_dir)
47
+ load_gemspec!
48
+ define_tasks!
49
+ end
50
+
51
+ protected
52
+
53
+ # Define Unit test tasks
54
+ def define_test_tasks!
55
+ require 'rake/testtask'
56
+
57
+ namespace(:test) do
58
+ Rake::TestTask.new(:basic) do |t|
59
+ t.pattern = test_pattern
60
+ t.verbose = true
61
+ t.libs << 'test'
62
+ end
63
+ end
64
+
65
+ desc "Run all unit tests for #{gemspec.name}"
66
+ task(:test => ['test:basic'])
67
+ end
68
+
69
+ # Defines RSpec tasks
70
+ def define_rspec_tasks!
71
+ require 'spec/rake/spectask'
72
+
73
+ namespace(:spec) do
74
+ desc "Verify all RSpec examples for #{gemspec.name}"
75
+ Spec::Rake::SpecTask.new(:basic) do |t|
76
+ t.spec_files = FileList[spec_pattern]
77
+ end
78
+
79
+ desc "Verify all RSpec examples for #{gemspec.name} and output specdoc"
80
+ Spec::Rake::SpecTask.new(:specdoc) do |t|
81
+ t.spec_files = FileList[spec_pattern]
82
+ t.spec_opts << '--format' << 'specdoc' << '--color'
83
+ end
84
+
85
+ desc "Run RCov on specs for #{gemspec.name}"
86
+ Spec::Rake::SpecTask.new(:rcov) do |t|
87
+ t.spec_files = FileList[spec_pattern]
88
+ t.rcov = true
89
+ t.rcov_opts = ['--exclude', '"spec/*,gems/*"', '--rails']
90
+ end
91
+ end
92
+
93
+ desc "Verify all RSpec examples for #{gemspec.name} and output specdoc"
94
+ task(:spec => ['spec:specdoc'])
95
+ end
96
+
97
+ # Defines the rake tasks
98
+ def define_tasks!
99
+
100
+ define_test_tasks! if has_tests?
101
+ define_rspec_tasks! if has_specs?
102
+
103
+ namespace(@task_namespace) do
104
+ desc "Updates the filelist in the gemspec file"
105
+ task(:manifest) { manifest_task }
106
+
107
+ desc "Builds the .gem package"
108
+ task(:build => :manifest) { build_task }
109
+
110
+ desc "Sets the version of the gem in the gemspec"
111
+ task(:set_version => [:check_version, :check_current_branch]) { version_task }
112
+ task(:check_version => :fetch_origin) { check_version_task }
113
+
114
+ task(:fetch_origin) { fetch_origin_task }
115
+ task(:check_current_branch) { check_current_branch_task }
116
+ task(:check_clean_status) { check_clean_status_task }
117
+ task(:check_not_diverged => :fetch_origin) { check_not_diverged_task }
118
+
119
+ checks = [:check_current_branch, :check_clean_status, :check_not_diverged, :check_version]
120
+ checks.unshift('spec:basic') if has_specs?
121
+ checks.unshift('test:basic') if has_tests?
122
+ checks.push << [:check_rubyforge] if gemspec.rubyforge_project
123
+
124
+ desc "Perform all checks that would occur before a release"
125
+ task(:release_checks => checks)
126
+
127
+ release_tasks = [:release_checks, :set_version, :build, :github_release]
128
+ release_tasks << [:rubyforge_release] if gemspec.rubyforge_project
129
+
130
+ desc "Release a new verison of the gem"
131
+ task(:release => release_tasks) { release_task }
132
+
133
+ task(:check_rubyforge) { check_rubyforge_task }
134
+ task(:rubyforge_release) { rubyforge_release_task }
135
+ task(:github_release => [:commit_modified_files, :tag_version]) { github_release_task }
136
+ task(:tag_version) { tag_version_task }
137
+ task(:commit_modified_files) { commit_modified_files_task }
138
+
139
+ desc "Updates the gem release tasks with the latest version on Github"
140
+ task(:update_tasks) { update_tasks_task }
141
+ end
142
+ end
143
+
144
+ # Updates the files list and test_files list in the gemspec file using the list of files
145
+ # in the repository and the spec/test file pattern.
146
+ def manifest_task
147
+ # Load all the gem's files using "git ls-files"
148
+ repository_files = git.ls_files.keys
149
+ test_files = Dir[test_pattern] + Dir[spec_pattern]
150
+
151
+ update_gemspec(:files, repository_files)
152
+ update_gemspec(:test_files, repository_files & test_files)
153
+ end
154
+
155
+ # Builds the gem
156
+ def build_task
157
+ sh "gem build -q #{gemspec_file}"
158
+ Dir.mkdir('pkg') unless File.exist?('pkg')
159
+ sh "mv #{gemspec.name}-#{gemspec.version}.gem pkg/#{gemspec.name}-#{gemspec.version}.gem"
160
+ end
161
+
162
+ # Updates the version number in the gemspec file, the VERSION constant in the main
163
+ # include file and the contents of the VERSION file.
164
+ def version_task
165
+ update_gemspec(:version, ENV['VERSION']) if ENV['VERSION']
166
+ update_gemspec(:date, Date.today)
167
+
168
+ update_version_file(gemspec.version)
169
+ update_version_constant(gemspec.version)
170
+ end
171
+
172
+ def check_version_task
173
+ raise "#{ENV['VERSION']} is not a valid version number!" if ENV['VERSION'] && !Gem::Version.correct?(ENV['VERSION'])
174
+ proposed_version = Gem::Version.new(ENV['VERSION'] || gemspec.version)
175
+ # Loads the latest version number using the created tags
176
+ newest_version = git.tags.map { |tag| tag.name.split('-').last }.compact.map { |v| Gem::Version.new(v) }.max
177
+ raise "This version (#{proposed_version}) is not higher than the highest tagged version (#{newest_version})" if newest_version && newest_version >= proposed_version
178
+ end
179
+
180
+ # Checks whether the current branch is not diverged from the remote branch
181
+ def check_not_diverged_task
182
+ raise "The current branch is diverged from the remote branch!" if git.log.between('HEAD', git.remote(remote).branch(remote_branch).gcommit).any?
183
+ end
184
+
185
+ # Checks whether the repository status ic clean
186
+ def check_clean_status_task
187
+ raise "The current working copy contains modifications" if git.status.changed.any?
188
+ end
189
+
190
+ # Checks whether the current branch is correct
191
+ def check_current_branch_task
192
+ raise "Currently not on #{local_branch} branch!" unless git.branch.name == local_branch.to_s
193
+ end
194
+
195
+ # Fetches the latest updates from Github
196
+ def fetch_origin_task
197
+ git.fetch('origin')
198
+ end
199
+
200
+ # Commits every file that has been changed by the release task.
201
+ def commit_modified_files_task
202
+ if modified_files.any?
203
+ modified_files.each { |file| git.add(file) }
204
+ git.commit("Released #{gemspec.name} gem version #{gemspec.version}")
205
+ end
206
+ end
207
+
208
+ # Adds a tag for the released version
209
+ def tag_version_task
210
+ git.add_tag("#{gemspec.name}-#{gemspec.version}")
211
+ end
212
+
213
+ # Pushes the changes and tag to github
214
+ def github_release_task
215
+ git.push(remote, remote_branch, true)
216
+ end
217
+
218
+ # Checks whether Rubyforge is configured properly
219
+ def check_rubyforge_task
220
+ # Login no longer necessary when using rubyforge 2.0.0 gem
221
+ # raise "Could not login on rubyforge!" unless `rubyforge login 2>&1`.strip.empty?
222
+ output = `rubyforge names`.split("\n")
223
+ raise "Rubyforge group not found!" unless output.any? { |line| %r[^groups\s*\:.*\b#{Regexp.quote(gemspec.rubyforge_project)}\b.*] =~ line }
224
+ raise "Rubyforge package not found!" unless output.any? { |line| %r[^packages\s*\:.*\b#{Regexp.quote(gemspec.name)}\b.*] =~ line }
225
+ end
226
+
227
+ # Task to release the .gem file toRubyforge.
228
+ def rubyforge_release_task
229
+ sh 'rubyforge', 'add_release', gemspec.rubyforge_project, gemspec.name, gemspec.version.to_s, "pkg/#{gemspec.name}-#{gemspec.version}.gem"
230
+ end
231
+
232
+ # Gem release task.
233
+ # All work is done by the task's dependencies, so just display a release completed message.
234
+ def release_task
235
+ puts
236
+ puts '------------------------------------------------------------'
237
+ puts "Released #{gemspec.name} version #{gemspec.version}"
238
+ end
239
+
240
+ private
241
+
242
+ # Checks whether this project has any RSpec files
243
+ def has_specs?
244
+ FileList[spec_pattern].any?
245
+ end
246
+
247
+ # Checks whether this project has any unit test files
248
+ def has_tests?
249
+ FileList[test_pattern].any?
250
+ end
251
+
252
+ # Loads the gemspec file
253
+ def load_gemspec!
254
+ @gemspec = eval(File.read(@gemspec_file))
255
+ end
256
+
257
+ # Updates the VERSION file with the new version
258
+ def update_version_file(version)
259
+ if File.exists?('VERSION')
260
+ File.open('VERSION', 'w') { |f| f << version.to_s }
261
+ modified_files << 'VERSION'
262
+ end
263
+ end
264
+
265
+ # Updates the VERSION constant in the main include file if it exists
266
+ def update_version_constant(version)
267
+ if main_include && File.exist?(main_include)
268
+ file_contents = File.read(main_include)
269
+ if file_contents.sub!(/^(\s+VERSION\s*=\s*)[^\s].*$/) { $1 + version.to_s.inspect }
270
+ File.open(main_include, 'w') { |f| f << file_contents }
271
+ modified_files << main_include
272
+ end
273
+ end
274
+ end
275
+
276
+ # Updates an attribute of the gemspec file.
277
+ # This function will open the file, and search/replace the attribute using a regular expression.
278
+ def update_gemspec(attribute, new_value, literal = false)
279
+
280
+ unless literal
281
+ new_value = case new_value
282
+ when Array then "%w(#{new_value.join(' ')})"
283
+ when Hash, String then new_value.inspect
284
+ when Date then new_value.strftime('%Y-%m-%d').inspect
285
+ else raise "Cannot write value #{new_value.inspect} to gemspec file!"
286
+ end
287
+ end
288
+
289
+ spec = File.read(gemspec_file)
290
+ regexp = Regexp.new('^(\s+\w+\.' + Regexp.quote(attribute.to_s) + '\s*=\s*)[^\s].*$')
291
+ if spec.sub!(regexp) { $1 + new_value }
292
+ File.open(gemspec_file, 'w') { |f| f << spec }
293
+ modified_files << gemspec_file
294
+
295
+ # Reload the gemspec so the changes are incorporated
296
+ load_gemspec!
297
+ end
298
+ end
299
+
300
+ # Updates the tasks file using the latest file found on Github
301
+ def update_tasks_task
302
+ require 'net/http'
303
+
304
+ server = 'github.com'
305
+ path = '/wvanbergen/github-gem/raw/master/tasks/github-gem.rake'
306
+
307
+ Net::HTTP.start(server) do |http|
308
+ response = http.get(path)
309
+ open(__FILE__, "w") { |file| file.write(response.body) }
310
+ end
311
+
312
+ relative_file = File.expand_path(__FILE__).sub(%r[^#{git.dir.path}/], '')
313
+ if git.status[relative_file] && git.status[relative_file].type == 'M'
314
+ git.add(relative_file)
315
+ git.commit("Updated to latest gem release management tasks.")
316
+ puts "Updated to latest version of gem release management tasks."
317
+ else
318
+ puts "Release managament tasks already are at the latest version."
319
+ end
320
+ end
321
+
322
+ end
323
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_status_exceptions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.9
5
+ platform: ruby
6
+ authors:
7
+ - Willem van Bergen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-01 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: actionpack
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.1.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: Clean up your controller code by raising exceptions that generate responses with different HTTP status codes.
36
+ email:
37
+ - willem@vanbergen.org
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - spec/spec_helper.rb
46
+ - http_status_exceptions.gemspec
47
+ - .gitignore
48
+ - init.rb
49
+ - lib/http_status_exceptions.rb
50
+ - Rakefile
51
+ - MIT-LICENSE
52
+ - tasks/github-gem.rake
53
+ - README.rdoc
54
+ - spec/http_status_exception_spec.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/wvanbergen/http_status_exceptions/wikis
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.5
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: A Rails plugin to use exceptions for generating HTTP status responses
83
+ test_files:
84
+ - spec/http_status_exception_spec.rb