From 340d3e7043b71b75ac0a793364e475854f80b13e Mon Sep 17 00:00:00 2001 From: nick evans Date: Wed, 22 Jan 2025 13:11:06 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20ResponseParser=20config=20is=20m?= =?UTF-8?q?utable=20and=20non-global?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When ResponseParser was initialized without any explicit config, it used Config.global directly. This meant that changes to `parser.config` were also changes to the _global_ config! When ResponseParser is initialized with a config hash, that creates a frozen config object. This meant that changes to `parser.config` were impossible. So, when the given config is global or frozen, we create a new config and inherit from the given config. We want to continue using the given config as-is in other cases, so the client and its parser can share the same exact config. --- lib/net/imap/response_parser.rb | 6 +++- test/net/imap/test_imap_response_parser.rb | 35 ++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/net/imap/response_parser.rb b/lib/net/imap/response_parser.rb index f6dc438a..29ee38b8 100644 --- a/lib/net/imap/response_parser.rb +++ b/lib/net/imap/response_parser.rb @@ -13,13 +13,17 @@ class ResponseParser attr_reader :config - # :call-seq: Net::IMAP::ResponseParser.new -> Net::IMAP::ResponseParser + # Creates a new ResponseParser. + # + # When +config+ is frozen or global, the parser #config inherits from it. + # Otherwise, +config+ will be used directly. def initialize(config: Config.global) @str = nil @pos = nil @lex_state = nil @token = nil @config = Config[config] + @config = @config.new if @config == Config.global || @config.frozen? end # :call-seq: diff --git a/test/net/imap/test_imap_response_parser.rb b/test/net/imap/test_imap_response_parser.rb index e1eb16c5..5d594bca 100644 --- a/test/net/imap/test_imap_response_parser.rb +++ b/test/net/imap/test_imap_response_parser.rb @@ -118,6 +118,41 @@ def teardown # response data, should still use normal tests, below ############################################################################ + test "default config inherits from Config.global" do + parser = Net::IMAP::ResponseParser.new + refute parser.config.frozen? + refute_equal Net::IMAP::Config.global, parser.config + assert_same Net::IMAP::Config.global, parser.config.parent + end + + test "config can be passed in to #initialize" do + config = Net::IMAP::Config.global.new + parser = Net::IMAP::ResponseParser.new config: config + assert_same config, parser.config + end + + test "passing in global config inherits from Config.global" do + parser = Net::IMAP::ResponseParser.new config: Net::IMAP::Config.global + refute parser.config.frozen? + refute_equal Net::IMAP::Config.global, parser.config + assert_same Net::IMAP::Config.global, parser.config.parent + end + + test "config will inherits from passed in frozen config" do + parser = Net::IMAP::ResponseParser.new config: {debug: true} + refute_equal Net::IMAP::Config.global, parser.config.parent + refute parser.config.frozen? + + assert parser.config.parent.frozen? + assert parser.config.debug? + assert parser.config.inherited?(:debug) + + config = Net::IMAP::Config[debug: true] + parser = Net::IMAP::ResponseParser.new(config:) + refute_equal Net::IMAP::Config.global, parser.config.parent + assert_same config, parser.config.parent + end + # Strangly, there are no example responses for BINARY[section] in either # RFC3516 or RFC9051! The closest I found was RFC5259, and those examples # aren't FETCH responses.