Class: Skit::Serialization::Processor::Union

Inherits:
Base
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/skit/serialization/processor/union.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#traverse

Constructor Details

#initialize(type_spec, registry:) ⇒ Union

Returns a new instance of Union.



20
21
22
23
24
25
26
# File 'lib/skit/serialization/processor/union.rb', line 20

def initialize(type_spec, registry:)
  super
  @struct_classes = T.let(
    self.class.struct_types(type_spec),
    T::Array[T.class_of(T::Struct)]
  )
end

Class Method Details

.boolean_union?(type_spec) ⇒ Boolean

Returns:



74
75
76
77
78
79
# File 'lib/skit/serialization/processor/union.rb', line 74

def boolean_union?(type_spec)
  raw_types = type_spec.types.filter_map do |t|
    t.is_a?(T::Types::Simple) ? t.raw_type : nil
  end
  raw_types.sort_by { |t| t.name.to_s } == [FalseClass, TrueClass]
end

.contains_nil_class?(type_spec) ⇒ Boolean

Returns:



67
68
69
70
71
# File 'lib/skit/serialization/processor/union.rb', line 67

def contains_nil_class?(type_spec)
  type_spec.types.any? do |t|
    t.is_a?(T::Types::Simple) && t.raw_type == NilClass
  end
end

.handles?(type_spec) ⇒ Boolean

Returns:



11
12
13
14
15
16
17
# File 'lib/skit/serialization/processor/union.rb', line 11

def self.handles?(type_spec)
  return false unless type_spec.is_a?(T::Types::Union)
  return false if contains_nil_class?(type_spec)
  return false if boolean_union?(type_spec)

  struct_types(type_spec).length == type_spec.types.length
end

.struct_types(type_spec) ⇒ Object



82
83
84
85
86
87
88
89
# File 'lib/skit/serialization/processor/union.rb', line 82

def struct_types(type_spec)
  type_spec.types.filter_map do |t|
    next unless t.is_a?(T::Types::Simple)

    klass = t.raw_type
    klass if klass.is_a?(Class) && klass < T::Struct
  end
end

Instance Method Details

#deserialize(value, path: Path.new) ⇒ Object

Raises:



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/skit/serialization/processor/union.rb', line 44

def deserialize(value, path: Path.new)
  return value if value_is_union_member?(value)

  unless value.is_a?(::Hash)
    raise DeserializeError.new("Expected Hash or union member struct, got #{value.class}",
                               path: path)
  end

  @struct_classes.each do |struct_class|
    result = try_deserialize(value, struct_class, path: path)
    return result if result
  end

  raise DeserializeError.new(
    "No matching struct found for union: #{@struct_classes.map(&:name).join(", ")}",
    path: path
  )
end

#serialize(value, path: Path.new) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/skit/serialization/processor/union.rb', line 29

def serialize(value, path: Path.new)
  struct_class = find_struct_class_for_value(value)

  unless struct_class
    raise SerializeError.new(
      "#{value.class} is not a member of this union: #{@struct_classes.map(&:name).join(", ")}",
      path: path
    )
  end

  processor = @registry.processor_for(struct_class)
  processor.serialize(value, path: path)
end