From 1249b51e9f519eb819ccdfe7a806574ca4a7c4e4 Mon Sep 17 00:00:00 2001 From: Brandon Weaver Date: Tue, 6 Jun 2023 09:49:23 -0700 Subject: [PATCH] Optimizes `normalize_headers` for performance Optimizes the `WebMock::Util::Headers.normalize_headers` method to: * Create less objects * Avoid using Regexp where possible * Hoists constants More details can be found in the related issue, including performance benchmarks: https://github.com/bblimke/webmock/issues/1027 --- lib/webmock/util/headers.rb | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/webmock/util/headers.rb b/lib/webmock/util/headers.rb index c803ff9e0..91e490e68 100644 --- a/lib/webmock/util/headers.rb +++ b/lib/webmock/util/headers.rb @@ -6,18 +6,21 @@ module Util class Headers + STANDARD_HEADER_DELIMITER = '-'.freeze + NONSTANDARD_HEADER_DELIMITER = '_'.freeze + JOIN = ', '.freeze + def self.normalize_headers(headers) return nil unless headers - array = headers.map { |name, value| - [name.to_s.split(/_|-/).map { |segment| segment.capitalize }.join("-"), - case value + + headers.each_with_object({}) do |(name, value), new_headers| + new_headers[normalize_name(name)] = + case value when Regexp then value - when Array then (value.size == 1) ? value.first.to_s : value.map {|v| v.to_s}.sort + when Array then (value.size == 1) ? value.first.to_s : value.map(&:to_s).sort else value.to_s - end - ] - } - Hash[*array.inject([]) {|r,x| r + x}] + end + end end def self.sorted_headers_string(headers) @@ -57,6 +60,15 @@ def self.basic_auth_header(*credentials) "Basic #{Base64.strict_encode64(credentials.join(':')).chomp}" end + def self.normalize_name(name) + name + .to_s + .tr(NONSTANDARD_HEADER_DELIMITER, STANDARD_HEADER_DELIMITER) + .split(STANDARD_HEADER_DELIMITER) + .map!(&:capitalize) + .join(STANDARD_HEADER_DELIMITER) + end + end end