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..02632d501 100644 --- a/lib/net/imap/config/attr_type_coercion.rb +++ b/lib/net/imap/config/attr_type_coercion.rb @@ -26,34 +26,27 @@ 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.safe(...) = Ractor.make_shareable nil.instance_eval(...).freeze + private_class_method :safe - 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; safe{type} end + Types[:boolean] = Boolean = safe{-> {!!_1}} + Types[Integer] = safe{->{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.dup.freeze + Enum = ->(*enum) { + enum = safe{enum} 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 + safe{->val { + return val if enum.include?(val) + raise ArgumentError, "expected %s, got %p" % [expected, val] + }} + } end end