ducktrap 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. checksums.yaml +7 -0
  2. data/.circle.yml +6 -0
  3. data/.gitignore +5 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +16 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.devtools +59 -0
  8. data/Guardfile +18 -0
  9. data/LICENSE +20 -0
  10. data/README.md +47 -0
  11. data/Rakefile +2 -0
  12. data/TODO +4 -0
  13. data/config/devtools.yml +2 -0
  14. data/config/flay.yml +3 -0
  15. data/config/flog.yml +2 -0
  16. data/config/heckle.yml +3 -0
  17. data/config/mutant.yml +2 -0
  18. data/config/reek.yml +98 -0
  19. data/config/yardstick.yml +2 -0
  20. data/ducktrap.gemspec +23 -0
  21. data/lib/ducktrap.rb +73 -0
  22. data/lib/ducktrap/builder.rb +36 -0
  23. data/lib/ducktrap/error.rb +48 -0
  24. data/lib/ducktrap/evaluator.rb +127 -0
  25. data/lib/ducktrap/evaluator/invalid.rb +30 -0
  26. data/lib/ducktrap/evaluator/static.rb +25 -0
  27. data/lib/ducktrap/formatter.rb +138 -0
  28. data/lib/ducktrap/mapper.rb +59 -0
  29. data/lib/ducktrap/nary.rb +148 -0
  30. data/lib/ducktrap/node.rb +94 -0
  31. data/lib/ducktrap/node/anima.rb +40 -0
  32. data/lib/ducktrap/node/anima/dump.rb +39 -0
  33. data/lib/ducktrap/node/anima/load.rb +39 -0
  34. data/lib/ducktrap/node/block.rb +44 -0
  35. data/lib/ducktrap/node/coercion.rb +7 -0
  36. data/lib/ducktrap/node/custom.rb +121 -0
  37. data/lib/ducktrap/node/disjunction.rb +8 -0
  38. data/lib/ducktrap/node/forward.rb +55 -0
  39. data/lib/ducktrap/node/guard_nil.rb +42 -0
  40. data/lib/ducktrap/node/hash.rb +7 -0
  41. data/lib/ducktrap/node/hash/transform.rb +53 -0
  42. data/lib/ducktrap/node/invalid.rb +29 -0
  43. data/lib/ducktrap/node/inverse.rb +46 -0
  44. data/lib/ducktrap/node/key.rb +61 -0
  45. data/lib/ducktrap/node/key/add.rb +42 -0
  46. data/lib/ducktrap/node/key/delete.rb +44 -0
  47. data/lib/ducktrap/node/key/dump.rb +38 -0
  48. data/lib/ducktrap/node/key/fetch.rb +49 -0
  49. data/lib/ducktrap/node/map.rb +42 -0
  50. data/lib/ducktrap/node/noop.rb +30 -0
  51. data/lib/ducktrap/node/primitive.rb +61 -0
  52. data/lib/ducktrap/node/static.rb +33 -0
  53. data/lib/ducktrap/nullary.rb +41 -0
  54. data/lib/ducktrap/pretty_dump.rb +31 -0
  55. data/lib/ducktrap/registry.rb +60 -0
  56. data/lib/ducktrap/singleton.rb +55 -0
  57. data/lib/ducktrap/unary.rb +153 -0
  58. data/spec/rcov.opts +7 -0
  59. data/spec/shared/inverse_behavior.rb +7 -0
  60. data/spec/spec_helper.rb +20 -0
  61. data/spec/support/ice_nine_config.rb +8 -0
  62. data/spec/support/let_mock_helper.rb +13 -0
  63. data/spec/unit/ducktrap/builder/class_methods/new_spec.rb +41 -0
  64. data/spec/unit/ducktrap/builder/new_spec.rb +41 -0
  65. data/spec/unit/ducktrap/class_methods/build_spec.rb +11 -0
  66. data/spec/unit/ducktrap/error/exception/pretty_inspect_spec.rb +22 -0
  67. data/spec/unit/ducktrap/error/pretty_inspect_spec.rb +19 -0
  68. data/spec/unit/ducktrap/evaluator/assert_successful_spec.rb +38 -0
  69. data/spec/unit/ducktrap/evaluator/invalid/output_spec.rb +14 -0
  70. data/spec/unit/ducktrap/evaluator/noop/output_spec.rb +14 -0
  71. data/spec/unit/ducktrap/evaluator/output_spec.rb +52 -0
  72. data/spec/unit/ducktrap/evaluator/pretty_inspect_spec.rb +63 -0
  73. data/spec/unit/ducktrap/evaluator/successful_predicate_spec.rb +36 -0
  74. data/spec/unit/ducktrap/failed_transformation_error/message_spec.rb +10 -0
  75. data/spec/unit/ducktrap/formatter/attribute_spec.rb +24 -0
  76. data/spec/unit/ducktrap/formatter/body_spec.rb +19 -0
  77. data/spec/unit/ducktrap/formatter/class_methods/new_spec.rb +14 -0
  78. data/spec/unit/ducktrap/formatter/initialize_spec.rb +14 -0
  79. data/spec/unit/ducktrap/formatter/name_spec.rb +25 -0
  80. data/spec/unit/ducktrap/formatter/nest_spec.rb +48 -0
  81. data/spec/unit/ducktrap/formatter/puts_spec.rb +36 -0
  82. data/spec/unit/ducktrap/mapper/builder/dumper_spec.rb +20 -0
  83. data/spec/unit/ducktrap/mapper/builder/loader_spec.rb +20 -0
  84. data/spec/unit/ducktrap/mapper/builder/object_spec.rb +90 -0
  85. data/spec/unit/ducktrap/mapper/class_methods/build_spec.rb +20 -0
  86. data/spec/unit/ducktrap/nary/builder/add_spec.rb +16 -0
  87. data/spec/unit/ducktrap/nary/builder/method_missing_spec.rb +44 -0
  88. data/spec/unit/ducktrap/nary/builder/output_spec.rb +16 -0
  89. data/spec/unit/ducktrap/nary/class_methods/build_spec.rb +22 -0
  90. data/spec/unit/ducktrap/nary/class_methods/included_spec.rb +13 -0
  91. data/spec/unit/ducktrap/nary/evaluator/output_spec.rb +79 -0
  92. data/spec/unit/ducktrap/nary/instance_methods/inverse_spec.rb +24 -0
  93. data/spec/unit/ducktrap/nary/instance_methods/pretty_inspect_spec.rb +31 -0
  94. data/spec/unit/ducktrap/node/anima/dump/evaluator/output_spec.rb +18 -0
  95. data/spec/unit/ducktrap/node/anima/dump/inverse_spec.rb +10 -0
  96. data/spec/unit/ducktrap/node/anima/dump/pretty_inspect_spec.rb +15 -0
  97. data/spec/unit/ducktrap/node/anima/evaluator/output_spec.rb +18 -0
  98. data/spec/unit/ducktrap/node/anima/load/evaluator/output_spec.rb +35 -0
  99. data/spec/unit/ducktrap/node/anima/load/inverse_spec.rb +10 -0
  100. data/spec/unit/ducktrap/node/anima/load/pretty_inspect_spec.rb +15 -0
  101. data/spec/unit/ducktrap/node/anima/pretty_inspect_spec.rb +15 -0
  102. data/spec/unit/ducktrap/node/block/evaluator/output_spec.rb +79 -0
  103. data/spec/unit/ducktrap/node/block/inverse_spec.rb +24 -0
  104. data/spec/unit/ducktrap/node/call_spec.rb +21 -0
  105. data/spec/unit/ducktrap/node/class_methods/build_spec.rb +11 -0
  106. data/spec/unit/ducktrap/node/class_methods/register_spec.rb +16 -0
  107. data/spec/unit/ducktrap/node/custom/builder/forward_spec.rb +54 -0
  108. data/spec/unit/ducktrap/node/custom/builder/inverse_spec.rb +54 -0
  109. data/spec/unit/ducktrap/node/custom/builder/object_spec.rb +54 -0
  110. data/spec/unit/ducktrap/node/custom/call_spec.rb +21 -0
  111. data/spec/unit/ducktrap/node/custom/class_methods/build_spec.rb +20 -0
  112. data/spec/unit/ducktrap/node/custom/inverse_spec.rb +12 -0
  113. data/spec/unit/ducktrap/node/custom/pretty_inspect_spec.rb +15 -0
  114. data/spec/unit/ducktrap/node/forward/evaluator/output_spec.rb +13 -0
  115. data/spec/unit/ducktrap/node/forward/inverse_spec.rb +14 -0
  116. data/spec/unit/ducktrap/node/forward/pretty_inspect_spec.rb +19 -0
  117. data/spec/unit/ducktrap/node/guard_nil/call_spec.rb +21 -0
  118. data/spec/unit/ducktrap/node/guard_nil/evaluator/output_spec.rb +27 -0
  119. data/spec/unit/ducktrap/node/guard_nil/inverse_spec.rb +12 -0
  120. data/spec/unit/ducktrap/node/hash/transform/evaluator/output_spec.rb +51 -0
  121. data/spec/unit/ducktrap/node/hash/transform/inverse_spec.rb +27 -0
  122. data/spec/unit/ducktrap/node/invalid/call_spec.rb +13 -0
  123. data/spec/unit/ducktrap/node/invalid/inverse_spec.rb +11 -0
  124. data/spec/unit/ducktrap/node/inverse/call_spec.rb +11 -0
  125. data/spec/unit/ducktrap/node/inverse/inverse_spec.rb +14 -0
  126. data/spec/unit/ducktrap/node/inverse/pretty_inspect_spec.rb +19 -0
  127. data/spec/unit/ducktrap/node/key/add/call_spec.rb +15 -0
  128. data/spec/unit/ducktrap/node/key/add/evaluator/call_spec.rb +15 -0
  129. data/spec/unit/ducktrap/node/key/add/inverse_spec.rb +14 -0
  130. data/spec/unit/ducktrap/node/key/delete/call_spec.rb +13 -0
  131. data/spec/unit/ducktrap/node/key/delete/evaluator/call_spec.rb +13 -0
  132. data/spec/unit/ducktrap/node/key/delete/inverse_spec.rb +13 -0
  133. data/spec/unit/ducktrap/node/key/dump/evaluator/output_spec.rb +37 -0
  134. data/spec/unit/ducktrap/node/key/dump/inverse_spec.rb +14 -0
  135. data/spec/unit/ducktrap/node/key/evaluator/key_spec.rb +26 -0
  136. data/spec/unit/ducktrap/node/key/fetch/evaluator/output_spec.rb +48 -0
  137. data/spec/unit/ducktrap/node/key/fetch/inverse_spec.rb +14 -0
  138. data/spec/unit/ducktrap/node/key/pretty_inspect_spec.rb +20 -0
  139. data/spec/unit/ducktrap/node/map/evaluator/output_spec.rb +22 -0
  140. data/spec/unit/ducktrap/node/map/inverse_spec.rb +15 -0
  141. data/spec/unit/ducktrap/node/noop/call_spec.rb +11 -0
  142. data/spec/unit/ducktrap/node/noop/inverse_spec.rb +9 -0
  143. data/spec/unit/ducktrap/node/pretty_inspect_spec.rb +17 -0
  144. data/spec/unit/ducktrap/node/primitive/call_spec.rb +19 -0
  145. data/spec/unit/ducktrap/node/primitive/inverse_spec.rb +13 -0
  146. data/spec/unit/ducktrap/node/primitive/pretty_inspect_spec.rb +15 -0
  147. data/spec/unit/ducktrap/node/run_spec.rb +46 -0
  148. data/spec/unit/ducktrap/node/static/call_spec.rb +13 -0
  149. data/spec/unit/ducktrap/node/static/inverse_spec.rb +14 -0
  150. data/spec/unit/ducktrap/nullary/class_methods/build_spec.rb +37 -0
  151. data/spec/unit/ducktrap/nullary/class_methods/included_spec.rb +7 -0
  152. data/spec/unit/ducktrap/pretty_dump/pretty_dump_spec.rb +47 -0
  153. data/spec/unit/ducktrap/pretty_dump/pretty_inspect_spec.rb +22 -0
  154. data/spec/unit/ducktrap/registry/lookup_spec.rb +27 -0
  155. data/spec/unit/ducktrap/registry/register_spec.rb +21 -0
  156. data/spec/unit/ducktrap/singleton/class_methods/included_spec.rb +13 -0
  157. data/spec/unit/ducktrap/singleton/class_methods/instance_spec.rb +19 -0
  158. data/spec/unit/ducktrap/singleton/instance_methods/inspect_spec.rb +19 -0
  159. data/spec/unit/ducktrap/singleton/instance_methods/pretty_inspect_spec.rb +17 -0
  160. data/spec/unit/ducktrap/unary/class_methods/build_spec.rb +18 -0
  161. data/spec/unit/ducktrap/unary/class_methods/included_spec.rb +14 -0
  162. data/spec/unit/ducktrap/unary/evaluator/output2_spec.rb +48 -0
  163. data/spec/unit/ducktrap/unary/evaluator/output_spec.rb +37 -0
  164. data/spec/unit/ducktrap/unary/instance_methods/pretty_inspect_spec.rb +15 -0
  165. metadata +399 -0
