Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/net/imap/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative "config/attr_inheritance"
require_relative "config/attr_type_coercion"
require_relative "config/attr_version_defaults"
require_relative "config/global"

module Net
class IMAP
Expand Down Expand Up @@ -632,7 +633,7 @@ def defaults_hash
end

@default = AttrVersionDefaults.compile_default!
@global = default.new
@global = Global.setup!
AttrVersionDefaults.compile_version_defaults!

end
Expand Down
1 change: 0 additions & 1 deletion lib/net/imap/config/attr_accessors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ def self.attr_accessor(name) # :nodoc: internal API
def self.attributes
instance_methods.grep(/=\z/).map { _1.to_s.delete_suffix("=").to_sym }
end
private_class_method :attributes

def self.struct # :nodoc: internal API
unless defined?(self::Struct)
Expand Down
2 changes: 1 addition & 1 deletion lib/net/imap/config/attr_type_coercion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def self.safe(&b)
else
def self.safe(&b) nil.instance_eval(&b).freeze end
end
private_class_method :safe
# private_class_method :safe

Types = Hash.new do |h, type| type => Proc | nil; safe{type} end
Types[:boolean] = Boolean = safe{-> {!!_1}}
Expand Down
11 changes: 6 additions & 5 deletions lib/net/imap/config/attr_version_defaults.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ module AttrVersionDefaults
# See Config.version_defaults.
singleton_class.attr_reader :version_defaults

@version_defaults = Hash.new {|h, k|
@version_defaults = {}
version_defaults.default_proc = AttrTypeCoercion.safe {->(h, k){
# NOTE: String responds to both so the order is significant.
# And ignore non-numeric conversion to zero, because: "wat!?".to_r == 0
(h.fetch(k.to_r, nil) || h.fetch(k.to_f, nil) if k.is_a?(Numeric)) ||
(h.fetch(k.to_sym, nil) if k.respond_to?(:to_sym)) ||
(h.fetch(k.to_r, nil) if k.respond_to?(:to_r) && k.to_r != 0r) ||
(h.fetch(k.to_f, nil) if k.respond_to?(:to_f) && k.to_f != 0.0)
}
(h.fetch(k.to_sym, nil) if k.respond_to?(:to_sym)) ||
(h.fetch(k.to_r, nil) if k.respond_to?(:to_r) && k.to_r != 0r) ||
(h.fetch(k.to_f, nil) if k.respond_to?(:to_f) && k.to_f != 0.0)
}}

# :stopdoc: internal APIs only

Expand Down
57 changes: 57 additions & 0 deletions lib/net/imap/config/global.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require "singleton"

module Net
class IMAP
class Config
class Global < Config
include Singleton
extend Forwardable
singleton_class.extend(Forwardable)

singleton_class.attr_reader :snapshot

def_delegators :"self.class", :reset, :snapshot
protected :snapshot

def self.setup!
@snapshot = Config.default.new.freeze
AttrAccessors.attributes.each do |attr|
singleton_class.define_method(:"#{attr}=") do |val|
@snapshot = snapshot.dup.update(attr => val).freeze
end
singleton_class.def_delegator :snapshot, attr
def_delegators :"self.class", attr, :"#{attr}="
end
instance
end

def initialize
super(Config.default)
@data = nil
freeze
end

def new(**attrs) Config.new(self, **attrs) end

def self.reset(attr = nil)
if attr.nil?
@snapshot = Config.default.new.freeze
self
elsif snapshot.inherited?(attr)
nil
else
old, new = send(attr), snapshot.dup
new.reset(attr)
@snapshot = new.freeze
old
end
end

protected

def data = snapshot.data

end
end
end
end
12 changes: 11 additions & 1 deletion test/net/imap/test_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class ConfigTest < Net::IMAP::TestCase
assert_equal true, global.debug?
global.reset(:debug)
assert_equal false, global.debug?
refute global.frozen?
assert global.frozen?
end

test "Net::IMAP.config" do
Expand Down Expand Up @@ -157,6 +157,16 @@ class ConfigTest < Net::IMAP::TestCase
end
end

if defined?(Ractor)
test ".global is deeply frozen (and Ractor shareable)" do
assert Ractor.shareable?(Config.global)
end

test ".version_defaults is deeply frozen (and Ractor shareable)" do
assert Ractor.shareable? Config.version_defaults
end
end

test "Config[:default] and Config[:current] both hold default config" do
defaults = Config.default.to_h
assert_equal(defaults, Config[:default].to_h)
Expand Down