Skip to content

Commit

Permalink
Provide wrappers for the errors that can be raised from a request.
Browse files Browse the repository at this point in the history
  • Loading branch information
alloy committed Apr 20, 2014
1 parent 0e08d3e commit 0b417cb
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 2 deletions.
8 changes: 6 additions & 2 deletions lib/rest.rb
@@ -1,7 +1,10 @@
require 'uri'

# REST is basically a convenience wrapper around Net::HTTP. It defines a simple and consistant API for doing REST-style
# HTTP calls.
# REST is basically a convenience wrapper around Net::HTTP. It defines a simple and consistant API
# for doing REST-style HTTP calls.
#
# In addition it provides wrappers for the many error classes that can be raised while making
# requests. See REST::Error for a complete discussion of options.
module REST
# Library version
VERSION = '0.7.0'
Expand Down Expand Up @@ -101,5 +104,6 @@ def self.post(uri, body, headers={}, options={}, &configure_block)
end
end

require File.expand_path('../rest/error', __FILE__)
require File.expand_path('../rest/request', __FILE__)
require File.expand_path('../rest/response', __FILE__)
91 changes: 91 additions & 0 deletions lib/rest/error.rb
@@ -0,0 +1,91 @@
require 'net/http'

module REST
# This constant can be used to rescue any of the known `Timeout`, `Connection`, and `Protocol`
# error classes.
#
# For instance, to rescue _any_ type of error that could be raise while making a request:
#
# begin
# REST.get('http://example.com/pigeons/12')
# rescue REST::Error => e
# p e # => Timeout::Error
# end
#
# If you want to rescue only `Timeout` related error classes, however, you can limit the scope:
#
# begin
# REST.get('http://example.com/pigeons/12')
# rescue REST::Error::Timeout => e
# p e # => Timeout::Error
# end
module Error
# This constant can be used to rescue only the known `Timeout` error classes.
module Timeout
def self.class_names
%w(
Errno::ETIMEDOUT
Timeout::Error
Net::OpenTimeout
Net::ReadTimeout
)
end
end

# This constant can be used to rescue only the known `Connection` error classes.
module Connection
def self.class_names
%w(
EOFError
Errno::ECONNABORTED
Errno::ECONNREFUSED
Errno::ECONNRESET
Errno::EHOSTUNREACH
Errno::EINVAL
Errno::ENETUNREACH
SocketError
OpenSSL::SSL::SSLError
)
end
end

# This constant can be used to rescue only the known `Protocol` error classes.
module Protocol
def self.class_names
%w(
Net::HTTPBadResponse
Net::HTTPHeaderSyntaxError
Net::ProtocolError
Zlib::GzipFile::Error
)
end
end

private

[Timeout, Connection, Protocol].each do |mod|
mod.send(:include, Error)

# Collect all the error classes that exist at runtime.
def mod.classes
class_names.map do |name|
begin
# MRI < 2 does not support full constant paths for `Object.const_get`.
name.split('::').inject(Object) do |current, const|
current.const_get(const)
end
rescue NameError
nil
end
end.compact
end

# Include the `mod` into the classes.
def mod.extend_classes!
classes.each { |klass| klass.send(:include, self) }
end

mod.extend_classes!
end
end
end
1 change: 1 addition & 0 deletions lib/rest/request.rb
Expand Up @@ -111,6 +111,7 @@ def http_request
if url.scheme == 'https'
require 'net/https'
require 'openssl'
Error::Connection.extend_classes!

http_request.use_ssl = true

Expand Down
33 changes: 33 additions & 0 deletions test/rest_error_test.rb
@@ -0,0 +1,33 @@
require File.expand_path('../helper', __FILE__)

require 'openssl'
REST::Error::Connection.extend_classes!

describe "REST::Error" do
it "extends any Timeout related exception" do
classes = REST::Error::Timeout.classes
classes.should.not.be.empty
classes.each do |error_class|
lambda { raise error_class }.should.raise REST::Error::Timeout
lambda { raise error_class }.should.raise REST::Error
end
end

it "extends any Connection related exception" do
classes = REST::Error::Connection.classes
classes.should.not.be.empty
classes.each do |error_class|
lambda { raise error_class }.should.raise REST::Error::Connection
lambda { raise error_class }.should.raise REST::Error
end
end

it "extends any Protocol related exception" do
classes = REST::Error::Protocol.classes
classes.should.not.be.empty
classes.each do |error_class|
lambda { raise error_class }.should.raise REST::Error::Protocol
lambda { raise error_class }.should.raise REST::Error
end
end
end

0 comments on commit 0b417cb

Please sign in to comment.