diff --git a/lib/net/http/response.rb b/lib/net/http/response.rb index 3aeba2e..4b52469 100644 --- a/lib/net/http/response.rb +++ b/lib/net/http/response.rb @@ -133,6 +133,9 @@ # there is a protocol error. # class Net::HTTPResponse + # Valid keys for pattern matching via #deconstruct_keys. + PATTERN_MATCHING_KEYS = %i[code message http_version body content_type].freeze + class << self # true if the response has a body. def body_permitted? @@ -408,6 +411,31 @@ def body=(value) alias entity body #:nodoc: obsolete + # Returns a hash of response attributes for pattern matching. + # + # Valid keys are: +:code+, +:message+, +:http_version+, +:body+, +:content_type+ + # + # Example: + # + # response = Net::HTTP.get_response(uri) + # case response + # in code: '200', content_type: /json/ + # JSON.parse(response.body) + # in code: '404' + # handle_not_found + # end + # + def deconstruct_keys(keys) + valid_keys = keys ? PATTERN_MATCHING_KEYS & keys : PATTERN_MATCHING_KEYS + valid_keys.to_h do |key| + value = case key + when :body then @body + else public_send(key) + end + [key, value] + end + end + private # :nodoc: diff --git a/test/net/http/test_httpresponse.rb b/test/net/http/test_httpresponse.rb index 0128106..9d90139 100644 --- a/test/net/http/test_httpresponse.rb +++ b/test/net/http/test_httpresponse.rb @@ -744,6 +744,46 @@ def test_inspect_response assert_equal '#', res.inspect end + def test_deconstruct_keys + res = Net::HTTPOK.new('1.1', '200', 'OK') + res.body = 'test body' + res['content-type'] = 'text/plain' + + keys = res.deconstruct_keys(nil) + assert_equal '200', keys[:code] + assert_equal 'OK', keys[:message] + assert_equal '1.1', keys[:http_version] + assert_equal 'test body', keys[:body] + assert_equal 'text/plain', keys[:content_type] + end + + def test_deconstruct_keys_with_specific_keys + res = Net::HTTPOK.new('1.1', '200', 'OK') + res.body = 'test body' + + keys = res.deconstruct_keys([:code, :message]) + assert_equal({code: '200', message: 'OK'}, keys) + end + + def test_pattern_matching + res = Net::HTTPOK.new('1.1', '200', 'OK') + res['content-type'] = 'application/json' + + begin + matched = instance_eval <<~RUBY, __FILE__, __LINE__ + 1 + case res + in code: '200', content_type: /json/ + true + else + false + end + RUBY + assert_equal true, matched + rescue SyntaxError + omit "Pattern matching requires Ruby 2.7+" + end + end + private def dummy_io(str)