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

included

Class Attribute Details

.discriminatorObject (readonly)

Returns the value of attribute discriminator.



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

def discriminator
  @discriminator
end

.typesObject (readonly)

Returns the value of attribute types.



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

def types
  @types
end

Class Method Details

.construct(constructor_block, **_options) ⇒ Object



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

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

  self.instance_eval(&constructor_block)
  self
end

.constructable?Boolean

Returns:



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

def self.constructable?
  true
end

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



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

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

.describe_typesObject



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

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:



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

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



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

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

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



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

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

.given(value, type) ⇒ Object



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

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

.inherited(klass) ⇒ Object



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

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

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



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

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



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

def self.native_type
  self
end

.on(discriminator) ⇒ Object



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

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

.parse(value, context) ⇒ Object



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

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_hash)
    value.to_hash
  else
    raise Attributor::IncompatibleTypeError, context: context, value_type: value.class, type: self
  end
end

.valid_type?(value) ⇒ Boolean

Returns:



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

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