From 0a0fc18a07f966d19ba7956770f0e0b6fd29dc82 Mon Sep 17 00:00:00 2001 From: nick evans Date: Thu, 13 Mar 2025 16:38:27 -0400 Subject: [PATCH 1/2] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20Config=20at?= =?UTF-8?q?tr=20type=20coercion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switching to a "Types" registry, which holds a proc for each coercion. --- lib/net/imap/config.rb | 6 ++-- lib/net/imap/config/attr_type_coercion.rb | 36 ++++++++--------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/lib/net/imap/config.rb b/lib/net/imap/config.rb index 0e682c8e1..5b56ec0a8 100644 --- a/lib/net/imap/config.rb +++ b/lib/net/imap/config.rb @@ -245,7 +245,7 @@ def self.[](config) # present. When capabilities are unknown, Net::IMAP will automatically # send a +CAPABILITY+ command first before sending +LOGIN+. # - attr_accessor :enforce_logindisabled, type: [ + attr_accessor :enforce_logindisabled, type: Enum[ false, :when_capabilities_cached, true ] @@ -275,7 +275,7 @@ def self.[](config) # Raise an ArgumentError with the deprecation warning. # # Note: #responses_without_args is an alias for #responses_without_block. - attr_accessor :responses_without_block, type: [ + attr_accessor :responses_without_block, type: Enum[ :silence_deprecation_warning, :warn, :frozen_dup, :raise, ] @@ -320,7 +320,7 @@ def self.[](config) # # [+false+ (planned default for +v0.6+)] # ResponseParser _only_ uses AppendUIDData and CopyUIDData. - attr_accessor :parser_use_deprecated_uidplus_data, type: [ + attr_accessor :parser_use_deprecated_uidplus_data, type: Enum[ true, :up_to_max_size, false ] diff --git a/lib/net/imap/config/attr_type_coercion.rb b/lib/net/imap/config/attr_type_coercion.rb index c15dbb8a6..916e89329 100644 --- a/lib/net/imap/config/attr_type_coercion.rb +++ b/lib/net/imap/config/attr_type_coercion.rb @@ -26,34 +26,24 @@ def self.included(mod) end private_class_method :included - def self.attr_accessor(attr, type: nil) - return unless type - if :boolean == type then boolean attr - elsif Integer == type then integer attr - elsif Array === type then enum attr, type - else raise ArgumentError, "unknown type coercion %p" % [type] - end - end - - def self.boolean(attr) - define_method :"#{attr}=" do |val| super !!val end - define_method :"#{attr}?" do send attr end - end + Types = Hash.new do |h, type| type => Proc | nil; type end + Types[:boolean] = Boolean = -> {!!_1} + Types[Integer] = ->{Integer(_1)} - def self.integer(attr) - define_method :"#{attr}=" do |val| super Integer val end + def self.attr_accessor(attr, type: nil) + type = Types[type] or return + define_method :"#{attr}=" do |val| super type[val] end + define_method :"#{attr}?" do send attr end if type == Boolean end - def self.enum(attr, enum) + Enum = ->(*enum) { enum = enum.dup.freeze expected = -"one of #{enum.map(&:inspect).join(", ")}" - define_method :"#{attr}=" do |val| - unless enum.include?(val) - raise ArgumentError, "expected %s, got %p" % [expected, val] - end - super val - end - end + ->val { + return val if enum.include?(val) + raise ArgumentError, "expected %s, got %p" % [expected, val] + } + } end end From 95796752097108fab21d62d0360a29a004f14c77 Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 17 Mar 2025 14:58:09 -0400 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20Fix=20Config::AttrTypeCoercion?= =?UTF-8?q?=20for=20Ractor=20sharing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/net/imap/config/attr_type_coercion.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/net/imap/config/attr_type_coercion.rb b/lib/net/imap/config/attr_type_coercion.rb index 916e89329..02632d501 100644 --- a/lib/net/imap/config/attr_type_coercion.rb +++ b/lib/net/imap/config/attr_type_coercion.rb @@ -26,9 +26,12 @@ def self.included(mod) end private_class_method :included - Types = Hash.new do |h, type| type => Proc | nil; type end - Types[:boolean] = Boolean = -> {!!_1} - Types[Integer] = ->{Integer(_1)} + def self.safe(...) = Ractor.make_shareable nil.instance_eval(...).freeze + private_class_method :safe + + Types = Hash.new do |h, type| type => Proc | nil; safe{type} end + Types[:boolean] = Boolean = safe{-> {!!_1}} + Types[Integer] = safe{->{Integer(_1)}} def self.attr_accessor(attr, type: nil) type = Types[type] or return @@ -37,12 +40,12 @@ def self.attr_accessor(attr, type: nil) end Enum = ->(*enum) { - enum = enum.dup.freeze + enum = safe{enum} expected = -"one of #{enum.map(&:inspect).join(", ")}" - ->val { + safe{->val { return val if enum.include?(val) raise ArgumentError, "expected %s, got %p" % [expected, val] - } + }} } end