contingency 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 21458e2b0634b9e68a901d2008418bbae490fdfe
4
+ data.tar.gz: c590972c7818e0f7c06dc2227fe72d3b78124f1c
5
+ SHA512:
6
+ metadata.gz: b41aa57923b2beeb99aa025f72cf65b6805f26e071565649c6be14eb5e7c9806f82d570acce03d1fc411e1cbf0fb472f28b31e2c663d719cde0b6cc951018fe5
7
+ data.tar.gz: c3871c5eeb363b533472ec76c6c6d3eec1cd94b23afd650d0fb62fc00219e9602dc74aae6663e0a6436475ddd75e84278cb38cfd9e11e527e43335c3256a24cb
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in contingency.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Christopher Keele
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,204 @@
1
+ <a name='contingency'>
2
+ # Contingency
3
+ </a>
4
+
5
+ > "Freedom is the recognition of contingency."
6
+
7
+ > * *Richard M. Rorty*
8
+
9
+ Contingency is the custom error page controller you've implemented in every project you've ever written. It's compatibile with every framework you've ever implemented a project in. A [Contingency Plan](#supported-integrations) has been written for every Ruby framework you're familiar with. And odds are, its better tested than your implementation.
10
+
11
+ So for the love of god, stop implementing it yourself.
12
+
13
+ It's quick to get started, gives you full customization over Exception coverage, gives you full control over rendering your own error page, and has a contingency plan itself in the event that your custom error views trigger an Exception.
14
+
15
+ It's also very lightweight: the core functionality (the module in `contingency/plan.rb`) is less than 50 lines; and only adds 3 integration methods, 2 helper methods, and 1 controller action method to your controller. Everything but the controller method is private. The rest of the codebase else is just a matter of integration. It's a hard codebase to get lost in.
16
+
17
+ Experience true freedom, and make yourself a Contingency Plan.
18
+
19
+ <a name='table-of-contents'>
20
+ ## Table of Contents
21
+ </a>
22
+
23
+ * [Installation](#installation)
24
+ * [Configuration](#configuration)
25
+ * [Supported Integrations](#supported-integrations)
26
+ * [Rails](#rails-integration)
27
+ * [Custom Integrations](#custom-integrations)
28
+ * [Integrating Contingency Yourself](#integrating-contingency-yourself)
29
+ * [Integration Dependencies](#three-integration-methods)
30
+ * [Versioning](#versioning)
31
+ * [Contingency Versioning](#contingency-versioning)
32
+ * [Integration Versioning](#contingency-integration-versioning)
33
+ * [Contributing Integrations](#contributing-integrations)
34
+ * [Contributing to Contingency](#contributing-to-contingency)
35
+ * [Credits](#credits)
36
+ * [Contributers](#contributers)
37
+ * [Shout-Outs](#shout-outs)
38
+
39
+ <a name='installation'>
40
+ ## Installation
41
+ </a>
42
+
43
+ Add these lines to your application's Gemfile:
44
+
45
+ gem 'contingency', '~> 1.0'
46
+ gem 'contingency_my-framework-name', '~> x.0'
47
+
48
+ ...where [my-framework-name](#supported-integrations) is the name of your framework.
49
+
50
+ Then, execute:
51
+
52
+ $ bundle
53
+
54
+ <a name='configuration'>
55
+ ## Configuration
56
+ </a>
57
+
58
+ Contingency
59
+
60
+ <a name='supported-integrations'>
61
+ ## Supported Integrations
62
+ </a>
63
+
64
+ <table>
65
+ <thead>
66
+ <tr>
67
+ <td>Contingency Plan</td>
68
+ <td>Integration Quality</td>
69
+ <td>Version</td>
70
+ <td>Maintainer</td>
71
+ </tr>
72
+ </thead>
73
+ <tbody>
74
+ <tr>
75
+ <td>
76
+ <a href='#rails-integration'>Rails</a>
77
+ </td>
78
+ <td>
79
+ <a href='#poor-dependency-management'>Poor</a>
80
+ </td>
81
+ <td>
82
+ <a href='https://www.github.com/christhekeele/contingency_rails'>0.0.1</a>
83
+ </td>
84
+ <td>
85
+ <a href='https://www.github.com/christhekeele/contingency_rails/issues'>christhekeele</a>
86
+ </td>
87
+ </tr>
88
+ </tbody>
89
+ </table>
90
+
91
+ <a name='rails-integration'>
92
+ ### Rails
93
+ </a>
94
+
95
+ <a name='custom-integrations'>
96
+ ## Custom Integrations
97
+ </a>
98
+
99
+ If the framework you're using doesn't have a Contingency Plan integration, you're only 3 methods away from integrating it yourself.
100
+
101
+ <a name='integrating-contingency-yourself'>
102
+ ### Integrating it Yourself
103
+ </a>
104
+
105
+ It's easy to integrate Contingency into your own app. Contingency only relys on 3 methods to communicate with your framework:
106
+
107
+ <a name='three-integration-methods'>
108
+ #### Integration Dependencies
109
+ </a>
110
+
111
+ <a name='for-the-love-of-god-contribute'>
112
+ </a>
113
+
114
+ If you decide to go through this trouble, you really should consider [contributing your Contingency Plan integration](#contributing-integrations) to Contingency.</a> I'll be more than happy to help you develop your integration until [it meets our minimum quality standards](#versioning), if it doesn't out-of-the-box.
115
+
116
+ <a name='versioning'>
117
+ ## Versioning
118
+ </a>
119
+
120
+ <a name='contingency-versioning'>
121
+ ### Contingency Versioning
122
+ </a>
123
+
124
+ Contingency itself is versioned as it changes. It bumps its major version as its API changes, which is rarely, as its public API only requires [3 methods](#three-integration-methods). It uses [symantic versioning](http://http://semver.org/). This means you should safely be able to install it with [loose bundler dependencies](#installation).
125
+
126
+ <a name='contingency-integration-versioning'>
127
+ ### Integration Versioning
128
+ </a>
129
+
130
+ <a name='great-dependency-management'>
131
+ #### Great
132
+ </a>
133
+
134
+ Contingency Plans should be versioned [with their frameworks](#supported-integrations). Integrations that follow this simple requirement are labeled as [**great**](#supported-integrations).
135
+
136
+ <a name='good-dependency-management'>
137
+ #### Good
138
+ </a>
139
+
140
+ Contingency Plans that keep up with at least [the major version of their framework](http://http://semver.org/) will result in the integration being labeled as [**good**](#supported-integrations).
141
+
142
+ <a name='poor-dependency-management'>
143
+ #### Poor
144
+ </a>
145
+
146
+ Contingency Plans that fail to keep up with [the major version of their framework](http://http://semver.org/) will result in the integration being labeled as [**poor**](#supported-integrations).
147
+
148
+ <a name='bad-dependency-management'>
149
+ #### Bad
150
+ </a>
151
+
152
+ Contingency Plans that throw off the shackles of [symantic versioning](http://http://semver.org/) and don't follow it from the get-go, Pull Request, or fall very behind will result in the integration being labeled as [**bad**](#supported-integrations).
153
+
154
+ I keep up with these frameworks through [the Bundle Scout](https://bundlescout.com). You should, too! **Checkest thineself lest thy wrekest thineself**.
155
+
156
+ <a name='contributing-integrations'>
157
+ ## Contributing Integrations
158
+ </a>
159
+
160
+ See [contingency_rails](https://www.github.com/christhekeele/contingency_rails) as an example.
161
+
162
+ 1. Create a new gem named after your framework (`bundle gem contingency-my_integration`)
163
+ 1. Add Contingency as a dependency to your gemspec and bundle install
164
+ 1. Generate an integration template (`bundle exec rake contingency:generate:plan[my_integration]`)
165
+ 1. Implement the 3 methods that rake instructs you to
166
+ 1. Commit your changes (`git commit -am 'Created my_integration'`)
167
+ 1. Push (`git push origin master`)
168
+ 1. Follow [the steps below](#contributing-to-contingency) to add autoloading your Contingency Plan in Contingency core and wait get your Pull Request accepted
169
+ 1. Create the intital build of your gem (`gem build contingency-my_integration`)
170
+ 1. Release your gem (`gem push contingency-my_integration.gem`)
171
+ 1. Revel in the fact that you've provided a Contingency Plan for you and yours
172
+ 1. Continue to mantain your integration over time by [handling API changes and bumping the version number in accordance with the framework](#versioning), lest your integration be marked as deprecated.
173
+
174
+
175
+ <a name='contributing-to-contingency'>
176
+ ## Contributing to Contingency
177
+ </a>
178
+
179
+ 1. Fork it
180
+ 1. Create your feature branch (`git checkout -b my-new-feature`)
181
+ 1. Add the name of your integration to the integrations array in the contingency/integration.rb file if [you're contributing a Contingency Plan](#contributing-integrations)
182
+ 1. Commit your changes (`git commit -am 'Add some feature'`)
183
+ 1. Push to the branch (`git push origin my-new-feature`)
184
+ 1. Create new Pull Request
185
+ 1. I tell you to go back and write some tests if you haven't already
186
+ 1. I tell you to go back and update the README.md if you haven't already
187
+ 1. I accept your Pull Request
188
+
189
+ <a name='credits'>
190
+ ## Credits
191
+ </a>
192
+
193
+ <a name='contributers'>
194
+ ### Contributers
195
+ </a>
196
+
197
+ * None, aside from [the creator](https://www.github.com/christhekeele/contingency). [Be the first!](#contributing-to-contingency)!
198
+
199
+ <a name='shout-outs'>
200
+ ### Shout-Outs
201
+ </a>
202
+
203
+ * Thanks to [nathanl](https://github.com/nathanl) and his excellent authorization gem, [Authority](https://github.com/nathanl/authority), the structure of which inspired this one.
204
+ * Thanks to [ryanb](https://github.com/ryanb), and his subscription-worthy [Railscasts](http://railscasts.com/), which have inspired us all. Especially us [Pro users](http://railscasts.com/pro).
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'contingency/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "contingency"
8
+ spec.version = Contingency::VERSION
9
+ spec.authors = ["Christopher Keele"]
10
+ spec.email = ["dev@chriskeele.com"]
11
+ spec.description = "A framework agnostic exception catcher and custom error page generator."
12
+ spec.summary = "Handle your ruby web application's errors your way, with your own beautiful customized error pages. Framework agnostic with several integrations and i18n support."
13
+ # spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport", ">= 3.0.0"
22
+ spec.add_dependency "i18n", ">= 0.6.0"
23
+ spec.add_dependency "rake", ">= 0.8.1.10"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rspec", "~> 2.13"
27
+ end
@@ -0,0 +1,37 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/rescuable'
3
+ require 'logger'
4
+ require "contingency/exceptions"
5
+ require "contingency/adapters/interface"
6
+
7
+ module Contingency
8
+
9
+ class << self
10
+ alias :configure :initialize
11
+ attr_accessor :configuration
12
+ attr_accessor :adapter, :adapters
13
+ end
14
+
15
+ self.adapters = []
16
+
17
+ def self.configure
18
+ self.adapter ||= self.adapters.first || Adapters::Interface
19
+ self.configuration ||= Configuration.new
20
+
21
+ yield(self.adapter.default_configuration) if self.adapter.respond_to?(:default_configuration)
22
+ yield(configuration) if block_given?
23
+
24
+ require "contingency/plan"
25
+
26
+ configuration
27
+ end
28
+
29
+ def self.logger
30
+ @logger ||= configuration.logger
31
+ end
32
+
33
+
34
+ end
35
+
36
+ require "contingency/configuration"
37
+ require "contingency/version"
@@ -0,0 +1,48 @@
1
+ module Contingency
2
+
3
+ module Adapters
4
+ module Interface
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class InterfaceNotImplementedError < NotImplementedError; end
10
+ end
11
+
12
+ ###
13
+ # Required integration methods go here.
14
+ # They're implemented here as no-ops that raise an error so
15
+ # all subclasses have to define them.
16
+ #
17
+
18
+ module ClassMethods
19
+ def catch_errors?
20
+ raise InterfaceNotImplementedError, "Override this `catch_errors?` method" \
21
+ " with one that decides if your framework should activate" \
22
+ " Contingency or not (ie `ENV[RACK_ENV] !== 'development'`)."
23
+ end
24
+ end
25
+
26
+ module InstanceMethods
27
+ def error_renderer(code)
28
+ raise InterfaceNotImplementedError, "Override this `error_renderer` method" \
29
+ " with one that expects an error code, and uses your framework's" \
30
+ " render method to find your views for it." \
31
+ " (ie `render Contingency.configuration.error_template, status: code`," \
32
+ " or even just `render code`)"
33
+ end
34
+
35
+ def failure_renderer(code)
36
+ raise InterfaceNotImplementedError, "Override this `failure_renderer` method" \
37
+ " with one that expects an error code, and uses your framework's" \
38
+ " render method to display a simple text error page in the event" \
39
+ " your `#{self.class.name}#error_renderer?`'s render can't render" \
40
+ " your error template." \
41
+ " (ie `render status: code, text: Contingency.configuration.error_template`)"
42
+
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ module Contingency
2
+ class Configuration
3
+
4
+ attr_accessor :errors, :error_messages,
5
+ :error_layout, :error_template,
6
+ :unknown_error_message, :failure_message,
7
+ :logger
8
+
9
+ def initialize
10
+ @errors = {}
11
+ @error_messages = {}
12
+
13
+ @error_layout = ''
14
+ @error_template = ''
15
+
16
+ @unknown_error_message = ['Server Error', 'It looks like something went wrong.']
17
+ @failure_message = "Server Error: It looks like something went wrong."
18
+
19
+ @logger = Logger.new(STDERR)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module Contingency
2
+ module Exceptions
3
+ class ContingencyError < Exception
4
+ attr_accessor :message, :backtrace
5
+ end
6
+ class RenderedErrorPageException < ContingencyError
7
+ def initialize
8
+ @message = 'An error page was explicitly requested.'
9
+ @backtrace = ['None. No real error occured.']
10
+ end
11
+ end
12
+ class ContingencyPlanException < ContingencyError
13
+ def initialize(original_exception, handler_exception)
14
+ @message = "`Contingency::Plan` encountered exception `#{handler_exception.class.name}`" \
15
+ " while trying to handle exception `#{original_exception.class.name}`:" \
16
+ "\n#{handler_exception.message}"
17
+ @backtrace = handler_exception.backtrace
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ module Contingency
2
+
3
+ module Plan
4
+ extend ActiveSupport::Concern
5
+ extend ActiveSupport::Rescuable
6
+
7
+
8
+ included do
9
+ extend Contingency.adapter
10
+
11
+ if catch_errors?
12
+ Contingency.configuration.errors.each do |code, exceptions|
13
+ rescue_from *exceptions, with: ->(exception){ render_error code, exception }
14
+ end
15
+ end
16
+ end
17
+
18
+ def error
19
+ render_error(params[:code], Contingency::Exceptions::RenderedErrorPageException.new)
20
+ end
21
+
22
+ def error_report(exception)
23
+ "#{exception.class} raised on #{request.fullpath}:" \
24
+ "\n#{exception.message}" \
25
+ "\nBacktrace:" \
26
+ "\n#{exception.backtrace.join("\n")}"
27
+ end
28
+
29
+ def render_error(code, exception)
30
+ message, description = Contingency.configuration.error_messages.fetch(code, Contingency.configuration.unknown_error_message)
31
+ error_logger = logger.method(code.to_i < 500 ? :info : :error)
32
+ error_logger.call "#{code}: #{description}.\n" + error_report(exception)
33
+ @code = code
34
+ @message = message
35
+ @description = description
36
+ error_renderer(code)
37
+ rescue Exception => handler_exception
38
+ logger.fatal error_report(Contingency::Exceptions::ContingencyPlanException.new(exception, handler_exception))
39
+ failure_renderer(500)
40
+ end
41
+ end
42
+
43
+ end
@@ -0,0 +1,3 @@
1
+ module Contingency
2
+ VERSION = "0.1.3"
3
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: contingency
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Christopher Keele
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: i18n
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.8.1.10
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.8.1.10
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '2.13'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '2.13'
83
+ description: A framework agnostic exception catcher and custom error page generator.
84
+ email:
85
+ - dev@chriskeele.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - .gitignore
91
+ - Gemfile
92
+ - LICENSE.txt
93
+ - README.md
94
+ - Rakefile
95
+ - contingency.gemspec
96
+ - lib/contingency.rb
97
+ - lib/contingency/adapters/interface.rb
98
+ - lib/contingency/configuration.rb
99
+ - lib/contingency/exceptions.rb
100
+ - lib/contingency/plan.rb
101
+ - lib/contingency/version.rb
102
+ homepage:
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.0.0
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: Handle your ruby web application's errors your way, with your own beautiful
126
+ customized error pages. Framework agnostic with several integrations and i18n support.
127
+ test_files: []
128
+ has_rdoc: