Completed
Push — dev ( ffd8f7...ec8098 )
by Fike
51s
created

HashType   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 81
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 7
c 1
b 0
f 0
dl 0
loc 81
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A initialize() 0 9 1
A define_attribute() 0 8 1
A define_denormalizer() 0 8 1
A define_acceptor() 0 10 1
A define_enumerator() 0 11 1
A define_extractor() 0 16 1
A define_normalizer() 0 5 1
1
# frozen_string_literal: true
2
3
require_relative '../concrete'
4
require_relative '../../path/segment'
5
require_relative '../../mixin/errors'
6
require_relative 'pair_type'
7
require_relative '../aux/pair'
8
9
module AMA
10
  module Entity
11
    class Mapper
12
      class Type
13
        module Hardwired
14
          # Predefined type for Hash class
15
          class HashType < Concrete
16
            include Mixin::Errors
17
18
            def initialize
19
              super(::Hash)
20
              define_attribute
21
              define_enumerator
22
              define_acceptor
23
              define_extractor
24
              define_normalizer
25
              define_denormalizer
26
            end
27
28
            private
29
30
            def define_attribute
31
              type = PairType.new
32
              type = type.resolve(
33
                type.parameter!(:L) => parameter!(:K),
34
                type.parameter!(:R) => parameter!(:V)
35
              )
36
              attribute!(:_tuple, type, virtual: true)
37
            end
38
39
            def define_acceptor
40
              acceptor_factory = lambda do |entity, *|
41
                acceptor = Object.new
42
                acceptor.define_singleton_method(:accept) do |_, tuple, *|
43
                  entity[tuple.left] = tuple.right
44
                end
45
                acceptor
46
              end
47
              self.acceptor = acceptor_factory
48
            end
49
50
            def define_enumerator
51
              self.enumerator = lambda do |entity, type, *|
52
                ::Enumerator.new do |yielder|
53
                  entity.each do |key, value|
54
                    tuple = Aux::Pair.new(left: key, right: value)
55
                    attribute = type.attributes[:_tuple]
56
                    yielder << [attribute, tuple, Path::Segment.index(key)]
57
                  end
58
                end
59
              end
60
            end
61
62
            def define_extractor
63
              self.extractor = lambda do |source, type, context = nil, *|
64
                source = source.to_h if source.respond_to?(:to_h)
65
                unless source.is_a?(Hash)
66
                  message = "Expected to receive hash, #{source.class} received"
67
                  mapping_error(message, context: context)
68
                end
69
                ::Enumerator.new do |yielder|
70
                  source.each do |key, value|
71
                    tuple = Aux::Pair.new(left: key, right: value)
72
                    attribute = type.attributes[:_tuple]
73
                    yielder << [attribute, tuple, Path::Segment.index(key)]
74
                  end
75
                end
76
              end
77
            end
78
79
            def define_denormalizer
80
              self.denormalizer = lambda do |input, context, *|
81
                input = input.to_h if input.respond_to?(:to_h)
82
                return input.clone if input.is_a?(Hash)
83
                message = "Expected to receive hash, #{input.class} received"
84
                mapping_error(message, context: context)
85
              end
86
            end
87
88
            def define_normalizer
89
              self.normalizer = lambda do |entity, *|
90
                entity.clone
91
              end
92
            end
93
94
            INSTANCE = new
95
          end
96
        end
97
      end
98
    end
99
  end
100
end
101