File: hash_transform.rb

package info (click to toggle)
ruby-morpher 0.2.6-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 520 kB
  • sloc: ruby: 2,366; makefile: 4
file content (149 lines) | stat: -rw-r--r-- 3,512 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
module Morpher
  class Evaluator
    class Transformer

      # Too complex hash transformation evaluator
      #
      # FIXME: Should be broken up in better
      # primitives a decompose, compose pair
      #
      # @api private
      #
      class HashTransform < self
        include Nary

        register :hash_transform

        # Test if evaluator is transitive
        #
        # FIXME: Needs to be calculated dynamically
        #
        # @return [true]
        #   if evaluator is transitive
        #
        # @return [false]
        #   otherwise
        #
        # @api private
        #
        def transitive?
          body.all?(&self.class.method(:transitive_keypair?))
        end

        # Test if evaluator is a keypair
        #
        # FIXME: Refactor the need for this away.
        #
        #   This is a side effect from this class is
        #   generally to big in sense of SRP.
        #   Must be refactorable away. But dunno now.
        #   Still exploring.
        #
        # @param [Evaluator]
        #
        # @api private
        #
        def self.transitive_keypair?(evaluator)
          return false unless evaluator.kind_of?(Block)

          body = evaluator.body

          left, operator, right = body if body.length.equal?(3)

          left.kind_of?(Key::Fetch) &&
          right.kind_of?(Key::Dump) &&
          operator.transitive?
        end

        # Call evaluator
        #
        # @param [Object] input
        #
        # @return [Object]
        #
        # @api private
        #
        def call(input)
          content = body.map do |node|
            node.call(input)
          end
          Hash[content]
        end

        # Return inverse evaluator
        #
        # @return [HashTransform]
        #
        # @api private
        #
        def inverse
          self.class.new(body.map(&:inverse))
        end

        # Return evaluation
        #
        # @param [Input]
        #
        # @return [Evaluation::Nary]
        #
        # @api private
        #
        # rubocop:disable MethodLength
        #
        def evaluation(input)
          evaluations = body.each_with_object([]) do |evaluator, aggregate|
            evaluation = evaluator.evaluation(input)
            aggregate << evaluation
            unless evaluation.success?
              return evaluation_error(input, aggregate)
            end
          end

          output = Hash[evaluations.map(&:output)]

          Evaluation::Nary.success(
            evaluator:   self,
            input:       input,
            evaluations: evaluations,
            output:      output
          )
        end

      private

        # Return evaluation error
        #
        # @return [Object] input
        #
        # @return [Array<Evaluations>] evaluations
        #
        # @api private
        #
        def evaluation_error(input, evaluations)
          Evaluation::Nary.error(
            evaluator:   self,
            input:       input,
            evaluations: evaluations
          )
        end

        # Build evaluator from node
        #
        # @param [Compiler] compiler
        # @param [Node] node
        #
        # @return [Evaluator]
        #
        # @api private
        #
        def self.build(compiler, node)
          body = node.children.map do |child|
            compiler.call(child)
          end
          new(body)
        end

      end # HashTransform
    end # Transformer
  end # Evaluator
end # Morpher