contingency 0.1.3

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.
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: