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.

Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/.circle.yml +6 -0
  3. data/.gitignore +5 -0
  4. data/.rspec +4 -0
  5. data/.rubocop.yml +8 -0
  6. data/Changelog.md +60 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +20 -0
  9. data/README.md +56 -0
  10. data/Rakefile +95 -0
  11. data/circle.yml +7 -0
  12. data/config/devtools.yml +2 -0
  13. data/config/flay.yml +3 -0
  14. data/config/flog.yml +2 -0
  15. data/config/heckle.yml +3 -0
  16. data/config/mutant.yml +8 -0
  17. data/config/reek.yml +109 -0
  18. data/config/rubocop.yml +138 -0
  19. data/config/yardstick.yml +2 -0
  20. data/examples/README.md +13 -0
  21. data/examples/a.rb +25 -0
  22. data/examples/b.rb +35 -0
  23. data/lib/morpher.rb +111 -0
  24. data/lib/morpher/compiler.rb +17 -0
  25. data/lib/morpher/compiler/emitter.rb +82 -0
  26. data/lib/morpher/compiler/error.rb +84 -0
  27. data/lib/morpher/compiler/evaluator.rb +63 -0
  28. data/lib/morpher/compiler/evaluator/emitter.rb +224 -0
  29. data/lib/morpher/compiler/preprocessor.rb +29 -0
  30. data/lib/morpher/compiler/preprocessor/emitter.rb +54 -0
  31. data/lib/morpher/compiler/preprocessor/emitter/anima.rb +69 -0
  32. data/lib/morpher/compiler/preprocessor/emitter/boolean.rb +31 -0
  33. data/lib/morpher/compiler/preprocessor/emitter/key.rb +87 -0
  34. data/lib/morpher/compiler/preprocessor/emitter/noop.rb +45 -0
  35. data/lib/morpher/compiler/preprocessor/emitter/param.rb +50 -0
  36. data/lib/morpher/evaluation.rb +118 -0
  37. data/lib/morpher/evaluator.rb +40 -0
  38. data/lib/morpher/evaluator/binary.rb +46 -0
  39. data/lib/morpher/evaluator/nary.rb +97 -0
  40. data/lib/morpher/evaluator/nullary.rb +92 -0
  41. data/lib/morpher/evaluator/nullary/parameterized.rb +48 -0
  42. data/lib/morpher/evaluator/predicate.rb +22 -0
  43. data/lib/morpher/evaluator/predicate/boolean.rb +76 -0
  44. data/lib/morpher/evaluator/predicate/contradiction.rb +36 -0
  45. data/lib/morpher/evaluator/predicate/eql.rb +50 -0
  46. data/lib/morpher/evaluator/predicate/negation.rb +52 -0
  47. data/lib/morpher/evaluator/predicate/primitive.rb +49 -0
  48. data/lib/morpher/evaluator/predicate/tautology.rb +36 -0
  49. data/lib/morpher/evaluator/transformer.rb +75 -0
  50. data/lib/morpher/evaluator/transformer/attribute.rb +25 -0
  51. data/lib/morpher/evaluator/transformer/block.rb +81 -0
  52. data/lib/morpher/evaluator/transformer/coerce.rb +166 -0
  53. data/lib/morpher/evaluator/transformer/custom.rb +34 -0
  54. data/lib/morpher/evaluator/transformer/domain.rb +86 -0
  55. data/lib/morpher/evaluator/transformer/domain/attribute_accessors.rb +60 -0
  56. data/lib/morpher/evaluator/transformer/domain/attribute_hash.rb +52 -0
  57. data/lib/morpher/evaluator/transformer/domain/instance_variables.rb +60 -0
  58. data/lib/morpher/evaluator/transformer/domain/param.rb +54 -0
  59. data/lib/morpher/evaluator/transformer/guard.rb +62 -0
  60. data/lib/morpher/evaluator/transformer/hash_transform.rb +149 -0
  61. data/lib/morpher/evaluator/transformer/input.rb +37 -0
  62. data/lib/morpher/evaluator/transformer/key.rb +86 -0
  63. data/lib/morpher/evaluator/transformer/map.rb +100 -0
  64. data/lib/morpher/evaluator/transformer/merge.rb +25 -0
  65. data/lib/morpher/evaluator/transformer/static.rb +27 -0
  66. data/lib/morpher/evaluator/unary.rb +79 -0
  67. data/lib/morpher/node_helpers.rb +19 -0
  68. data/lib/morpher/printer.rb +233 -0
  69. data/lib/morpher/printer/mixin.rb +58 -0
  70. data/lib/morpher/registry.rb +51 -0
  71. data/lib/morpher/type_lookup.rb +51 -0
  72. data/morpher.gemspec +29 -0
  73. data/spec/integration_spec.rb +184 -0
  74. data/spec/rcov.opts +7 -0
  75. data/spec/shared/evaluator_behavior.rb +155 -0
  76. data/spec/spec_helper.rb +36 -0
  77. data/spec/support/ice_nine_config.rb +8 -0
  78. data/spec/support/let_mock_helper.rb +8 -0
  79. data/spec/support/strip_helper.rb +12 -0
  80. data/spec/unit/morpher/compiler/preprocessor_spec.rb +46 -0
  81. data/spec/unit/morpher/evaluator/nullary/parameterized_spec.rb +25 -0
  82. data/spec/unit/morpher/evaluator/predicate/boolean/and_spec.rb +11 -0
  83. data/spec/unit/morpher/evaluator/predicate/boolean/or_spec.rb +26 -0
  84. data/spec/unit/morpher/evaluator/predicate/boolean/xor_spec.rb +26 -0
  85. data/spec/unit/morpher/evaluator/predicate/contrandiction_spec.rb +7 -0
  86. data/spec/unit/morpher/evaluator/predicate/eql_spec.rb +11 -0
  87. data/spec/unit/morpher/evaluator/predicate/negation_spec.rb +10 -0
  88. data/spec/unit/morpher/evaluator/predicate/primitive_spec.rb +17 -0
  89. data/spec/unit/morpher/evaluator/predicate/tautology_spec.rb +7 -0
  90. data/spec/unit/morpher/evaluator/transformer/attribute_spec.rb +9 -0
  91. data/spec/unit/morpher/evaluator/transformer/block_spec.rb +92 -0
  92. data/spec/unit/morpher/evaluator/transformer/coerce/parse_int_spec.rb +23 -0
  93. data/spec/unit/morpher/evaluator/transformer/custom_spec.rb +13 -0
  94. data/spec/unit/morpher/evaluator/transformer/domain/attribute_accessors_spec.rb +48 -0
  95. data/spec/unit/morpher/evaluator/transformer/domain/attribute_hash_spec.rb +40 -0
  96. data/spec/unit/morpher/evaluator/transformer/domain/instance_variables_spec.rb +47 -0
  97. data/spec/unit/morpher/evaluator/transformer/guard_spec.rb +12 -0
  98. data/spec/unit/morpher/evaluator/transformer/hash_transform_spec.rb +47 -0
  99. data/spec/unit/morpher/evaluator/transformer/input_spec.rb +11 -0
  100. data/spec/unit/morpher/evaluator/transformer/map_spec.rb +25 -0
  101. data/spec/unit/morpher/evaluator/transformer/static_spec.rb +10 -0
  102. data/spec/unit/morpher/evaluator_spec.rb +15 -0
  103. data/spec/unit/morpher/printer_spec.rb +21 -0
  104. data/spec/unit/morpher/registry_spec.rb +11 -0
  105. data/spec/unit/morpher_spec.rb +53 -0
  106. metadata +302 -0
