From c850d7c1eb7adc3ba89f8a6c4782c2debf9c59e7 Mon Sep 17 00:00:00 2001 From: Brandon Weaver Date: Sat, 8 Nov 2025 18:44:49 -0800 Subject: [PATCH] Add pattern matching support to Net::HTTP Implements deconstruct_keys to enable pattern matching on HTTP client configuration and state. Example: case http_client in address: 'localhost', port: 3000, use_ssl?: false 'local development' in use_ssl?: true, port: 443 'secure production' end --- lib/net/http.rb | 21 ++++++++++++++++++++ test/net/http/test_http.rb | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/lib/net/http.rb b/lib/net/http.rb index 8052702..3eb6a05 100644 --- a/lib/net/http.rb +++ b/lib/net/http.rb @@ -734,6 +734,9 @@ class HTTP < Protocol end # :startdoc: + # Valid keys for pattern matching via #deconstruct_keys. + PATTERN_MATCHING_KEYS = %i[address port use_ssl? started? read_timeout write_timeout open_timeout].freeze + # Returns +true+; retained for compatibility. def HTTP.version_1_2 true @@ -1511,6 +1514,24 @@ def use_ssl=(flag) @use_ssl = flag end + # Returns a hash of HTTP client attributes for pattern matching. + # + # Valid keys are: +:address+, +:port+, +:use_ssl?+, +:started?+, +:read_timeout+, +:write_timeout+, +:open_timeout+ + # + # Example: + # + # case http_client + # in address: "localhost", port: 3000, use_ssl?: false + # "local development" + # in use_ssl?: true, port: 443 + # "secure production" + # 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 + SSL_ATTRIBUTES = [ :ca_file, :ca_path, diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb index 366b4cd..d2e82e7 100644 --- a/test/net/http/test_http.rb +++ b/test/net/http/test_http.rb @@ -1399,4 +1399,43 @@ def test_partial_response http.ignore_eof = false assert_raise(EOFError) {http.get('/')} end + + def test_deconstruct_keys + http = Net::HTTP.new('example.com', 443) + http.use_ssl = true + + keys = http.deconstruct_keys(nil) + assert_equal 'example.com', keys[:address] + assert_equal 443, keys[:port] + assert_equal true, keys[:use_ssl?] + assert_equal false, keys[:started?] + assert_kind_of Numeric, keys[:read_timeout] + assert_kind_of Numeric, keys[:write_timeout] + assert_kind_of Numeric, keys[:open_timeout] + end + + def test_deconstruct_keys_with_specific_keys + http = Net::HTTP.new('example.com', 80) + + keys = http.deconstruct_keys([:address, :port, :use_ssl?]) + assert_equal({address: 'example.com', port: 80, use_ssl?: false}, keys) + end + + def test_pattern_matching + http = Net::HTTP.new('localhost', 3000) + + begin + matched = instance_eval <<~RUBY, __FILE__, __LINE__ + 1 + case http + in address: 'localhost', port: 3000, use_ssl?: false + true + else + false + end + RUBY + assert_equal true, matched + rescue SyntaxError + omit "Pattern matching requires Ruby 2.7+" + end + end end