Module: Crystalline

Defined in:
lib/crystalline/types.rb,
lib/crystalline.rb,
lib/crystalline/utils.rb,
lib/crystalline/module.rb,
lib/crystalline/metadata_fields.rb

Overview

typed: false frozen_string_literal: true

Defined Under Namespace

Modules: Enum, MetadataFields, Utils Classes: Array, Boolean, Hash, Nilable, Union

Class Method Summary collapse

Class Method Details

.json_encode(val, primitives: true) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/crystalline/module.rb', line 62

def self.json_encode(val, primitives: true)
  if val.class.respond_to? :enums
    val.serialize
  elsif val.is_a? DateTime
    val.strftime('%Y-%m-%dT%H:%M:%S.%NZ')
  elsif val.nil?
    nil
  elsif primitives
    val.to_s
  else
    val
  end
end

.needs_string_conversion(val) ⇒ Object



20
21
22
# File 'lib/crystalline/module.rb', line 20

def self.needs_string_conversion(val)
  val.class.respond_to?(:enums) || val.is_a?(DateTime) || val.nil?
end

.non_nilable_attr_count(klass) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/crystalline/module.rb', line 76

def self.non_nilable_attr_count(klass)
  # somewhat sane sort ordering for Union deserialization.
  # All Crystalline objects return the number of non-nilable fields
  # All non-string primitives return 2
  # All arrays and hashes return 1
  # Strings return 0 (since any data can deserialize to a string, it should be our last attempt)
  if klass.respond_to? :fields
    return -1 * klass.fields.count do |field|
      !::Crystalline::Utils.nilable? field.type
    end
  else
    if klass == String
      return 0
    elsif klass.is_a?(T::Types::TypedArray) || klass.is_a?(T::Types::TypedHash)
      return 1
    end
    return 2
  end
end

.to_dict(complex) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
# File 'lib/crystalline/module.rb', line 8

def self.to_dict(complex)
  if complex.is_a? Array
    complex.map { |v| Crystalline.to_dict(v) }
  elsif complex.is_a? Hash
    complex.transform_values { |v| Crystalline.to_dict(v) }
  elsif complex.respond_to?(:class) && complex.class.include?(::Crystalline::MetadataFields)
    complex.to_dict
  else
    json_encode complex, primitives: false
  end
end

.to_json(complex) ⇒ Object



24
25
26
# File 'lib/crystalline/module.rb', line 24

def self.to_json(complex)
  JSON.dump(to_dict(complex))
end

.unmarshal_json(data, type) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/crystalline/module.rb', line 28

def self.unmarshal_json(data, type)
  if Crystalline::Utils.nilable? type
    type = Crystalline::Utils.nilable_of type
  end
  if type.instance_of?(Class) && type.include?(::Crystalline::MetadataFields)
    type.from_dict(data)
  elsif Crystalline::Utils.union? type
    unmarshal_union(data, type)
  elsif Crystalline::Utils.arr? type
    data.map { |v| Crystalline.unmarshal_json(v, Crystalline::Utils.arr_of(type)) }
  elsif Crystalline::Utils.hash? type
    data.transform_values { |v| Crystalline.unmarshal_json(v, Crystalline::Utils.hash_of(type)) }
  elsif Crystalline::Utils.nilable?(type) && data == 'null'
    nil
  elsif Crystalline::Utils.boolean? type
    Crystalline::Utils.to_boolean(data)
  elsif type.is_a?(Class) && type < T::Enum
    type.deserialize(data)
  else
    data
  end
end

.unmarshal_union(data, type) ⇒ Object



51
52
53
54
55
56
57
58
59
60
# File 'lib/crystalline/module.rb', line 51

def self.unmarshal_union(data, type)
  union_types = Crystalline::Utils.get_union_types(type)
  union_types = union_types.sort_by { |klass| Crystalline.non_nilable_attr_count(klass) }

  union_types.each do |union_type|
    return Crystalline.unmarshal_json(data, union_type)
  rescue TypeError, NoMethodError, KeyError
    next
  end
end