@@ -0,0 +1,50 @@
1
+ module Morpher
2
+ class Evaluator
3
+ class Predicate
4
+ # Binary equal evaluator
5
+ class EQL < self
6
+ include Binary
7
+
8
+ register :eql
9
+
10
+ # Call evaluator
11
+ #
12
+ # @param [Object] input
13
+ #
14
+ # @return [true]
15
+ # if input is semantically equivalent to expectation
16
+ #
17
+ # @return [false]
18
+ # otherwise
19
+ #
20
+ # @api private
21
+ #
22
+ def call(input)
23
+ left.call(input).eql?(right.call(input))
24
+ end
25
+
26
+ # Return evaluation
27
+ #
28
+ # @param [Object] input
29
+ #
30
+ # @return [Evaluation]
31
+ #
32
+ # @api private
33
+ #
34
+ def evaluation(input)
35
+ left_evaluation = left.evaluation(input)
36
+ right_evaluation = right.evaluation(input)
37
+
38
+ Evaluation::Binary.success(
39
+ evaluator: self,
40
+ input: input,
41
+ output: left_evaluation.output.eql?(right_evaluation.output),
42
+ left_evaluation: left_evaluation,
43
+ right_evaluation: right_evaluation
44
+ )
45
+ end
46
+
47
+ end # EQL
48
+ end # Predicate
49
+ end # Evaluator
50
+ end # Morpher
@@ -0,0 +1,52 @@
1
+ module Morpher
2
+ class Evaluator
3
+ class Predicate
4
+ # Predicate negation
5
+ class Negation < self
6
+ include Unary
7
+
8
+ register :negate
9
+
10
+ # Return evaluation for input
11
+ #
12
+ # @param [Object] input
13
+ #
14
+ # @return [Evaluation]
15
+ #
16
+ # @api private
17
+ #
18
+ def evaluation(input)
19
+ operand_output = operand.call(input)
20
+ evaluation_success(input, operand_output, !operand_output)
21
+ end
22
+
23
+ # Call evaluator
24
+ #
25
+ # @param [Object] input
26
+ #
27
+ # @return [true]
28
+ # if input NOT evaluated to true under operand
29
+ #
30
+ # @return [false]
31
+ # otherwise
32
+ #
33
+ # @api private
34
+ #
35
+ def call(input)
36
+ !operand.call(input)
37
+ end
38
+
39
+ # Return inverse evaluator
40
+ #
41
+ # @return [Evaluator]
42
+ #
43
+ # @api private
44
+ #
45
+ def inverse
46
+ operand
47
+ end
48
+
49
+ end # Negation
50
+ end # Predicate
51
+ end # Evaluator
52
+ end # Morpher
@@ -0,0 +1,49 @@
1
+ module Morpher
2
+ class Evaluator
3
+ class Predicate
4
+ # Abstract namespace class for predicate evaluators on primitives
5
+ class Primitive < self
6
+ include Nullary::Parameterized
7
+
8
+ # Evaluator for exact primitive match
9
+ class Exact < self
10
+
11
+ register :primitive
12
+
13
+ # Call evaluator
14
+ #
15
+ # @param [Object] object
16
+ #
17
+ # @return [true]
18
+ # if object's type is #equal?
19
+ #
20
+ # @api private
21
+ #
22
+ def call(object)
23
+ object.class.equal?(param)
24
+ end
25
+
26
+ end # Exact
27
+
28
+ # Evaluator for permissive primtivie match
29
+ class Permissive < self
30
+ register :is_a
31
+
32
+ # Call evaluator
33
+ #
34
+ # @param [Object] object
35
+ #
36
+ # @return [true]
37
+ # if objects type equals exactly
38
+ #
39
+ # @api private
40
+ #
41
+ def call(object)
42
+ object.kind_of?(param)
43
+ end
44
+
45
+ end # Permissive
46
+ end # Primitive
47
+ end # Predicate
48
+ end # Evaluator
49
+ end # Morpher
@@ -0,0 +1,36 @@
1
+ module Morpher
2
+ class Evaluator
3
+ class Predicate
4
+
5
+ # Evaluator for trautology
6
+ class Tautology < self
7
+ include Nullary
8
+
9
+ register :true
10
+
11
+ # Call predicate evaluator
12
+ #
13
+ # @param [Object] _input
14
+ #
15
+ # @return [true]
16
+ #
17
+ # @api private
18
+ #
19
+ def call(_input)
20
+ true
21
+ end
22
+
23
+ # Return inverse evaluator
24
+ #
25
+ # @return [Evaluator]
26
+ #
27
+ # @api private
28
+ #
29
+ def inverse
30
+ Contradiction.new
31
+ end
32
+
33
+ end # Tautology
34
+ end # Predicate
35
+ end # Evaluator
36
+ end # Morpher
@@ -0,0 +1,75 @@
1
+ module Morpher
2
+ class Evaluator
3
+ # Abstract namespace class for transforming evaluators
4
+ class Transformer < self
5
+ include AbstractType
6
+
7
+ # Error raised when transformation cannot continue
8
+ class TransformError < RuntimeError
9
+ include Concord.new(:transformer, :input)
10
+ end
11
+
12
+ # Test evaluator transformer is transitive
13
+ #
14
+ # A transitive evaluator allows to inverse an operation
15
+ # via its #inverse evaluator.
16
+ #
17
+ # @return [true]
18
+ # if transformer is transitive
19
+ #
20
+ # @return [false]
21
+ # otherwise
22
+ #
23
+ # @api private
24
+ #
25
+ abstract_method :transitive?
26
+
27
+ # Mixin for evaluators that are transitive by definition
28
+ module Transitive
29
+
30
+ # Test if evaluator is transitive
31
+ #
32
+ # @return [false]
33
+ #
34
+ # @api private
35
+ #
36
+ def transitive?
37
+ true
38
+ end
39
+
40
+ end # Intransitive
41
+
42
+ # Mixin for evaluators that are intransitive by definition
43
+ module Intransitive
44
+
45
+ # Test if evaluator is transitive
46
+ #
47
+ # @return [false]
48
+ #
49
+ # @api private
50
+ #
51
+ def transitive?
52
+ false
53
+ end
54
+
55
+ end # Intransitive
56
+
57
+ private
58
+
59
+ # Raise transform error
60
+ #
61
+ # @param [Object] input
62
+ #
63
+ # @raise [TransformError]
64
+ #
65
+ # @return [undefined]
66
+ #
67
+ # @api private
68
+ #
69
+ def raise_transform_error(input)
70
+ fail TransformError.new(self, input)
71
+ end
72
+
73
+ end # Transform
74
+ end # Evaluator
75
+ end # Morpher
@@ -0,0 +1,25 @@
1
+ module Morpher
2
+ class Evaluator
3
+ class Transformer
4
+ # Transformer to return a specific attribute of input
5
+ class Attribute < self
6
+ include Nullary::Parameterized, Intransitive
7
+
8
+ register :attribute
9
+
10
+ # Call evaluator
11
+ #
12
+ # @param [Object] input
13
+ #
14
+ # @return [Object]
15
+ #
16
+ # @api private
17
+ #
18
+ def call(input)
19
+ input.public_send(param)
20
+ end
21
+
22
+ end # Attribute
23
+ end # Transformer
24
+ end # Evaluator
25
+ end # Morpher
@@ -0,0 +1,81 @@
1
+ module Morpher
2
+ class Evaluator
3
+ class Transformer
4
+
5
+ # Evaluator to perform n transformations in a row
6
+ class Block < self
7
+ include Nary
8
+
9
+ register :block
10
+
11
+ # Test if evaluator is transitive
12
+ #
13
+ # @return [true]
14
+ # if block is transitive
15
+ #
16
+ # @return [false]
17
+ # otherwise
18
+ #
19
+ # @api private
20
+ #
21
+ def transitive?
22
+ body.all?(&:transitive?)
23
+ end
24
+
25
+ # Call transformer
26
+ #
27
+ # @param [Object] input
28
+ #
29
+ # @return [Object]
30
+ #
31
+ # @api private
32
+ #
33
+ def call(input)
34
+ body.reduce(input) do |state, evaluator|
35
+ evaluator.call(state)
36
+ end
37
+ end
38
+
39
+ # Return inverse evaluator
40
+ #
41
+ # @return [Evaluator]
42
+ #
43
+ # @api private
44
+ #
45
+ def inverse
46
+ self.class.new(body.reverse.map(&:inverse))
47
+ end
48
+
49
+ # Return evaluation for input
50
+ #
51
+ # @param [Object] input
52
+ #
53
+ # @return [Evaluation::Nary]
54
+ #
55
+ # @api private
56
+ #
57
+ # rubocop:disable MethodLength
58
+ #
59
+ def evaluation(input)
60
+ state = input
61
+
62
+ evaluations = body.each_with_object([]) do |evaluator, aggregate|
63
+ evaluation = evaluator.evaluation(state)
64
+ aggregate << evaluation
65
+ unless evaluation.success?
66
+ return evaluation_error(input, aggregate)
67
+ end
68
+ state = evaluation.output
69
+ end
70
+
71
+ Evaluation::Nary.success(
72
+ evaluator: self,
73
+ input: input,
74
+ output: state,
75
+ evaluations: evaluations
76
+ )
77
+ end
78
+ end # Block
79
+ end # Transformer
80
+ end # Evaluato
81
+ end # Morpher
@@ -0,0 +1,166 @@
1
+ module Morpher
2
+ class Evaluator
3
+ class Transformer
4
+ # Abstract namespace class for coercing transformers
5
+ class Coerce < self
6
+ include AbstractType, Nullary::Parameterized, Transitive
7
+
8
+ # Parse mixin for cases the parsing possibly results
9
+ # in Argument and Type errors.
10
+ module Parse
11
+
12
+ # Call evaluator
13
+ #
14
+ # @param [Object] input
15
+ #
16
+ # @return [Object]
17
+ #
18
+ # @api private
19
+ #
20
+ def call(input)
21
+ invoke(input)
22
+ rescue ArgumentError, TypeError
23
+ raise_transform_error(input)
24
+ end
25
+
26
+ # Return evaluation
27
+ #
28
+ # @param [Object] input
29
+ #
30
+ # @return [Evaluation]
31
+ #
32
+ # @api private
33
+ #
34
+ def evaluation(input)
35
+ evaluation_success(input, invoke(input))
36
+ rescue ArgumentError, TypeError
37
+ evaluation_error(input)
38
+ end
39
+ end # Parse
40
+
41
+ # Evaluator for parsing an integer
42
+ class ParseInt < self
43
+
44
+ include Parse
45
+
46
+ register :parse_int
47
+
48
+ # Return inverse evaluator
49
+ #
50
+ # @return [Evaluator]
51
+ #
52
+ # @api private
53
+ #
54
+ def inverse
55
+ IntToString.new(param)
56
+ end
57
+
58
+ private
59
+
60
+ # Invoke coercion
61
+ #
62
+ # @return [Integer]
63
+ #
64
+ # @raise [ArgumentError, TypeError]
65
+ # if coercion does not succeed
66
+ #
67
+ # @api private
68
+ #
69
+ def invoke(input)
70
+ Integer(input, param)
71
+ end
72
+
73
+ end # ParseInt
74
+
75
+ # Evaluator for dumping fixnums to strings
76
+ class IntToString < self
77
+
78
+ register :int_to_string
79
+
80
+ # Call evaluator
81
+ #
82
+ # @param [Object] input
83
+ #
84
+ # @return [Hash<Symbol, Object>]
85
+ #
86
+ # @api private
87
+ #
88
+ def call(input)
89
+ input.to_s(param)
90
+ end
91
+
92
+ # Return inverse evaluator
93
+ #
94
+ # @return [Evaluator]
95
+ #
96
+ # @api private
97
+ #
98
+ def inverse
99
+ ParseInt.new(param)
100
+ end
101
+
102
+ end # IntToString
103
+
104
+ # Evaluator for parsing an ISO8601 String into a DateTime
105
+ class ParseIso8601DateTime < self
106
+
107
+ include Parse
108
+
109
+ register :parse_iso8601_date_time
110
+
111
+ # Return inverse evaluator
112
+ #
113
+ # @return [Evaluator]
114
+ #
115
+ # @api private
116
+ #
117
+ def inverse
118
+ DateTimeToIso8601String.new(param)
119
+ end
120
+
121
+ private
122
+
123
+ # Invoke coercion
124
+ #
125
+ # @return [DateTime]
126
+ #
127
+ # @raise [ArgumentError, TypeError]
128
+ # if coercion does not succeed
129
+ #
130
+ # @api private
131
+ #
132
+ def invoke(input)
133
+ DateTime.iso8601(input)
134
+ end
135
+ end # ParseIso8601DateTime
136
+
137
+ # Evaluator for dumping a DateTime to an ISO8601 string
138
+ class DateTimeToIso8601String < self
139
+ register :date_time_to_iso8601_string
140
+
141
+ # Call evaluator
142
+ #
143
+ # @param [Object] input
144
+ #
145
+ # @return [Object]
146
+ #
147
+ # @api private
148
+ #
149
+ def call(input)
150
+ input.iso8601(param)
151
+ end
152
+
153
+ # Return inverse evaluator
154
+ #
155
+ # @return [Evaluator]
156
+ #
157
+ # @api private
158
+ #
159
+ def inverse
160
+ ParseIso8601DateTime.new(param)
161
+ end
162
+ end # DateTimeToIso8601String
163
+ end # Fixnum
164
+ end # Transformer
165
+ end # Evaluator
166
+ end # Morpher