class Net::IMAP::DataLite
DataLite is a temporary substitute for ruby 3.2’s Data class. DataLite is aliased as Net::IMAP::Data, so that code using it won’t need to be updated when it is removed.
See ruby 3.2’s documentation for Data.
- When running ruby 3.1
-
This class reimplements the API for ruby 3.2’s
Data, and should be compatible for nearly all use-cases. This reimplementation will be removed innet-imap0.6, when support for ruby 3.1 is dropped.NOTE:
net-imapno longer supports ruby versions prior to 3.1. - When running ruby >= 3.2
-
This class inherits from
Dataand only defines the methods needed for YAML serialization. This will be dropped whenpsychadds support forData.
Some of the code in this class was copied or adapted from the polyfill-data gem, by Jim Gay and Joel Drapper, under the MIT license terms.
Constants
- ARITY_ERROR
- ATTRSET_ERROR
- DUP_ERROR
- TYPE_ERROR
Public Class Methods
Defines a new Data class.
NOTE: Unlike ruby 3.2’s Data.define, DataLite.define only supports member names which are valid local variable names. Member names can’t be keywords (e.g: next or class) or start with capital letters, “@”, etc.
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 81 def self.define(*args, &block) members = args.each_with_object({}) do |arg, members| arg = arg.to_str unless arg in Symbol | String if arg.respond_to?(:to_str) arg = arg.to_sym if arg in String arg in Symbol or raise TypeError, TYPE_ERROR % [arg] arg in %r{=} and raise ArgumentError, ATTRSET_ERROR % [arg] members.key?(arg) and raise ArgumentError, DUP_ERROR % [arg] members[arg] = true end members = members.keys.freeze klass = ::Class.new(self) klass.singleton_class.undef_method :define klass.define_singleton_method(:members) { members } def klass.new(*args, **kwargs, &block) if kwargs.size.positive? if args.size.positive? raise ArgumentError, ARITY_ERROR % [args.size, 0] end elsif members.size < args.size expected = members.size.zero? ? 0 : 0..members.size raise ArgumentError, ARITY_ERROR % [args.size, expected] else kwargs = Hash[members.take(args.size).zip(args)] end allocate.tap do |instance| instance.__send__(:initialize, **kwargs, &block) end.freeze end klass.singleton_class.alias_method :[], :new klass.attr_reader(*members) # Dynamically defined initializer methods are in an included module, # rather than directly on DataLite (like in ruby 3.2+): # * simpler to handle required kwarg ArgumentErrors # * easier to ensure consistent ivar assignment order (object shape) # * faster than instance_variable_set klass.include(Module.new do if members.any? kwargs = members.map{"#{_1.name}:"}.join(", ") params = members.map(&:name).join(", ") ivars = members.map{"@#{_1.name}"}.join(", ") attrs = members.map{"attrs[:#{_1.name}]"}.join(", ") module_eval <<~RUBY, __FILE__, __LINE__ + 1 protected def initialize(#{kwargs}) #{ivars} = #{params}; freeze end def marshal_load(attrs) #{ivars} = #{attrs}; freeze end RUBY end end) klass.module_eval do _1.module_eval(&block) end if block_given? klass end
Public Instance Methods
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 165 def ==(other) self.class == other.class && to_h == other.to_h end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 162 def attributes; Hash[members.map {|m| [m, send(m)] }] end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 167 def deconstruct; attributes.values end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 169 def deconstruct_keys(keys) raise TypeError unless keys.is_a?(Array) || keys.nil? return attributes if keys&.first.nil? attributes.slice(*keys) end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 32 def encode_with(coder) coder.map = attributes.transform_keys(&:to_s) end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 166 def eql?(other) self.class == other.class && hash == other.hash end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 164 def hash; [self.class, attributes].hash end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 33 def init_with(coder) initialize(**coder.map.transform_keys(&:to_sym)) end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 180 def inspect __inspect_guard__(self) do |seen| return "#<data #{self.class}:...>" if seen attrs = attributes.map {|kv| "%s=%p" % kv }.join(", ") display = ["data", self.class.name, attrs].compact.join(" ") "#<#{display}>" end end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 161 def members; self.class.members end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 163 def to_h(&block) attributes.to_h(&block) end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 175 def with(**kwargs) return self if kwargs.empty? self.class.new(**attributes.merge(kwargs)) end
Private Instance Methods
Yields true if obj has been seen already, false if it hasn’t. Marks obj as seen inside the block, so circuler references don’t recursively trigger a SystemStackError (stack level too deep).
Making circular references inside a Data object should be very uncommon, but we’ll support them for the sake of completeness.
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 201 def __inspect_guard__(obj) preexisting = Thread.current[:__net_imap_data__inspect__] Thread.current[:__net_imap_data__inspect__] ||= {}.compare_by_identity inspect_guard = Thread.current[:__net_imap_data__inspect__] if inspect_guard.include?(obj) yield true else begin inspect_guard[obj] = true yield false ensure inspect_guard.delete(obj) end end ensure unless preexisting.equal?(inspect_guard) Thread.current[:__net_imap_data__inspect__] = preexisting end end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 192 def initialize_copy(source) super.freeze end
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 193 def marshal_dump; attributes end