diff --git a/lib/net/http/generic_request.rb b/lib/net/http/generic_request.rb index c92004e..080ad9c 100644 --- a/lib/net/http/generic_request.rb +++ b/lib/net/http/generic_request.rb @@ -9,6 +9,8 @@ # :include: doc/net-http/examples.rdoc # class Net::HTTPGenericRequest + # Valid keys for pattern matching via #deconstruct_keys. + PATTERN_MATCHING_KEYS = %i[method path uri body content_type].freeze include Net::HTTPHeader @@ -208,6 +210,24 @@ def body_stream=(input) input end + # Returns a hash of request attributes for pattern matching. + # + # Valid keys are: +:method+, +:path+, +:uri+, +:body+, +:content_type+ + # + # Example: + # + # case request + # in method: 'POST', path: %r{^/api/} + # handle_api_request(request) + # in method: 'GET', path: '/' + # handle_root + # 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 + def set_body_internal(str) #:nodoc: internal use only raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream) self.body = str if str diff --git a/test/net/http/test_http_request.rb b/test/net/http/test_http_request.rb index 7fd82b0..e846703 100644 --- a/test/net/http/test_http_request.rb +++ b/test/net/http/test_http_request.rb @@ -89,5 +89,45 @@ def test_header_set 'Bug #7831 - do not decode content if the user overrides' end if Net::HTTP::HAVE_ZLIB + def test_deconstruct_keys + uri = URI('https://example.com/api/users') + req = Net::HTTP::Post.new(uri) + req.body = 'test data' + req['content-type'] = 'application/json' + + keys = req.deconstruct_keys(nil) + assert_equal 'POST', keys[:method] + assert_equal '/api/users', keys[:path] + assert_equal uri, keys[:uri] + assert_equal 'test data', keys[:body] + assert_equal 'application/json', keys[:content_type] + end + + def test_deconstruct_keys_with_specific_keys + req = Net::HTTP::Get.new('/test') + + keys = req.deconstruct_keys([:method, :path]) + assert_equal({method: 'GET', path: '/test'}, keys) + end + + def test_pattern_matching + uri = URI('https://example.com/api/users') + req = Net::HTTP::Post.new(uri) + + begin + matched = instance_eval <<~RUBY, __FILE__, __LINE__ + 1 + case req + in method: 'POST', path: %r{^/api/} + true + else + false + end + RUBY + assert_equal true, matched + rescue SyntaxError + omit "Pattern matching requires Ruby 2.7+" + end + end + end