@@ -0,0 +1,48 @@
1
+ module Ducktrap
2
+
3
+ # Error returned for invalid inputs
4
+ class Error
5
+ include PrettyDump, Adamantium::Flat, Concord::Public.new(:context, :input)
6
+
7
+ private
8
+
9
+ # Dump state to output
10
+ #
11
+ # @param [Formatter] formatter
12
+ #
13
+ # @return [undefined]
14
+ #
15
+ # @api private
16
+ #
17
+ def dump(output)
18
+ output.name(self)
19
+ output.attribute(:input, input)
20
+ output.nest(:context, context)
21
+ end
22
+
23
+ # Error caused by exception
24
+ class Exception < self
25
+ include Concord::Public.new(:context, :input, :exception)
26
+
27
+ private
28
+
29
+ # Dump state to output
30
+ #
31
+ # @param [Formatter] formatter
32
+ #
33
+ # @return [undefined]
34
+ #
35
+ # @api private
36
+ #
37
+ def dump(output)
38
+ excpt = exception
39
+ output.name(self)
40
+ output.attribute(:input, input)
41
+ output.attribute(:exception, excpt.class)
42
+ output.attribute(:exception_message, excpt.message)
43
+ output.nest(:context, context)
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,127 @@
1
+ module Ducktrap
2
+
3
+ # Abstract base class for transform evaluator
4
+ class Evaluator
5
+ include AbstractType, Adamantium::Flat, PrettyDump, Concord::Public.new(:context, :input)
6
+
7
+ # Test if conversion was successful
8
+ #
9
+ # @return [true]
10
+ # if conversion was successful
11
+ #
12
+ # @return [false]
13
+ # otherwise
14
+ #
15
+ # @api private
16
+ #
17
+ def successful?
18
+ !output.kind_of?(Error)
19
+ end
20
+ memoize :successful?
21
+
22
+ alias_method :success?, :successful?
23
+
24
+ # Assert evaluator is successful
25
+ #
26
+ # @return [self]
27
+ # if successful
28
+ #
29
+ # @raise [FailedTransformationError]
30
+ # otherwise
31
+ #
32
+ # @api private
33
+ #
34
+ def assert_successful
35
+ unless successful?
36
+ raise FailedTransformationError.new(self)
37
+ end
38
+ self
39
+ end
40
+
41
+ # Return output
42
+ #
43
+ # @return [Object]
44
+ #
45
+ # @api private
46
+ #
47
+ attr_reader :output
48
+
49
+ # Return output
50
+ #
51
+ # @return [Object]
52
+ #
53
+ # @api private
54
+ #
55
+ def output
56
+ process
57
+ end
58
+ memoize :output
59
+
60
+ private
61
+
62
+ # Calculate result
63
+ #
64
+ # @return [Object]
65
+ # if successful
66
+ #
67
+ # @return [Error]
68
+ # otherwise
69
+ #
70
+ # @api private
71
+ #
72
+ abstract_method :process
73
+ private :process
74
+
75
+ # Return error
76
+ #
77
+ # @return [Error]
78
+ #
79
+ # @api private
80
+ #
81
+ def error
82
+ Error.new(context, input)
83
+ end
84
+
85
+ # Return error with message
86
+ #
87
+ # @param [Error::Message]
88
+ #
89
+ # @return [Error]
90
+ #
91
+ # @api private
92
+ #
93
+ def exception(exception)
94
+ Error::Exception.new(context, input, exception)
95
+ end
96
+
97
+ # Return nested error
98
+ #
99
+ # @return [Error::Nested]
100
+ #
101
+ # @api private
102
+ #
103
+ def nested_error(error)
104
+ Error.new(error, input)
105
+ end
106
+
107
+ # Dump object
108
+ #
109
+ # @param [Formatter] formatter
110
+ #
111
+ # @return [undefined]
112
+ #
113
+ # @api private
114
+ #
115
+ def dump(formatter)
116
+ formatter.name(self)
117
+ formatter.attribute(:input, input)
118
+ if successful?
119
+ formatter.attribute(:output, output)
120
+ else
121
+ formatter.nest(:error, output)
122
+ end
123
+ formatter.nest(:context, context)
124
+ end
125
+
126
+ end
127
+ end
@@ -0,0 +1,30 @@
1
+ module Ducktrap
2
+ class Evaluator
3
+ # Evaluator that always returns errors
4
+ class Invalid < self
5
+
6
+ # Return output
7
+ #
8
+ # @return [Evaluator]
9
+ #
10
+ # @api private
11
+ #
12
+ attr_reader :output
13
+
14
+ # Initialize object
15
+ #
16
+ # @param [Ducktra] context
17
+ # @param [Object] input
18
+ #
19
+ # @return [undefined]
20
+ #
21
+ # @api private
22
+ #
23
+ def initialize(_context, _input)
24
+ super
25
+ @output = error
26
+ end
27
+
28
+ end # Invalid
29
+ end # Evaluator
30
+ end # Ducktrap
@@ -0,0 +1,25 @@
1
+ module Ducktrap
2
+ class Evaluator
3
+
4
+ # Static evaluator with input as output
5
+ class Noop < self
6
+
7
+ # Return output
8
+ #
9
+ # @return [Object]
10
+ #
11
+ # @api private
12
+ #
13
+ def output
14
+ input
15
+ end
16
+
17
+ end # Noop
18
+
19
+ # Static evaluator with static output
20
+ class Static < Noop
21
+ include Concord::Public.new(:context, :input, :output)
22
+ end # Static
23
+
24
+ end # Evaluator
25
+ end # Ducktrap
@@ -0,0 +1,138 @@
1
+ module Ducktrap
2
+ # Printer for ducktrap trees
3
+ class Formatter
4
+ include Adamantium::Flat, Equalizer.new(:output, :level)
5
+
6
+ # Return output
7
+ #
8
+ # @return [IO]
9
+ #
10
+ # @api private
11
+ #
12
+ attr_reader :output
13
+ protected :output
14
+
15
+ # Return indent
16
+ #
17
+ # @return [Fixnum]
18
+ #
19
+ # @api private
20
+ #
21
+ attr_reader :level
22
+ protected :level
23
+
24
+ # Initialize formatter
25
+ #
26
+ # @param [IO] output
27
+ # @param [Fixnum] indent
28
+ #
29
+ # @return [undefined]
30
+ #
31
+ # @api private
32
+ #
33
+ def initialize(output = $stderr, level = 0)
34
+ @output, @level = output, level
35
+ end
36
+
37
+ # Write name of class of object
38
+ #
39
+ # @param [Object] object
40
+ #
41
+ # @return [self]
42
+ #
43
+ # @api private
44
+ #
45
+ def name(object)
46
+ puts(object.class.name)
47
+ end
48
+
49
+ # Write nest with label
50
+ #
51
+ # @param [String] label
52
+ # @param [#pretty_dump] nested
53
+ #
54
+ # @return [self]
55
+ #
56
+ # @api private
57
+ #
58
+ def nest(label, nested)
59
+ indented = indent
60
+ indented.puts("#{label}:")
61
+ nested.pretty_dump(indented.indent)
62
+ self
63
+ end
64
+
65
+ # Write labeled value
66
+ #
67
+ # @param [#to_str] name
68
+ # @param [#inspect] value
69
+ #
70
+ # @return [self]
71
+ #
72
+ # @api private
73
+ #
74
+ def attribute(name, value)
75
+ indent.puts("#{name}: #{value.inspect}")
76
+ self
77
+ end
78
+
79
+ # Write body
80
+ #
81
+ # @param [Enumerable<#pretty_dump>] body
82
+ #
83
+ # @return [self]
84
+ #
85
+ # @api private
86
+ #
87
+ def body(body)
88
+ indented = indent
89
+ indented.puts('body:')
90
+ body.each do |member|
91
+ member.pretty_dump(indented.indent)
92
+ end
93
+ self
94
+ end
95
+
96
+ # Write string with indentation
97
+ #
98
+ # @param [String] string
99
+ #
100
+ # @return [self]
101
+ #
102
+ # @api private
103
+ #
104
+ def puts(string)
105
+ util = output
106
+ util.write(prefix)
107
+ util.puts(string)
108
+ self
109
+ end
110
+
111
+ # Return formatter with deeper indentation indent
112
+ #
113
+ # @return [Formatter]
114
+ #
115
+ # @api private
116
+ #
117
+ def indent
118
+ self.class.new(output, level+1)
119
+ end
120
+ memoize :indent
121
+
122
+ private
123
+
124
+ INDENT = ' '.freeze
125
+
126
+ # Return prefix at current indentation
127
+ #
128
+ # @return [String]
129
+ #
130
+ # @api private
131
+ #
132
+ def prefix
133
+ INDENT * level
134
+ end
135
+ memoize :prefix
136
+
137
+ end
138
+ end
@@ -0,0 +1,59 @@
1
+ module Ducktrap
2
+ # An object holding references to two inverse ducktraps
3
+ class Mapper
4
+ include Concord::Public.new(:loader, :dumper)
5
+
6
+ # Build mapper
7
+ #
8
+ # @return [Mapper]
9
+ #
10
+ # @api private
11
+ #
12
+ def self.build(&block)
13
+ Builder.new(self, &block).object
14
+ end
15
+
16
+ # Builder for mapper
17
+ class Builder < Ducktrap::Builder
18
+
19
+ # Capture loader block
20
+ #
21
+ # @return [self]
22
+ #
23
+ # @api private
24
+ #
25
+ def loader(&block)
26
+ @loader = Ducktrap.build(&block)
27
+ @dumper ||= @loader.inverse
28
+ self
29
+ end
30
+
31
+ # Capture dumper block
32
+ #
33
+ # @return [self]
34
+ #
35
+ # @api private
36
+ #
37
+ def dumper(&block)
38
+ @dumper = Ducktrap.build(&block)
39
+ @loader ||= @dumper.inverse
40
+ self
41
+ end
42
+
43
+ # Return mapper
44
+ #
45
+ # @return [Mapper]
46
+ #
47
+ # @api private
48
+ #
49
+ def object
50
+ unless @loader or @dumper
51
+ raise 'Did not specify loader or dumper or both'
52
+ end
53
+
54
+ klass.new(@loader, @dumper)
55
+ end
56
+
57
+ end # Builder
58
+ end # Mapper
59
+ end # Ducktrap
@@ -0,0 +1,148 @@
1
+ module Ducktrap
2
+ # Mixin for Nary ducktraps
3
+ module Nary
4
+
5
+ # Builder for nary ducktraps
6
+ class Builder < Ducktrap::Builder
7
+
8
+ # Add ducktrap argument
9
+ #
10
+ # @param [Ducktrap] ducktrap
11
+ #
12
+ # @return [self]
13
+ #
14
+ # @api private
15
+ #
16
+ def add(ducktrap)
17
+ body << ducktrap
18
+ self
19
+ end
20
+
21
+ # Hook called when method is missing
22
+ #
23
+ # @return [Object]
24
+ #
25
+ # @api private
26
+ #
27
+ def method_missing(name, *arguments, &block)
28
+ builder = DSL.lookup(name) { super }
29
+ add(builder.build(*arguments, &block))
30
+ end
31
+
32
+ # Return build instance
33
+ #
34
+ # @return [Object]
35
+ #
36
+ # @api private
37
+ #
38
+ def object
39
+ @klass.new(body)
40
+ end
41
+ memoize :object
42
+
43
+ # Return body
44
+ #
45
+ # @return [Enumerable<Ducktrap>]
46
+ #
47
+ # @api private
48
+ #
49
+ attr_reader :body
50
+
51
+ # Initialize object
52
+ #
53
+ # @param [Class] klass
54
+ # the klass to build
55
+ #
56
+ # @param [Enumerable<Ducktrap>] body
57
+ # the body of nary ducktrap
58
+ #
59
+ # @api private
60
+ #
61
+ def initialize(klass, body = [])
62
+ @body = body
63
+ super(klass)
64
+ end
65
+
66
+ end # Builder
67
+
68
+ module ClassMethods
69
+
70
+ # Build ducktrap
71
+ #
72
+ # @return [Ducktrap]
73
+ #
74
+ # @api private
75
+ #
76
+ def build(*arguments, &block)
77
+ Builder.new(self, *arguments, &block).object
78
+ end
79
+
80
+ end # ClassMethods
81
+
82
+ module InstanceMethods
83
+
84
+ private
85
+
86
+ # Return inverse body
87
+ #
88
+ # @return [Enumerable<Ducktrap>]
89
+ #
90
+ # @api private
91
+ #
92
+ def inverse_body
93
+ body.map(&:inverse).reverse
94
+ end
95
+
96
+ # Dump instance
97
+ #
98
+ # @param [Formatter] output
99
+ #
100
+ # @return [undefined]
101
+ #
102
+ # @api private
103
+ #
104
+ def dump(output)
105
+ output.name(self)
106
+ output.body(body)
107
+ end
108
+
109
+ end # InstanceMethods
110
+
111
+ CONCORD = Concord::Public.new(:body)
112
+
113
+ # Hook called when module was included
114
+ #
115
+ # @param [Class,Module] scope
116
+ #
117
+ # @return [undefined]
118
+ #
119
+ # @api private
120
+ #
121
+ def self.included(scope)
122
+ scope.extend(ClassMethods)
123
+ scope.module_eval do
124
+ include InstanceMethods
125
+ include CONCORD
126
+ end
127
+ end
128
+ private_class_method :included
129
+
130
+ # Base class for nary evaluators
131
+ class Evaluator < Ducktrap::Evaluator
132
+
133
+ private
134
+
135
+ # Return body
136
+ #
137
+ # @return [Enumerable<Ducktrap>]
138
+ #
139
+ # @api private
140
+ #
141
+ def body
142
+ context.body
143
+ end
144
+
145
+ end # Evaluator
146
+
147
+ end # Nary
148
+ end # Ducktrap