temescal 0.1.0
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 +7 -0
- data/LICENSE +20 -0
- data/README.md +53 -0
- data/Rakefile +5 -0
- data/lib/temescal.rb +6 -0
- data/lib/temescal/configuration.rb +54 -0
- data/lib/temescal/middleware.rb +55 -0
- data/lib/temescal/monitors.rb +35 -0
- data/lib/temescal/response.rb +25 -0
- data/lib/temescal/version.rb +3 -0
- data/spec/lib/temescal/configuration_spec.rb +25 -0
- data/spec/lib/temescal/middleware_spec.rb +112 -0
- data/spec/lib/temescal/monitors_spec.rb +29 -0
- data/spec/spec_helper.rb +29 -0
- data/temescal.gemspec +22 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 668a0e9c9bb3d5400a4b9b28302607767828bc0c
|
4
|
+
data.tar.gz: 1f1a62d3e48d5db8cd32b853a06ea116be8a3b69
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 614f71816ca80c27852abe47a8aef37702fc8eced6143613ed25735dd1bc3bc051a7e9d4f4dd1eefb1709aedc6537191354abaab13a837cc57bbc70469f91564
|
7
|
+
data.tar.gz: 1bf5f51abe2f31d8e2cd7b8595f97c4d6a86083f99d34f1d800e7e96495de41bae2017b62ec1bb6b7f1ced4a8ccf4fd04062b7c7ea7edde87484a2fd3c0799e9
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013-2014 Todd Bealmear
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
temescal
|
2
|
+
========
|
3
|
+
|
4
|
+
[](https://travis-ci.org/todd/temescal) [](https://coveralls.io/r/todd/temescal?branch=master) [](https://codeclimate.com/github/todd/temescal) [](https://gemnasium.com/todd/temescal)
|
5
|
+
|
6
|
+
Temescal is Rack middleware that will automatically rescue exceptions for JSON APIs and render a nice, clean JSON response with the error information. No need to write custom error handling logic for your apps - Temescal will take care of it for you!
|
7
|
+
## Getting Started
|
8
|
+
Add the gem to your Gemfile and run `bundle install`:
|
9
|
+
```
|
10
|
+
gem 'temescal'
|
11
|
+
```
|
12
|
+
Since Temescal is just Rack middleware, adding it to your application is super easy. For Rails, add an initializer:
|
13
|
+
```ruby
|
14
|
+
Rails.application.config.middleware.use Temescal::Middleware do |config|
|
15
|
+
config.monitors = :airbrake, :new_relic
|
16
|
+
config.default_message = "Oops! Something went kablooey!"
|
17
|
+
end
|
18
|
+
```
|
19
|
+
For Sinatra:
|
20
|
+
```ruby
|
21
|
+
use Temescal::Middleware do |config|
|
22
|
+
config.monitors = :airbrake, :new_relic
|
23
|
+
config.default_message = "Oops! Something went kablooey!"
|
24
|
+
end
|
25
|
+
```
|
26
|
+
## Default Behavior
|
27
|
+
By default, Temescal will render a JSON response formatted as such (using StandardError with a message of "Foobar" as an example):
|
28
|
+
```json
|
29
|
+
{
|
30
|
+
meta: {
|
31
|
+
status: 500,
|
32
|
+
error: "StandardError",
|
33
|
+
message: "Foobar"
|
34
|
+
}
|
35
|
+
}
|
36
|
+
```
|
37
|
+
Temescal will also log the error for you through STDERR.
|
38
|
+
## Monitors
|
39
|
+
Though Temescal will log an error for you, it won't necessarily be picked up by your monitoring solution of choice in a production environment. Luckily, Temescal provides integration with popular monitoring services. At the moment, only two (Airbrake, New Relic) are supported, but more will be added if there's a need. If you use a different monitoring service that you'd like to see supported, pull requests are more than welcome!
|
40
|
+
|
41
|
+
Note that you'll need the gem for your monitor installed and configured for your application in order for Temescal to properly work with it.
|
42
|
+
|
43
|
+
## Configuration
|
44
|
+
Temescal provides several configuration options for you. You can set these options when configuring the middleware for your application.
|
45
|
+
|
46
|
+
`monitors` to set the monitors you'd like to use with Temescal. It takes symbols of monitor names (currently `:airbrake` and `:new_relic`).
|
47
|
+
|
48
|
+
`raise_errors` to set whether you'd like to override Temescal and raise all errors without rendering a Temescal response. Set to `true` to enable.
|
49
|
+
|
50
|
+
`default_message` to set an all-encompasing message to use in responses instead of the exception's message. Takes a string.
|
51
|
+
|
52
|
+
## License
|
53
|
+
Copyright 2013-2014 Todd Bealmear. See LICENSE for details.
|
data/Rakefile
ADDED
data/lib/temescal.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module Temescal
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
# Public: Getter for monitors array.
|
5
|
+
attr_reader :monitors
|
6
|
+
|
7
|
+
# Public: Setter for raise_errors option.
|
8
|
+
attr_writer :raise_errors
|
9
|
+
|
10
|
+
# Public: Getter/Setter for default JSON message.
|
11
|
+
attr_accessor :default_message
|
12
|
+
|
13
|
+
# Public: Initializes configuration and monitors option.
|
14
|
+
#
|
15
|
+
# Returns a new Configuration object.
|
16
|
+
def initialize
|
17
|
+
@monitors = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Public: Setter for monitors option.
|
21
|
+
#
|
22
|
+
# monitors - Zero or more Symbols representing monitoring services
|
23
|
+
# supported by Temescal.
|
24
|
+
#
|
25
|
+
# Raises NameError if a monitor Symbol is invalid.
|
26
|
+
def monitors=(*monitors)
|
27
|
+
monitors.flatten.each do |monitor|
|
28
|
+
monitor = camelize_symbol(monitor)
|
29
|
+
@monitors << Temescal::Monitors.const_get(monitor)
|
30
|
+
end
|
31
|
+
|
32
|
+
rescue NameError => exception
|
33
|
+
strategy = exception.message.split(" ").last
|
34
|
+
raise NameError.new("#{strategy} is not a valid monitoring strategy")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Public: Getter for raise_errors.
|
38
|
+
#
|
39
|
+
# Returns true if raise_errors is configured to true or the application is
|
40
|
+
# running in a test environment, false otherwise.
|
41
|
+
def raise_errors?
|
42
|
+
@raise_errors == true || ENV["RACK_ENV"] == "test"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Private: Converts a snake cased Symbol to a camel cased String.
|
48
|
+
#
|
49
|
+
# Returns the converted String.
|
50
|
+
def camelize_symbol(symbol)
|
51
|
+
symbol.to_s.split(/_/).map { |word| word.capitalize }.join
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Temescal
|
2
|
+
class Middleware
|
3
|
+
|
4
|
+
# Public: Initializes the middleware.
|
5
|
+
#
|
6
|
+
# app - The Rack application.
|
7
|
+
# block - Optional block for configuring the middleware.
|
8
|
+
#
|
9
|
+
# Returns an instance of the middleware.
|
10
|
+
def initialize(app, &block)
|
11
|
+
@app = app
|
12
|
+
yield(configuration) if block
|
13
|
+
end
|
14
|
+
|
15
|
+
# Public: call method for Rack application. Rescues from an exception and
|
16
|
+
# does the following: 1) Logs the error 2) Reports error to configured
|
17
|
+
# monitoring services 3) Generates a JSON response with error information.
|
18
|
+
#
|
19
|
+
# env - The environment of the request.
|
20
|
+
#
|
21
|
+
# Returns an array of response data for Rack.
|
22
|
+
def call(env)
|
23
|
+
begin
|
24
|
+
@status, @headers, @response = @app.call(env)
|
25
|
+
rescue => error
|
26
|
+
raise if configuration.raise_errors?
|
27
|
+
|
28
|
+
@error = error
|
29
|
+
message = configuration.default_message || @error.message
|
30
|
+
|
31
|
+
$stderr.print formatted_error
|
32
|
+
configuration.monitors.each { |monitor| monitor.report(@error) }
|
33
|
+
|
34
|
+
@status = @error.respond_to?(:http_status) ? @error.http_status : 500
|
35
|
+
@response = Response.build(@status, @error, message)
|
36
|
+
@headers = { "Content-Type" => "application/json" }
|
37
|
+
end
|
38
|
+
[@status, @headers, @response]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Private: Getter for middleware configuration.
|
44
|
+
def configuration
|
45
|
+
@_configuration ||= Configuration.new
|
46
|
+
end
|
47
|
+
|
48
|
+
# Private: Formats the exception for logging.
|
49
|
+
def formatted_error
|
50
|
+
message = "\n#{@error.class}: #{@error.message}\n "
|
51
|
+
message << @error.backtrace.join("\n ")
|
52
|
+
message << "\n\n"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Temescal
|
2
|
+
|
3
|
+
# Public: Collection of reporting strategies for different monitoring
|
4
|
+
# services.
|
5
|
+
module Monitors
|
6
|
+
|
7
|
+
# Public: Abstract strategy for monitor reporting strategies.
|
8
|
+
class MonitorsStrategy
|
9
|
+
# Raises NotImplementedError
|
10
|
+
def self.report(exception)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Public: Reporting strategy for Airbrake.
|
16
|
+
class Airbrake < MonitorsStrategy
|
17
|
+
# Public: Reports an exception to Airbrake.
|
18
|
+
#
|
19
|
+
# exception - The caught exception.
|
20
|
+
def self.report(exception)
|
21
|
+
::Airbrake.notify exception
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public: Reporting strategy for New Relic.
|
26
|
+
class NewRelic < MonitorsStrategy
|
27
|
+
# Public: Reports an exception to New Relic.
|
28
|
+
#
|
29
|
+
# exception - The caught exception.
|
30
|
+
def self.report(exception)
|
31
|
+
::NewRelic::Agent.notice_error exception
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Temescal
|
4
|
+
module Response
|
5
|
+
|
6
|
+
# Public: Builds a response body for the Rack response.
|
7
|
+
#
|
8
|
+
# status - The HTTP status code of the response.
|
9
|
+
# exception - The caught exception.
|
10
|
+
# message - The error message.
|
11
|
+
#
|
12
|
+
# Returns an Array containing a JSON string as the response body.
|
13
|
+
def self.build(status, exception, message)
|
14
|
+
[
|
15
|
+
{
|
16
|
+
meta: {
|
17
|
+
status: status,
|
18
|
+
error: exception.class.to_s,
|
19
|
+
message: message
|
20
|
+
}
|
21
|
+
}.to_json
|
22
|
+
]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class Temescal::Monitors::Monitor; end
|
4
|
+
class Temescal::Monitors::FakeMonitor; end
|
5
|
+
class Temescal::Monitors::FooMonitor; end
|
6
|
+
|
7
|
+
describe Temescal::Configuration do
|
8
|
+
let(:config) { Temescal::Configuration.new }
|
9
|
+
|
10
|
+
context "#monitors=" do
|
11
|
+
it "should add a list of valid monitor classes to the monitors array from snake-cased arguments" do
|
12
|
+
config.monitors = :monitor, :fake_monitor, :foo_monitor
|
13
|
+
|
14
|
+
expect(config.monitors).to eq [
|
15
|
+
Temescal::Monitors::Monitor,
|
16
|
+
Temescal::Monitors::FakeMonitor,
|
17
|
+
Temescal::Monitors::FooMonitor
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise an error if a monitor strategy is invalid" do
|
22
|
+
expect { config.monitors = :foo }.to raise_error(NameError, /Foo is not a valid monitoring strategy/)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Temescal::Middleware do
|
4
|
+
context "Ok response" do
|
5
|
+
let(:app) { ->(env) { [200, env, "app" ] } }
|
6
|
+
|
7
|
+
let(:middleware) do
|
8
|
+
Temescal::Middleware.new(app)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should render the application's response" do
|
12
|
+
code, _, _ = middleware.call env_for('http://foobar.com')
|
13
|
+
|
14
|
+
expect(code).to eq 200
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "Bad response" do
|
19
|
+
before do
|
20
|
+
Temescal::Monitors::NewRelic.stub(:report)
|
21
|
+
$stderr.stub(:print)
|
22
|
+
|
23
|
+
# Travis automatically sets RACK_ENV=test
|
24
|
+
# Need to override for tests to run correctly.
|
25
|
+
ENV["RACK_ENV"] = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:app) { ->(env) { raise StandardError.new("Foobar") } }
|
29
|
+
|
30
|
+
let(:middleware) do
|
31
|
+
Temescal::Middleware.new(app) do |config|
|
32
|
+
config.monitors = :new_relic
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should respond with a 500 if the exception does not have a http_status attribute" do
|
37
|
+
code, _, _ = middleware.call env_for("http://foobar.com")
|
38
|
+
|
39
|
+
expect(code).to eq 500
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should respond with the appropriate status if the exception has a http_status attribute" do
|
43
|
+
StandardError.any_instance.stub(:http_status).and_return(403)
|
44
|
+
|
45
|
+
code, _, _ = middleware.call env_for("http://foobar.com")
|
46
|
+
|
47
|
+
expect(code).to eq 403
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should set the correct content type header" do
|
51
|
+
_, headers, _ = middleware.call env_for("http://foobar.com")
|
52
|
+
|
53
|
+
expect(headers["Content-Type"]).to eq "application/json"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should render a JSON response for the error" do
|
57
|
+
_, _, response = middleware.call env_for("http://foobar.com")
|
58
|
+
|
59
|
+
json = JSON.parse(response.first)["meta"]
|
60
|
+
expect(json["status"]).to eq 500
|
61
|
+
expect(json["error"]).to eq "StandardError"
|
62
|
+
expect(json["message"]).to eq "Foobar"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should log the error" do
|
66
|
+
expect($stderr).to receive(:print).with(an_instance_of String)
|
67
|
+
|
68
|
+
middleware.call env_for("http://foobar.com")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should report the error to the specified monitors" do
|
72
|
+
expect(Temescal::Monitors::NewRelic).to receive(:report).with(an_instance_of StandardError)
|
73
|
+
|
74
|
+
middleware.call env_for("http://foobar.com")
|
75
|
+
end
|
76
|
+
|
77
|
+
context "with default_message set" do
|
78
|
+
it "should build a response with the specified message instead of the exception message" do
|
79
|
+
middleware = Temescal::Middleware.new(app) do |config|
|
80
|
+
config.default_message = "An error has occured - we'll get on it right away!"
|
81
|
+
end
|
82
|
+
|
83
|
+
_, _, response = middleware.call env_for("http://foobar.com")
|
84
|
+
|
85
|
+
json = JSON.parse(response.first)["meta"]
|
86
|
+
expect(json["message"]).to eq "An error has occured - we'll get on it right away!"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "Override middleware to raise exception" do
|
92
|
+
before do
|
93
|
+
$stderr.stub(:print)
|
94
|
+
end
|
95
|
+
|
96
|
+
let(:app) { ->(env) { raise StandardError.new("Foobar") } }
|
97
|
+
|
98
|
+
let(:middleware) do
|
99
|
+
Temescal::Middleware.new(app) do |config|
|
100
|
+
config.raise_errors = true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should raise the error" do
|
105
|
+
expect { middleware.call env_for("http://foobar.com") }.to raise_error StandardError
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def env_for url, opts={}
|
110
|
+
Rack::MockRequest.env_for(url, opts)
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Temescal::Monitors do
|
4
|
+
let(:exception) { StandardError.new }
|
5
|
+
|
6
|
+
context "MonitorsStrategy" do
|
7
|
+
it "should raise an error when the report method is called" do
|
8
|
+
expect { Temescal::Monitors::MonitorsStrategy.report(exception) }.to raise_error(NotImplementedError)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "Airbrake" do
|
13
|
+
it "should send the exception to Airbrake when report is called" do
|
14
|
+
Airbrake.stub(:send_notice)
|
15
|
+
|
16
|
+
expect(Airbrake).to receive(:notify).with(exception)
|
17
|
+
|
18
|
+
Temescal::Monitors::Airbrake.report exception
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "NewRelic" do
|
23
|
+
it "should send the exception to New Relic when report is called" do
|
24
|
+
expect(NewRelic::Agent).to receive(:notice_error).with(exception)
|
25
|
+
|
26
|
+
Temescal::Monitors::NewRelic.report exception
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
if ENV['CI']
|
2
|
+
require 'coveralls'
|
3
|
+
Coveralls.wear!
|
4
|
+
else
|
5
|
+
require 'awesome_print'
|
6
|
+
require 'pry-debugger'
|
7
|
+
|
8
|
+
require 'simplecov'
|
9
|
+
SimpleCov.start
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rack'
|
13
|
+
|
14
|
+
require 'airbrake'
|
15
|
+
require 'newrelic_rpm'
|
16
|
+
|
17
|
+
require 'temescal'
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
21
|
+
config.run_all_when_everything_filtered = true
|
22
|
+
config.filter_run :focus
|
23
|
+
|
24
|
+
# Run specs in random order to surface order dependencies. If you find an
|
25
|
+
# order dependency and want to debug it, you can fix the order by providing
|
26
|
+
# the seed, which is printed after each run.
|
27
|
+
# --seed 1234
|
28
|
+
config.order = 'random'
|
29
|
+
end
|
data/temescal.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
4
|
+
require 'temescal/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.add_dependency 'rack'
|
8
|
+
spec.add_development_dependency 'bundler'
|
9
|
+
|
10
|
+
spec.authors = ['Todd Bealmear']
|
11
|
+
spec.description = %q{Rack Middleware for gracefully handling exceptions for JSON APIs.}
|
12
|
+
spec.email = ['todd@t0dd.io']
|
13
|
+
spec.files = %w(LICENSE README.md Rakefile temescal.gemspec)
|
14
|
+
spec.files += Dir.glob('lib/**/*.rb')
|
15
|
+
spec.files += Dir.glob('spec/**/*')
|
16
|
+
spec.homepage = 'https://github.com/todd/temescal'
|
17
|
+
spec.licenses = ['MIT']
|
18
|
+
spec.name = 'temescal'
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
spec.summary = spec.description
|
21
|
+
spec.version = Temescal::VERSION
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: temescal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Todd Bealmear
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Rack Middleware for gracefully handling exceptions for JSON APIs.
|
42
|
+
email:
|
43
|
+
- todd@t0dd.io
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- temescal.gemspec
|
52
|
+
- lib/temescal/configuration.rb
|
53
|
+
- lib/temescal/middleware.rb
|
54
|
+
- lib/temescal/monitors.rb
|
55
|
+
- lib/temescal/response.rb
|
56
|
+
- lib/temescal/version.rb
|
57
|
+
- lib/temescal.rb
|
58
|
+
- spec/lib/temescal/configuration_spec.rb
|
59
|
+
- spec/lib/temescal/middleware_spec.rb
|
60
|
+
- spec/lib/temescal/monitors_spec.rb
|
61
|
+
- spec/spec_helper.rb
|
62
|
+
homepage: https://github.com/todd/temescal
|
63
|
+
licenses:
|
64
|
+
- MIT
|
65
|
+
metadata: {}
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 2.1.10
|
83
|
+
signing_key:
|
84
|
+
specification_version: 4
|
85
|
+
summary: Rack Middleware for gracefully handling exceptions for JSON APIs.
|
86
|
+
test_files: []
|