Class: Attributor::Polymorphic

Inherits:
Object
  • Object
show all
Includes:
Type
Defined in:
lib/attributor/types/polymorphic.rb

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from Type

get_memoized_collection_class, set_memoized_collection_class

Class Attribute Details

.discriminatorObject (readonly)

Returns the value of attribute discriminator.



9
10
11
# File 'lib/attributor/types/polymorphic.rb', line 9

def discriminator
  @discriminator
end

.typesObject (readonly)

Returns the value of attribute types.



10
11
12
# File 'lib/attributor/types/polymorphic.rb', line 10

def types
  @types
end

Class Method Details

.construct(constructor_block, **_options) ⇒ Object



45
46
47
48
49
50
# File 'lib/attributor/types/polymorphic.rb', line 45

def self.construct(constructor_block, **_options)
  return self if constructor_block.nil?

  self.instance_eval(&constructor_block)
  self
end

.constructable?Boolean

Returns:



37
38
39
# File 'lib/attributor/types/polymorphic.rb', line 37

def self.constructable?
  true
end

.describe(shallow = false, example: nil) ⇒ Object



106
107
108
109
110
111
# File 'lib/attributor/types/polymorphic.rb', line 106

def self.describe(shallow = false, example: nil)
  super.merge(
    discriminator: self.discriminator,
    types: self.describe_types
  )
end

.describe_typesObject



113
114
115
116
117
# File 'lib/attributor/types/polymorphic.rb', line 113

def self.describe_types
  self.types.each_with_object({}) do |(key, value), description|
    description[key] = { type: value.describe(true) }
  end
end

.discriminator_value_for(parsed_value) ⇒ Object

Raises:



67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/attributor/types/polymorphic.rb', line 67

def self.discriminator_value_for(parsed_value)
  return parsed_value[self.discriminator] if parsed_value.key?(self.discriminator)

  value = case self.discriminator
          when ::String
            parsed_value[self.discriminator.to_sym]
          when ::Symbol
            parsed_value[self.discriminator.to_s]
          end

  return value if value

  raise LoadError, "can't find key #{self.discriminator.inspect} in #{parsed_value.inspect}"
end

.dump(value, **opts) ⇒ Object



82
83
84
85
86
# File 'lib/attributor/types/polymorphic.rb', line 82

def self.dump(value, **opts)
  if (loaded = load(value))
    loaded.dump(**opts)
  end
end

.example(context = nil, **values) ⇒ Object



29
30
31
# File 'lib/attributor/types/polymorphic.rb', line 29

def self.example(context = nil, **values)
  types.values.sample.example(context, **values)
end

.given(value, type) ⇒ Object



19
20
21
# File 'lib/attributor/types/polymorphic.rb', line 19

def self.given(value, type)
  @types[value] = type
end

.inherited(klass) ⇒ Object



23
24
25
26
27
# File 'lib/attributor/types/polymorphic.rb', line 23

def self.inherited(klass)
  klass.instance_eval do
    @types = {}
  end
end

.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/attributor/types/polymorphic.rb', line 52

def self.load(value, context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
  return nil if value.nil?

  return value if self.types.values.include?(value.class)

  parsed_value = self.parse(value, context)

  discriminator_value = discriminator_value_for(parsed_value)

  type = self.types.fetch(discriminator_value) do
    raise LoadError, "invalid value for discriminator: #{discriminator_value}"
  end
  type.load(parsed_value)
end

.native_typeObject



41
42
43
# File 'lib/attributor/types/polymorphic.rb', line 41

def self.native_type
  self
end

.on(discriminator) ⇒ Object



13
14
15
16
17
# File 'lib/attributor/types/polymorphic.rb', line 13

def self.on(discriminator)
  ::Class.new(self) do
    @discriminator = discriminator
  end
end

.parse(value, context) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/attributor/types/polymorphic.rb', line 88

def self.parse(value, context)
  if value.nil?
    {}
  elsif value.is_a?(Attributor::Hash)
    value.contents
  elsif value.is_a?(::Hash)
    value
  elsif value.is_a?(::String)
    decode_json(value, context)
  elsif value.respond_to?(:to_h)
    value.to_h
  elsif value.respond_to?(:to_hash) # Deprecate this in lieu of to_h only?
    value.to_hash
  else
    raise Attributor::IncompatibleTypeError, context: context, value_type: value.class, type: self
  end
end

.valid_type?(value) ⇒ Boolean

Returns:



33
34
35
# File 'lib/attributor/types/polymorphic.rb', line 33

def self.valid_type?(value)
  self.types.values.include?(value.class)
end