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
|