class Net::IMAP::DataLite
def self.define(*args, &block)
be keywords (e.g: +next+ or +class+) or start with capital letters, "@",
member names which are valid local variable names. Member names can't
_NOTE:_ Unlike ruby 3.2's +Data.define+, DataLite.define only supports
Defines a new Data class.
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
def ==(other) self.class == other.class && to_h == other.to_h end
def ==(other) self.class == other.class && to_h == other.to_h end
def __inspect_guard__(obj)
Making circular references inside a Data object _should_ be very
recursively trigger a SystemStackError (stack level too deep).
Marks +obj+ as seen inside the block, so circuler references don't
Yields +true+ if +obj+ has been seen already, +false+ if it hasn't.
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
def __to_h__; Hash[members.map {|m| [m, send(m)] }] end
def __to_h__; Hash[members.map {|m| [m, send(m)] }] end
def deconstruct; __to_h__.values end
def deconstruct; __to_h__.values end
def deconstruct_keys(keys)
def deconstruct_keys(keys) raise TypeError unless keys.is_a?(Array) || keys.nil? return __to_h__ if keys&.first.nil? __to_h__.slice(*keys) end
def encode_with(coder) coder.map = to_h.transform_keys(&:to_s) end
def encode_with(coder) coder.map = to_h.transform_keys(&:to_s) end
def eql?(other) self.class == other.class && hash == other.hash end
def eql?(other) self.class == other.class && hash == other.hash end
def hash; [self.class, __to_h__].hash end
def hash; [self.class, __to_h__].hash end
def init_with(coder) initialize(**coder.map.transform_keys(&:to_sym)) end
def init_with(coder) initialize(**coder.map.transform_keys(&:to_sym)) end
def initialize_copy(source) super.freeze end
def initialize_copy(source) super.freeze end
def inspect
def inspect __inspect_guard__(self) do |seen| return "#<data #{self.class}:...>" if seen attrs = __to_h__.map {|kv| "%s=%p" % kv }.join(", ") display = ["data", self.class.name, attrs].compact.join(" ") "#<#{display}>" end end
def marshal_dump; __to_h__ end
def marshal_dump; __to_h__ end
def members; self.class.members end
def members; self.class.members end
def to_h(&block) block ? __to_h__.to_h(&block) : __to_h__ end
def to_h(&block) block ? __to_h__.to_h(&block) : __to_h__ end
def with(**kwargs)
def with(**kwargs) return self if kwargs.empty? self.class.new(**__to_h__.merge(kwargs)) end