morpher 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of morpher might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.circle.yml +6 -0
- data/.gitignore +5 -0
- data/.rspec +4 -0
- data/.rubocop.yml +8 -0
- data/Changelog.md +60 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +56 -0
- data/Rakefile +95 -0
- data/circle.yml +7 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/heckle.yml +3 -0
- data/config/mutant.yml +8 -0
- data/config/reek.yml +109 -0
- data/config/rubocop.yml +138 -0
- data/config/yardstick.yml +2 -0
- data/examples/README.md +13 -0
- data/examples/a.rb +25 -0
- data/examples/b.rb +35 -0
- data/lib/morpher.rb +111 -0
- data/lib/morpher/compiler.rb +17 -0
- data/lib/morpher/compiler/emitter.rb +82 -0
- data/lib/morpher/compiler/error.rb +84 -0
- data/lib/morpher/compiler/evaluator.rb +63 -0
- data/lib/morpher/compiler/evaluator/emitter.rb +224 -0
- data/lib/morpher/compiler/preprocessor.rb +29 -0
- data/lib/morpher/compiler/preprocessor/emitter.rb +54 -0
- data/lib/morpher/compiler/preprocessor/emitter/anima.rb +69 -0
- data/lib/morpher/compiler/preprocessor/emitter/boolean.rb +31 -0
- data/lib/morpher/compiler/preprocessor/emitter/key.rb +87 -0
- data/lib/morpher/compiler/preprocessor/emitter/noop.rb +45 -0
- data/lib/morpher/compiler/preprocessor/emitter/param.rb +50 -0
- data/lib/morpher/evaluation.rb +118 -0
- data/lib/morpher/evaluator.rb +40 -0
- data/lib/morpher/evaluator/binary.rb +46 -0
- data/lib/morpher/evaluator/nary.rb +97 -0
- data/lib/morpher/evaluator/nullary.rb +92 -0
- data/lib/morpher/evaluator/nullary/parameterized.rb +48 -0
- data/lib/morpher/evaluator/predicate.rb +22 -0
- data/lib/morpher/evaluator/predicate/boolean.rb +76 -0
- data/lib/morpher/evaluator/predicate/contradiction.rb +36 -0
- data/lib/morpher/evaluator/predicate/eql.rb +50 -0
- data/lib/morpher/evaluator/predicate/negation.rb +52 -0
- data/lib/morpher/evaluator/predicate/primitive.rb +49 -0
- data/lib/morpher/evaluator/predicate/tautology.rb +36 -0
- data/lib/morpher/evaluator/transformer.rb +75 -0
- data/lib/morpher/evaluator/transformer/attribute.rb +25 -0
- data/lib/morpher/evaluator/transformer/block.rb +81 -0
- data/lib/morpher/evaluator/transformer/coerce.rb +166 -0
- data/lib/morpher/evaluator/transformer/custom.rb +34 -0
- data/lib/morpher/evaluator/transformer/domain.rb +86 -0
- data/lib/morpher/evaluator/transformer/domain/attribute_accessors.rb +60 -0
- data/lib/morpher/evaluator/transformer/domain/attribute_hash.rb +52 -0
- data/lib/morpher/evaluator/transformer/domain/instance_variables.rb +60 -0
- data/lib/morpher/evaluator/transformer/domain/param.rb +54 -0
- data/lib/morpher/evaluator/transformer/guard.rb +62 -0
- data/lib/morpher/evaluator/transformer/hash_transform.rb +149 -0
- data/lib/morpher/evaluator/transformer/input.rb +37 -0
- data/lib/morpher/evaluator/transformer/key.rb +86 -0
- data/lib/morpher/evaluator/transformer/map.rb +100 -0
- data/lib/morpher/evaluator/transformer/merge.rb +25 -0
- data/lib/morpher/evaluator/transformer/static.rb +27 -0
- data/lib/morpher/evaluator/unary.rb +79 -0
- data/lib/morpher/node_helpers.rb +19 -0
- data/lib/morpher/printer.rb +233 -0
- data/lib/morpher/printer/mixin.rb +58 -0
- data/lib/morpher/registry.rb +51 -0
- data/lib/morpher/type_lookup.rb +51 -0
- data/morpher.gemspec +29 -0
- data/spec/integration_spec.rb +184 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/evaluator_behavior.rb +155 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/support/ice_nine_config.rb +8 -0
- data/spec/support/let_mock_helper.rb +8 -0
- data/spec/support/strip_helper.rb +12 -0
- data/spec/unit/morpher/compiler/preprocessor_spec.rb +46 -0
- data/spec/unit/morpher/evaluator/nullary/parameterized_spec.rb +25 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/and_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/or_spec.rb +26 -0
- data/spec/unit/morpher/evaluator/predicate/boolean/xor_spec.rb +26 -0
- data/spec/unit/morpher/evaluator/predicate/contrandiction_spec.rb +7 -0
- data/spec/unit/morpher/evaluator/predicate/eql_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/predicate/negation_spec.rb +10 -0
- data/spec/unit/morpher/evaluator/predicate/primitive_spec.rb +17 -0
- data/spec/unit/morpher/evaluator/predicate/tautology_spec.rb +7 -0
- data/spec/unit/morpher/evaluator/transformer/attribute_spec.rb +9 -0
- data/spec/unit/morpher/evaluator/transformer/block_spec.rb +92 -0
- data/spec/unit/morpher/evaluator/transformer/coerce/parse_int_spec.rb +23 -0
- data/spec/unit/morpher/evaluator/transformer/custom_spec.rb +13 -0
- data/spec/unit/morpher/evaluator/transformer/domain/attribute_accessors_spec.rb +48 -0
- data/spec/unit/morpher/evaluator/transformer/domain/attribute_hash_spec.rb +40 -0
- data/spec/unit/morpher/evaluator/transformer/domain/instance_variables_spec.rb +47 -0
- data/spec/unit/morpher/evaluator/transformer/guard_spec.rb +12 -0
- data/spec/unit/morpher/evaluator/transformer/hash_transform_spec.rb +47 -0
- data/spec/unit/morpher/evaluator/transformer/input_spec.rb +11 -0
- data/spec/unit/morpher/evaluator/transformer/map_spec.rb +25 -0
- data/spec/unit/morpher/evaluator/transformer/static_spec.rb +10 -0
- data/spec/unit/morpher/evaluator_spec.rb +15 -0
- data/spec/unit/morpher/printer_spec.rb +21 -0
- data/spec/unit/morpher/registry_spec.rb +11 -0
- data/spec/unit/morpher_spec.rb +53 -0
- metadata +302 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer < self
|
4
|
+
# Custom transformer with external injected behavior
|
5
|
+
class Custom < self
|
6
|
+
include Nullary::Parameterized, Transitive
|
7
|
+
register :custom
|
8
|
+
|
9
|
+
# Call transformer with input
|
10
|
+
#
|
11
|
+
# @param [Object]
|
12
|
+
#
|
13
|
+
# @return [undefinedo]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def call(input)
|
18
|
+
param.first.call(input)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return inverse transformer
|
22
|
+
#
|
23
|
+
# @return [Evaluator::Transformer]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
#
|
27
|
+
def inverse
|
28
|
+
self.class.new(param.reverse)
|
29
|
+
end
|
30
|
+
|
31
|
+
end # Custom
|
32
|
+
end # Transformer
|
33
|
+
end # Evaluator
|
34
|
+
end # Morpher
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
# Abstract namespace class for transformers from/to domain
|
5
|
+
class Domain < self
|
6
|
+
include AbstractType, Nullary::Parameterized, Transitive
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
# Call block with param attributes
|
11
|
+
#
|
12
|
+
# @param [Object] aggregate
|
13
|
+
#
|
14
|
+
# @return [Object]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def transform(aggregate, &block)
|
19
|
+
param.attributes.each_with_object(aggregate, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Mixin for domain dumpers
|
23
|
+
module Dump
|
24
|
+
|
25
|
+
# Return inverse evaluator
|
26
|
+
#
|
27
|
+
# @return [Evaluator]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
#
|
31
|
+
def inverse
|
32
|
+
self.class::Load.new(param)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Dump object
|
38
|
+
#
|
39
|
+
# @param [Symbol] left
|
40
|
+
# @param [Symbol] right
|
41
|
+
#
|
42
|
+
# @return [Object]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
#
|
46
|
+
def dump(&block)
|
47
|
+
transform({}, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
end # Dump
|
51
|
+
|
52
|
+
# Mixin for domain loaders
|
53
|
+
module Load
|
54
|
+
include AbstractType
|
55
|
+
|
56
|
+
# Return inverse evaluator
|
57
|
+
#
|
58
|
+
# @return [Evaluator]
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
#
|
62
|
+
def inverse
|
63
|
+
self.class::Dump.new(param)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Load object
|
69
|
+
#
|
70
|
+
# @param [Symbol] left
|
71
|
+
# @param [Symbol] right
|
72
|
+
#
|
73
|
+
# @return [Object]
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
#
|
77
|
+
def load(&block)
|
78
|
+
transform(param.model.allocate, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
end # Load
|
82
|
+
|
83
|
+
end # Domain
|
84
|
+
end # Transformer
|
85
|
+
end # Evaluator
|
86
|
+
end # Morpher
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
class Domain
|
5
|
+
# Abstract namespace class for domain objects via attribute accessors
|
6
|
+
class AttributeAccessors < self
|
7
|
+
include AbstractType
|
8
|
+
|
9
|
+
# Evaluator for dumping domain objects via instance variables
|
10
|
+
class Dump < self
|
11
|
+
include Domain::Dump
|
12
|
+
|
13
|
+
register :dump_attribute_accessors
|
14
|
+
|
15
|
+
# Call evaluator
|
16
|
+
#
|
17
|
+
# @param [Object] input
|
18
|
+
#
|
19
|
+
# @return [Hash<Symbol, Object>]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
def call(input)
|
24
|
+
dump do |attribute, attributes|
|
25
|
+
name = attribute.name
|
26
|
+
attributes[name] = input.public_send(name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end # Dump
|
31
|
+
|
32
|
+
# Evaluator for loading domain objects via attributes hash
|
33
|
+
class Load < self
|
34
|
+
include Domain::Load
|
35
|
+
|
36
|
+
register :load_attribute_accessors
|
37
|
+
|
38
|
+
# Call evaluator
|
39
|
+
#
|
40
|
+
# @param [Object] input
|
41
|
+
#
|
42
|
+
# @return [Object]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
#
|
46
|
+
def call(input)
|
47
|
+
load do |attribute, object|
|
48
|
+
object.public_send(
|
49
|
+
attribute.writer,
|
50
|
+
input.fetch(attribute.name)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end # Load
|
56
|
+
end # Domain
|
57
|
+
end # Anima
|
58
|
+
end # Transformer
|
59
|
+
end # Evaluator
|
60
|
+
end # Morpher
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
class Domain < self
|
5
|
+
# Abstract namespace class for domain objects on attributes hash
|
6
|
+
class AttributeHash < self
|
7
|
+
include AbstractType
|
8
|
+
|
9
|
+
# Evaluator for dumping domain objects via attributes hash
|
10
|
+
class Dump < self
|
11
|
+
include Domain::Dump
|
12
|
+
|
13
|
+
register :dump_attribute_hash
|
14
|
+
|
15
|
+
# Call evaluator
|
16
|
+
#
|
17
|
+
# @param [Object] input
|
18
|
+
#
|
19
|
+
# @return [Hash<Symbol, Object>]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
def call(input)
|
24
|
+
input.to_h
|
25
|
+
end
|
26
|
+
|
27
|
+
end # Dump
|
28
|
+
|
29
|
+
# Evaluator for loading domain objects via attributes hash
|
30
|
+
class Load < self
|
31
|
+
include Domain::Load
|
32
|
+
|
33
|
+
register :load_attribute_hash
|
34
|
+
|
35
|
+
# Call evaluator
|
36
|
+
#
|
37
|
+
# @param [Object] input
|
38
|
+
#
|
39
|
+
# @return [Object]
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
#
|
43
|
+
def call(input)
|
44
|
+
param.model.new(input)
|
45
|
+
end
|
46
|
+
|
47
|
+
end # Load
|
48
|
+
end # Domain
|
49
|
+
end # Anima
|
50
|
+
end # Transformer
|
51
|
+
end # Evaluator
|
52
|
+
end # Morpher
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
class Domain < self
|
5
|
+
# Abstract namespace class for domain objects via instance variables
|
6
|
+
class InstanceVariables < self
|
7
|
+
include AbstractType
|
8
|
+
|
9
|
+
# Evaluator for dumping domain objects via instance variables
|
10
|
+
class Dump < self
|
11
|
+
include Domain::Dump
|
12
|
+
|
13
|
+
register :dump_instance_variables
|
14
|
+
|
15
|
+
# Call evaluator
|
16
|
+
#
|
17
|
+
# @param [Object] input
|
18
|
+
#
|
19
|
+
# @return [Hash<Symbol, Object>]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
#
|
23
|
+
def call(input)
|
24
|
+
dump do |attribute, attributes|
|
25
|
+
attributes[attribute.name] =
|
26
|
+
input.instance_variable_get(attribute.ivar_name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end # Dump
|
31
|
+
|
32
|
+
# Evaluator for loading domain objects via instance variables
|
33
|
+
class Load < self
|
34
|
+
include Domain::Load
|
35
|
+
|
36
|
+
register :load_instance_variables
|
37
|
+
|
38
|
+
# Call evaluator
|
39
|
+
#
|
40
|
+
# @param [Object] input
|
41
|
+
#
|
42
|
+
# @return [Object]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
#
|
46
|
+
def call(input)
|
47
|
+
load do |attribute, object|
|
48
|
+
object.instance_variable_set(
|
49
|
+
attribute.ivar_name,
|
50
|
+
input.fetch(attribute.name)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end # Load
|
56
|
+
end # Domain
|
57
|
+
end # Anima
|
58
|
+
end # Transformer
|
59
|
+
end # Evaluator
|
60
|
+
end # Morpher
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
class Domain < self
|
5
|
+
|
6
|
+
# Domain specific transformer parameter
|
7
|
+
class Param
|
8
|
+
include Adamantium, Concord::Public.new(:model, :attribute_names)
|
9
|
+
|
10
|
+
# Return attributes
|
11
|
+
#
|
12
|
+
# @return [Enumerable<Attribute>]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def attributes
|
17
|
+
attribute_names.map(&Attribute.method(:new))
|
18
|
+
end
|
19
|
+
memoize :attributes
|
20
|
+
|
21
|
+
# Attribute on a domain transformer param
|
22
|
+
class Attribute
|
23
|
+
include Adamantium, Concord::Public.new(:name)
|
24
|
+
|
25
|
+
# Return instance variable name
|
26
|
+
#
|
27
|
+
# @return [Symbol]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
#
|
31
|
+
def ivar_name
|
32
|
+
:"@#{name}"
|
33
|
+
end
|
34
|
+
memoize :ivar_name
|
35
|
+
|
36
|
+
# Return writer name
|
37
|
+
#
|
38
|
+
# @return [Symbol]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
def writer
|
43
|
+
:"#{name}="
|
44
|
+
end
|
45
|
+
memoize :writer
|
46
|
+
|
47
|
+
end # Attribute
|
48
|
+
|
49
|
+
end # Param
|
50
|
+
|
51
|
+
end # Domain
|
52
|
+
end # Transformer
|
53
|
+
end # Evaluator
|
54
|
+
end # Morpher
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
|
5
|
+
# Transformer that allows to guard transformation process
|
6
|
+
# with a predicate on input
|
7
|
+
class Guard < self
|
8
|
+
include Unary, Transitive
|
9
|
+
|
10
|
+
register :guard
|
11
|
+
|
12
|
+
# Call evaluator
|
13
|
+
#
|
14
|
+
# @param [Object] input
|
15
|
+
#
|
16
|
+
# @return [Object]
|
17
|
+
# if input evaluates true under predicate
|
18
|
+
#
|
19
|
+
# @raise [TransformError]
|
20
|
+
# otherwise
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
def call(input)
|
25
|
+
if operand.call(input)
|
26
|
+
input
|
27
|
+
else
|
28
|
+
fail TransformError.new(self, input)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return evaluation
|
33
|
+
#
|
34
|
+
# @param [Object] input
|
35
|
+
#
|
36
|
+
# @return [Evaluation::Guard]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
#
|
40
|
+
def evaluation(input)
|
41
|
+
operand_evaluation = operand.evaluation(input)
|
42
|
+
if operand_evaluation.output
|
43
|
+
evaluation_success(input, operand_evaluation, input)
|
44
|
+
else
|
45
|
+
evaluation_error(input, operand_evaluation)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return inverse evaluator
|
50
|
+
#
|
51
|
+
# @return [self]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
#
|
55
|
+
def inverse
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
end # Guard
|
60
|
+
end # Transformer
|
61
|
+
end # Evaluator
|
62
|
+
end # Morpher
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module Morpher
|
2
|
+
class Evaluator
|
3
|
+
class Transformer
|
4
|
+
|
5
|
+
# Too complex hash transformation evaluator
|
6
|
+
#
|
7
|
+
# FIXME: Should be broken up in better
|
8
|
+
# primitives a decompose, compose pair
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
class HashTransform < self
|
13
|
+
include Nary
|
14
|
+
|
15
|
+
register :hash_transform
|
16
|
+
|
17
|
+
# Test if evaluator is transitive
|
18
|
+
#
|
19
|
+
# FIXME: Needs to be calculated dynamically
|
20
|
+
#
|
21
|
+
# @return [true]
|
22
|
+
# if evaluator is transitive
|
23
|
+
#
|
24
|
+
# @return [false]
|
25
|
+
# otherwise
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
def transitive?
|
30
|
+
body.all?(&self.class.method(:transitive_keypair?))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Test if evaluator is a keypair
|
34
|
+
#
|
35
|
+
# FIXME: Refactor the need for this away.
|
36
|
+
#
|
37
|
+
# This is a side effect from this class is
|
38
|
+
# generally to big in sense of SRP.
|
39
|
+
# Must be refactorable away. But dunno now.
|
40
|
+
# Still exploring.
|
41
|
+
#
|
42
|
+
# @param [Evaluator]
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
#
|
46
|
+
def self.transitive_keypair?(evaluator)
|
47
|
+
return false unless evaluator.kind_of?(Block)
|
48
|
+
|
49
|
+
body = evaluator.body
|
50
|
+
|
51
|
+
left, operator, right = body if body.length.equal?(3)
|
52
|
+
|
53
|
+
left.kind_of?(Key::Fetch) &&
|
54
|
+
right.kind_of?(Key::Dump) &&
|
55
|
+
operator.transitive?
|
56
|
+
end
|
57
|
+
|
58
|
+
# Call evaluator
|
59
|
+
#
|
60
|
+
# @param [Object] input
|
61
|
+
#
|
62
|
+
# @return [Object]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
#
|
66
|
+
def call(input)
|
67
|
+
content = body.map do |node|
|
68
|
+
node.call(input)
|
69
|
+
end
|
70
|
+
Hash[content]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return inverse evaluator
|
74
|
+
#
|
75
|
+
# @return [HashTransform]
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
#
|
79
|
+
def inverse
|
80
|
+
self.class.new(body.map(&:inverse))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return evaluation
|
84
|
+
#
|
85
|
+
# @param [Input]
|
86
|
+
#
|
87
|
+
# @return [Evaluation::Nary]
|
88
|
+
#
|
89
|
+
# @api private
|
90
|
+
#
|
91
|
+
# rubocop:disable MethodLength
|
92
|
+
#
|
93
|
+
def evaluation(input)
|
94
|
+
evaluations = body.each_with_object([]) do |evaluator, aggregate|
|
95
|
+
evaluation = evaluator.evaluation(input)
|
96
|
+
aggregate << evaluation
|
97
|
+
unless evaluation.success?
|
98
|
+
return evaluation_error(input, aggregate)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
output = Hash[evaluations.map(&:output)]
|
103
|
+
|
104
|
+
Evaluation::Nary.success(
|
105
|
+
evaluator: self,
|
106
|
+
input: input,
|
107
|
+
evaluations: evaluations,
|
108
|
+
output: output
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
# Return evaluation error
|
115
|
+
#
|
116
|
+
# @return [Object] input
|
117
|
+
#
|
118
|
+
# @return [Array<Evaluations>] evaluations
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
#
|
122
|
+
def evaluation_error(input, evaluations)
|
123
|
+
Evaluation::Nary.error(
|
124
|
+
evaluator: self,
|
125
|
+
input: input,
|
126
|
+
evaluations: evaluations
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Build evaluator from node
|
131
|
+
#
|
132
|
+
# @param [Compiler] compiler
|
133
|
+
# @param [Node] node
|
134
|
+
#
|
135
|
+
# @return [Evaluator]
|
136
|
+
#
|
137
|
+
# @api private
|
138
|
+
#
|
139
|
+
def self.build(compiler, node)
|
140
|
+
body = node.children.map do |child|
|
141
|
+
compiler.call(child)
|
142
|
+
end
|
143
|
+
new(body)
|
144
|
+
end
|
145
|
+
|
146
|
+
end # HashTransform
|
147
|
+
end # Transformer
|
148
|
+
end # Evaluator
|
149
|
+
end # Morpher
|