Registry.select()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
1
# frozen_String_literal: true
2
3
require_relative '../mixin/errors'
4
require_relative 'parameter'
5
require_relative 'builtin/enumerable_type'
6
require_relative 'builtin/array_type'
7
require_relative 'builtin/hash_type'
8
require_relative 'builtin/hash_tuple_type'
9
require_relative 'builtin/set_type'
10
require_relative 'builtin/primitive_type'
11
require_relative 'builtin/rational_type'
12
require_relative 'builtin/datetime_type'
13
14
module AMA
15
  module Entity
16
    class Mapper
17
      class Type
18
        # Holds all registered types
19
        class Registry
20
          include Mixin::Errors
21
22
          attr_accessor :types
23
24
          def initialize
25
            @types = {}
26
          end
27
28
          # @return [AMA::Entity::Mapper::Type::Registry]
29
          def with_default_types
30
            register(BuiltIn::EnumerableType::INSTANCE)
31
            register(BuiltIn::ArrayType::INSTANCE)
32
            register(BuiltIn::HashType::INSTANCE)
33
            register(BuiltIn::SetType::INSTANCE)
34
            register(BuiltIn::HashTupleType::INSTANCE)
35
            register(BuiltIn::RationalType::INSTANCE)
36
            register(BuiltIn::DateTimeType::INSTANCE)
37
            BuiltIn::PrimitiveType::ALL.each do |type|
38
              register(type)
39
            end
40
            self
41
          end
42
43
          # @param [Class, Module] klass
44
          def [](klass)
45
            @types[klass]
46
          end
47
48
          # @param [AMA::Entity::Mapper::Type] type
49
          def register(type)
50
            @types[type.type] = type
51
          end
52
53
          # @param [Class] klass
54
          def key?(klass)
55
            @types.key?(klass)
56
          end
57
58
          alias registered? key?
59
60
          # @param [Class, Module] klass
61
          # @return [Array<AMA::Entity::Mapper::Type>]
62
          def select(klass)
63
            types = class_hierarchy(klass).map do |entry|
64
              @types[entry]
65
            end
66
            types.reject(&:nil?)
67
          end
68
69
          # @param [Class, Module] klass
70
          # @return [AMA::Entity::Mapper::Type, NilClass]
71
          def find(klass)
72
            candidates = select(klass)
73
            candidates.empty? ? nil : candidates.first
74
          end
75
76
          # @param [Class, Module] klass
77
          # @return [AMA::Entity::Mapper::Type]
78
          def find!(klass)
79
            candidate = find(klass)
80
            return candidate if candidate
81
            message = "Could not find any registered type for class #{klass}"
82
            compliance_error(message)
83
          end
84
85
          # @param [Class, Module] klass
86
          # @return [TrueClass, FalseClass]
87
          def resolvable?(klass)
88
            !select(klass).empty?
89
          end
90
91
          private
92
93
          # @param [Class, Module] klass
94
          def class_hierarchy(klass)
95
            ptr = klass
96
            chain = []
97
            loop do
98
              chain.push(*class_with_modules(ptr))
99
              break if !ptr.respond_to?(:superclass) || ptr.superclass.nil?
100
              ptr = ptr.superclass
101
            end
102
            chain
103
          end
104
105
          def class_with_modules(klass)
106
            if klass.superclass.nil?
107
              parent_modules = []
108
            else
109
              parent_modules = klass.superclass.included_modules
110
            end
111
            [klass, *(klass.included_modules - parent_modules)]
112
          end
113
        end
114
      end
115
    end
116
  end
117
end
118