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 in net-imap 0.6, when support for ruby 3.1 is dropped.

NOTE: net-imap no longer supports ruby versions prior to 3.1.

When running ruby >= 3.2

This class inherits from Data and only defines the methods needed for YAML serialization. This will be dropped when psych adds support for Data.

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

::[](*args) → instance click to toggle source
::[](**kwargs) → instance

Constuctor for classes defined with ::define.

Alias for ::new

# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 151
      
define(*args, &block) click to toggle source

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
new(*args) → instance click to toggle source
new(**kwargs) → instance

Constuctor for classes defined with ::define.

Aliased as ::[].

# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 141
      

Public Instance Methods

==(other) click to toggle source
# 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
attributes() click to toggle source
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 162
def attributes;  Hash[members.map {|m| [m, send(m)] }]           end
deconstruct() click to toggle source
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 167
def deconstruct; attributes.values                               end
deconstruct_keys(keys) click to toggle source
# 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
encode_with(coder) click to toggle source
# 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
eql?(other) click to toggle source
# 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
hash() click to toggle source
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 164
def hash;        [self.class, attributes].hash                   end
init_with(coder) click to toggle source
# 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
inspect() click to toggle source
# 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
Also aliased as: to_s
members() click to toggle source
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 161
def members;     self.class.members                              end
to_h(&block) click to toggle source
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 163
def to_h(&block) attributes.to_h(&block)                         end
to_s()
Alias for: inspect
with(**kwargs) click to toggle source
# 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

__inspect_guard__(obj) { |true| ... } click to toggle source

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
initialize_copy(source) click to toggle source
Calls superclass method
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 192
def initialize_copy(source) super.freeze end
marshal_dump() click to toggle source
# File net-imap-0.5.4/lib/net/imap/data_lite.rb, line 193
def marshal_dump; attributes end