65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
# File 'lib/crystalline/metadata_fields.rb', line 65
def from_dict(d)
to_build = {}
fields.each do |field|
key = field.name
format_metadata = field.metadata.fetch(:format_json, {})
lookup = format_metadata.fetch(:letter_case, nil).call
value = d[lookup]
field_type = field.type
if ::Crystalline::Utils.nilable? field_type
if value == 'null'
to_build[key] = nil
next
end
field_type = ::Crystalline::Utils.nilable_of(field_type)
end
raise KeyError, "key #{lookup} not found in hash" if value.nil? && !::Crystalline::Utils.nilable?(field.type)
next if value.nil?
if Crystalline::Utils.arr? field_type
inner_type = Crystalline::Utils.arr_of(field_type)
unmarshalled_array = value.map { |f| unmarshal_single(inner_type, f, format_metadata) }
to_build[key] = unmarshalled_array
elsif Crystalline::Utils.hash? field_type
val_type = Crystalline::Utils.hash_of(field_type)
unmarshalled_hash = value.map { |k, v| [k, unmarshal_single(val_type, v, format_metadata)] }.to_h
to_build[key] = unmarshalled_hash
elsif Crystalline::Utils.union? field_type
discriminator = field.metadata.fetch(:discriminator, nil)
discriminator_mapping = field.metadata.fetch(:discriminator_mapping, nil)
if !discriminator.nil?
discriminator_value = value.fetch(discriminator)
if !discriminator_mapping.nil?
type_to_deserialize = discriminator_mapping[discriminator_value]
else
type_to_deserialize = Crystalline::Utils.get_union_types(field_type).find { |t| t.name.split('::').last == discriminator_value }
end
to_build[key] = Crystalline.unmarshal_json(value, type_to_deserialize)
else
union_types = Crystalline::Utils.get_union_types(field_type)
union_types = union_types.sort_by { |klass| Crystalline.non_nilable_attr_count(klass) }
union_types.each do |union_type|
begin
to_build[key] = Crystalline.unmarshal_json(value, union_type)
rescue TypeError
next
rescue NoMethodError
next
rescue KeyError
next
end
break
end
end
elsif field_type.instance_of?(Class) && field_type.include?(::Crystalline::MetadataFields)
to_build[key] = Crystalline.unmarshal_json(value, field_type)
else
to_build[key] = unmarshal_single(field_type, value, format_metadata)
end
end
new(**to_build)
end
|