Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions lib/net/http/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,37 @@ module Net
# You cannot use Net::HTTPExceptions directly; instead, you must use
# its subclasses.
module HTTPExceptions
# Valid keys for pattern matching via #deconstruct_keys.
PATTERN_MATCHING_KEYS = %i[message response].freeze

def initialize(msg, res) #:nodoc:
super msg
@response = res
end
attr_reader :response
alias data response #:nodoc: obsolete

# Returns a hash of exception attributes for pattern matching.
#
# Valid keys are: +:message+, +:response+
#
# Example:
#
# begin
# http.request(req)
# rescue => e
# case e
# in HTTPRetriableError[response: { code: '503' }]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming that #240 is merged this is possible, otherwise nested deconstruction is not quite possible hence the deviation in the tests.

# retry_with_backoff
# in HTTPClientException[response: { code: '404' }]
# handle_not_found
# end
# end
#
def deconstruct_keys(keys)
valid_keys = keys ? PATTERN_MATCHING_KEYS & keys : PATTERN_MATCHING_KEYS
valid_keys.to_h { |key| [key, public_send(key)] }
end
end

class HTTPError < ProtocolError
Expand Down
60 changes: 60 additions & 0 deletions test/net/http/test_httpexceptions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: false
require 'net/http'
require 'test/unit'

class HTTPExceptionsTest < Test::Unit::TestCase
def test_deconstruct_keys
response = Net::HTTPOK.new('1.1', '200', 'OK')
error = Net::HTTPError.new('test error', response)

keys = error.deconstruct_keys(nil)
assert_equal 'test error', keys[:message]
assert_equal response, keys[:response]
end

def test_deconstruct_keys_with_specific_keys
response = Net::HTTPNotFound.new('1.1', '404', 'Not Found')
error = Net::HTTPClientException.new('not found', response)

keys = error.deconstruct_keys([:message])
assert_equal({message: 'not found'}, keys)
end

def test_pattern_matching
response = Net::HTTPServiceUnavailable.new('1.1', '503', 'Service Unavailable')
error = Net::HTTPRetriableError.new('service unavailable', response)

begin
matched = instance_eval <<~RUBY, __FILE__, __LINE__ + 1
case error
in message: /unavailable/, response:
true
else
false
end
RUBY
assert_equal true, matched
rescue SyntaxError
omit "Pattern matching requires Ruby 2.7+"
end
end

def test_pattern_matching_with_response_attributes
response = Net::HTTPNotFound.new('1.1', '404', 'Not Found')
error = Net::HTTPClientException.new('not found', response)

begin
matched = instance_eval <<~RUBY, __FILE__, __LINE__ + 1
case error
in response: res if res.code == '404'
true
else
false
end
RUBY
assert_equal true, matched
rescue SyntaxError
omit "Pattern matching requires Ruby 2.7+"
end
end
end