plumb 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +609 -57
  3. data/bench/compare_parametric_schema.rb +102 -0
  4. data/bench/compare_parametric_struct.rb +68 -0
  5. data/bench/parametric_schema.rb +229 -0
  6. data/bench/plumb_hash.rb +109 -0
  7. data/examples/concurrent_downloads.rb +3 -3
  8. data/examples/env_config.rb +2 -2
  9. data/examples/event_registry.rb +127 -0
  10. data/examples/weekdays.rb +1 -1
  11. data/lib/plumb/and.rb +4 -3
  12. data/lib/plumb/any_class.rb +4 -4
  13. data/lib/plumb/array_class.rb +8 -5
  14. data/lib/plumb/attributes.rb +268 -0
  15. data/lib/plumb/build.rb +4 -3
  16. data/lib/plumb/composable.rb +381 -0
  17. data/lib/plumb/decorator.rb +57 -0
  18. data/lib/plumb/deferred.rb +1 -1
  19. data/lib/plumb/hash_class.rb +19 -8
  20. data/lib/plumb/hash_map.rb +8 -6
  21. data/lib/plumb/interface_class.rb +6 -2
  22. data/lib/plumb/json_schema_visitor.rb +59 -32
  23. data/lib/plumb/match_class.rb +5 -4
  24. data/lib/plumb/metadata.rb +5 -1
  25. data/lib/plumb/metadata_visitor.rb +13 -42
  26. data/lib/plumb/not.rb +4 -3
  27. data/lib/plumb/or.rb +10 -4
  28. data/lib/plumb/pipeline.rb +27 -7
  29. data/lib/plumb/policy.rb +10 -3
  30. data/lib/plumb/schema.rb +11 -10
  31. data/lib/plumb/static_class.rb +4 -3
  32. data/lib/plumb/step.rb +4 -3
  33. data/lib/plumb/stream_class.rb +8 -7
  34. data/lib/plumb/tagged_hash.rb +11 -11
  35. data/lib/plumb/transform.rb +4 -3
  36. data/lib/plumb/tuple_class.rb +8 -8
  37. data/lib/plumb/type_registry.rb +5 -2
  38. data/lib/plumb/types.rb +30 -1
  39. data/lib/plumb/value_class.rb +4 -3
  40. data/lib/plumb/version.rb +1 -1
  41. data/lib/plumb/visitor_handlers.rb +6 -0
  42. data/lib/plumb.rb +11 -5
  43. metadata +10 -3
  44. data/lib/plumb/steppable.rb +0 -229
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'date'
3
4
  require 'plumb/visitor_handlers'
4
5
 
5
6
  module Plumb
@@ -23,11 +24,16 @@ module Plumb
23
24
  MAX_ITEMS = 'maxItems'
24
25
  MIN_LENGTH = 'minLength'
25
26
  MAX_LENGTH = 'maxLength'
27
+ FORMAT = 'format'
28
+ ENVELOPE = {
29
+ '$schema' => 'https://json-schema.org/draft-08/schema#'
30
+ }.freeze
26
31
 
27
- def self.call(node)
28
- {
29
- '$schema' => 'https://json-schema.org/draft-08/schema#'
30
- }.merge(new.visit(node))
32
+ def self.call(node, root: true)
33
+ data = new.visit(node)
34
+ return data unless root
35
+
36
+ ENVELOPE.merge(data)
31
37
  end
32
38
 
33
39
  private def stringify_keys(hash) = hash.transform_keys(&:to_s)
@@ -37,7 +43,7 @@ module Plumb
37
43
  end
38
44
 
39
45
  on(:pipeline) do |node, props|
40
- visit(node.type, props)
46
+ visit_children(node, props)
41
47
  end
42
48
 
43
49
  on(:step) do |node, props|
@@ -58,9 +64,12 @@ module Plumb
58
64
  )
59
65
  end
60
66
 
67
+ on(:data) do |node, props|
68
+ visit_name :hash, node._schema, props
69
+ end
70
+
61
71
  on(:and) do |node, props|
62
- left = visit(node.left)
63
- right = visit(node.right)
72
+ left, right = node.children.map { |c| visit(c) }
64
73
  type = right[TYPE] || left[TYPE]
65
74
  props = props.merge(left).merge(right)
66
75
  props = props.merge(TYPE => type) if type
@@ -69,11 +78,10 @@ module Plumb
69
78
 
70
79
  # A "default" value is usually an "or" of expected_value | (undefined >> static_value)
71
80
  on(:or) do |node, props|
72
- left = visit(node.left)
73
- right = visit(node.right)
74
- any_of = [left, right].uniq
81
+ left, right = node.children.map { |c| visit(c) }
82
+ any_of = [left, right].uniq.filter(&:any?)
75
83
  if any_of.size == 1
76
- props.merge(left)
84
+ props.merge(any_of.first)
77
85
  elsif any_of.size == 2 && (defidx = any_of.index { |p| p.key?(DEFAULT) })
78
86
  val = any_of[defidx.zero? ? 1 : 0]
79
87
  props.merge(val).merge(DEFAULT => any_of[defidx][DEFAULT])
@@ -83,22 +91,23 @@ module Plumb
83
91
  end
84
92
 
85
93
  on(:not) do |node, props|
86
- props.merge(NOT => visit(node.step))
94
+ props.merge(NOT => visit_children(node))
87
95
  end
88
96
 
89
97
  on(:value) do |node, props|
90
- props = case node.value
98
+ value = node.children.first
99
+ props = case value
91
100
  when ::String, ::Symbol, ::Numeric
92
- props.merge(CONST => node.value)
101
+ props.merge(CONST => value)
93
102
  else
94
103
  props
95
104
  end
96
105
 
97
- visit(node.value, props)
106
+ visit(value, props)
98
107
  end
99
108
 
100
109
  on(:transform) do |node, props|
101
- visit(node.target_type, props)
110
+ visit_children(node, props)
102
111
  end
103
112
 
104
113
  on(:undefined) do |_node, props|
@@ -108,18 +117,19 @@ module Plumb
108
117
  on(:static) do |node, props|
109
118
  # Set const AND default
110
119
  # to emulate static values
111
- props = case node.value
120
+ value = node.children.first
121
+ props = case value
112
122
  when ::String, ::Symbol, ::Numeric
113
- props.merge(CONST => node.value, DEFAULT => node.value)
123
+ props.merge(CONST => value, DEFAULT => value)
114
124
  else
115
125
  props
116
126
  end
117
127
 
118
- visit(node.value, props)
128
+ visit(value, props)
119
129
  end
120
130
 
121
131
  on(:policy) do |node, props|
122
- props = visit(node.step, props)
132
+ props = visit_children(node, props)
123
133
  method_name = :"visit_#{node.policy_name}_policy"
124
134
  if respond_to?(method_name)
125
135
  send(method_name, node, props)
@@ -168,20 +178,29 @@ module Plumb
168
178
 
169
179
  on(:match) do |node, props|
170
180
  # Set const if primitive
171
- props = case node.matcher
181
+ matcher = node.children.first
182
+ props = case matcher
172
183
  when ::String, ::Symbol, ::Numeric
173
- props.merge(CONST => node.matcher)
184
+ props.merge(CONST => matcher)
174
185
  else
175
186
  props
176
187
  end
177
188
 
178
- visit(node.matcher, props)
189
+ visit(matcher, props)
179
190
  end
180
191
 
181
192
  on(:boolean) do |_node, props|
182
193
  props.merge(TYPE => 'boolean')
183
194
  end
184
195
 
196
+ on(:uuid) do |_node, props|
197
+ props.merge(TYPE => 'string', FORMAT => 'uuid')
198
+ end
199
+
200
+ on(:email) do |_node, props|
201
+ props.merge(TYPE => 'string', FORMAT => 'email')
202
+ end
203
+
185
204
  on(::String) do |_node, props|
186
205
  props.merge(TYPE => 'string')
187
206
  end
@@ -228,6 +247,14 @@ module Plumb
228
247
  props.merge(opts)
229
248
  end
230
249
 
250
+ on(::Time) do |_node, props|
251
+ props.merge(TYPE => 'string', FORMAT => 'date-time')
252
+ end
253
+
254
+ on(::Date) do |_node, props|
255
+ props.merge(TYPE => 'string', FORMAT => 'date')
256
+ end
257
+
231
258
  on(::Hash) do |_node, props|
232
259
  props.merge(TYPE => 'object')
233
260
  end
@@ -245,7 +272,7 @@ module Plumb
245
272
  {
246
273
  TYPE => 'object',
247
274
  'patternProperties' => {
248
- '.*' => visit(node.value_type)
275
+ '.*' => visit(node.children[1])
249
276
  }
250
277
  }
251
278
  end
@@ -254,27 +281,27 @@ module Plumb
254
281
  {
255
282
  TYPE => 'object',
256
283
  'patternProperties' => {
257
- '.*' => visit(node.value_type)
284
+ '.*' => visit(node.children[1])
258
285
  }
259
286
  }
260
287
  end
261
288
 
262
289
  on(:build) do |node, props|
263
- visit(node.type, props)
290
+ visit_children(node, props)
264
291
  end
265
292
 
266
293
  on(:array) do |node, _props|
267
- items = visit(node.element_type)
268
- { TYPE => 'array', ITEMS => items }
294
+ items_props = visit_children(node)
295
+ { TYPE => 'array', ITEMS => items_props }
269
296
  end
270
297
 
271
298
  on(:stream) do |node, _props|
272
- items = visit(node.element_type)
273
- { TYPE => 'array', ITEMS => items }
299
+ items_props = visit_children(node)
300
+ { TYPE => 'array', ITEMS => items_props }
274
301
  end
275
302
 
276
303
  on(:tuple) do |node, _props|
277
- items = node.types.map { |t| visit(t) }
304
+ items = node.children.map { |t| visit(t) }
278
305
  { TYPE => 'array', 'prefixItems' => items }
279
306
  end
280
307
 
@@ -286,7 +313,7 @@ module Plumb
286
313
  }
287
314
 
288
315
  key = node.key.to_s
289
- children = node.types.map { |c| visit(c) }
316
+ children = node.children.map { |c| visit(c) }
290
317
  key_enum = children.map { |c| c[PROPERTIES][key][CONST] }
291
318
  key_type = children.map { |c| c[PROPERTIES][key][TYPE] }
292
319
  required << key
@@ -1,19 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class MatchClass
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :matcher
9
+ attr_reader :children
10
10
 
11
11
  def initialize(matcher = Undefined, error: nil, label: nil)
12
- raise TypeError 'matcher must respond to #===' unless matcher.respond_to?(:===)
12
+ raise ParseError 'matcher must respond to #===' unless matcher.respond_to?(:===)
13
13
 
14
14
  @matcher = matcher
15
15
  @error = error.nil? ? build_error(matcher) : (error % matcher)
16
16
  @label = matcher.is_a?(Class) ? matcher.inspect : "Match(#{label || @matcher.inspect})"
17
+ @children = [matcher].freeze
17
18
  freeze
18
19
  end
19
20
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Plumb
4
4
  class Metadata
5
- include Steppable
5
+ include Composable
6
6
 
7
7
  attr_reader :metadata
8
8
 
@@ -11,6 +11,10 @@ module Plumb
11
11
  freeze
12
12
  end
13
13
 
14
+ def ==(other)
15
+ other.is_a?(self.class) && @metadata == other.metadata
16
+ end
17
+
14
18
  def call(result) = result
15
19
 
16
20
  private def _inspect = "Metadata[#{@metadata.inspect}]"
@@ -10,23 +10,14 @@ module Plumb
10
10
  new.visit(node)
11
11
  end
12
12
 
13
- def on_missing_handler(node, props, method_name)
13
+ def on_missing_handler(node, props, _method_name)
14
14
  return props.merge(type: node) if node.instance_of?(Class)
15
15
 
16
- puts "Missing handler for #{node.inspect} with props #{node.inspect} and method_name :#{method_name}"
17
- props
18
- end
19
-
20
- on(:undefined) do |_node, props|
21
- props
22
- end
16
+ return props unless node.respond_to?(:children)
23
17
 
24
- on(:any) do |_node, props|
25
- props
26
- end
27
-
28
- on(:pipeline) do |node, props|
29
- visit(node.type, props)
18
+ node.children.reduce(props) do |acc, child|
19
+ visit(child, acc)
20
+ end
30
21
  end
31
22
 
32
23
  on(:step) do |node, props|
@@ -42,17 +33,12 @@ module Plumb
42
33
  props.merge(match: node, type:)
43
34
  end
44
35
 
45
- on(:match) do |node, props|
46
- visit(node.matcher, props)
47
- end
48
-
49
36
  on(:hash) do |_node, props|
50
37
  props.merge(type: Hash)
51
38
  end
52
39
 
53
40
  on(:and) do |node, props|
54
- left = visit(node.left)
55
- right = visit(node.right)
41
+ left, right = node.children.map { |child| visit(child) }
56
42
  type = right[:type] || left[:type]
57
43
  props = props.merge(left).merge(right)
58
44
  props = props.merge(type:) if type
@@ -60,7 +46,7 @@ module Plumb
60
46
  end
61
47
 
62
48
  on(:or) do |node, props|
63
- child_metas = [visit(node.left), visit(node.right)]
49
+ child_metas = node.children.map { |child| visit(child) }
64
50
  types = child_metas.map { |child| child[:type] }.flatten.compact
65
51
  types = types.first if types.size == 1
66
52
  child_metas.reduce(props) do |acc, child|
@@ -68,27 +54,16 @@ module Plumb
68
54
  end.merge(type: types)
69
55
  end
70
56
 
71
- on(:value) do |node, props|
72
- visit(node.value, props)
73
- end
74
-
75
- on(:transform) do |node, props|
76
- props.merge(type: node.target_type)
77
- end
78
-
79
57
  on(:static) do |node, props|
80
- type = node.value.is_a?(Class) ? node.value : node.value.class
81
- props.merge(static: node.value, type:)
58
+ value = node.children[0]
59
+ type = value.is_a?(Class) ? value : value.class
60
+ props.merge(static: value, type:)
82
61
  end
83
62
 
84
63
  on(:policy) do |node, props|
85
- visit(node.step, props).merge(node.policy_name => node.arg)
86
- end
87
-
88
- on(:rules) do |node, props|
89
- node.rules.reduce(props) do |acc, rule|
90
- acc.merge(rule.name => rule.arg_value)
91
- end
64
+ props = visit(node.children[0], props)
65
+ props = props.merge(node.policy_name => node.arg) unless node.arg == Plumb::Undefined
66
+ props
92
67
  end
93
68
 
94
69
  on(:boolean) do |_node, props|
@@ -103,10 +78,6 @@ module Plumb
103
78
  props.merge(type: Hash)
104
79
  end
105
80
 
106
- on(:build) do |node, props|
107
- visit(node.type, props)
108
- end
109
-
110
81
  on(:array) do |_node, props|
111
82
  props.merge(type: Array)
112
83
  end
data/lib/plumb/not.rb CHANGED
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class Not
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :step
9
+ attr_reader :children, :errors
10
10
 
11
11
  def initialize(step, errors: nil)
12
12
  @step = step
13
13
  @errors = errors
14
+ @children = [step].freeze
14
15
  freeze
15
16
  end
16
17
 
data/lib/plumb/or.rb CHANGED
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class Or
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :left, :right
9
+ attr_reader :children
10
10
 
11
11
  def initialize(left, right)
12
12
  @left = left
13
13
  @right = right
14
+ @children = [left, right].freeze
14
15
  freeze
15
16
  end
16
17
 
@@ -23,7 +24,12 @@ module Plumb
23
24
  return left_result if left_result.valid?
24
25
 
25
26
  right_result = @right.call(result)
26
- right_result.valid? ? right_result : result.invalid(errors: [left_result.errors, right_result.errors].flatten)
27
+ if right_result.valid?
28
+ right_result
29
+ else
30
+ right_result.invalid(errors: [left_result.errors,
31
+ right_result.errors].flatten)
32
+ end
27
33
  end
28
34
  end
29
35
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class Pipeline
7
- include Steppable
7
+ include Composable
8
8
 
9
9
  class AroundStep
10
- include Steppable
10
+ include Composable
11
11
 
12
12
  def initialize(step, block)
13
13
  @step = step
@@ -19,11 +19,28 @@ module Plumb
19
19
  end
20
20
  end
21
21
 
22
- attr_reader :type
22
+ class << self
23
+ def around_blocks
24
+ @around_blocks ||= []
25
+ end
26
+
27
+ def around(callable = nil, &block)
28
+ around_blocks << (callable || block)
29
+ self
30
+ end
31
+
32
+ def inherited(subclass)
33
+ around_blocks.each { |block| subclass.around(block) }
34
+ super
35
+ end
36
+ end
37
+
38
+ attr_reader :children
23
39
 
24
40
  def initialize(type = Types::Any, &setup)
25
41
  @type = type
26
- @around_blocks = []
42
+ @children = [type].freeze
43
+ @around_blocks = self.class.around_blocks.dup
27
44
  return unless block_given?
28
45
 
29
46
  configure(&setup)
@@ -38,10 +55,11 @@ module Plumb
38
55
  callable ||= block
39
56
  unless is_a_step?(callable)
40
57
  raise ArgumentError,
41
- "#step expects an interface #call(Result) Result, but got #{callable.inspect}"
58
+ "#step expects an interface #call(Result) Result, but got #{callable.inspect}"
42
59
  end
43
60
 
44
- callable = @around_blocks.reduce(callable) { |cl, bl| AroundStep.new(cl, bl) } if @around_blocks.any?
61
+ callable = prepare_step(callable)
62
+ callable = @around_blocks.reverse.reduce(callable) { |cl, bl| AroundStep.new(cl, bl) } if @around_blocks.any?
45
63
  @type >>= callable
46
64
  self
47
65
  end
@@ -69,5 +87,7 @@ module Plumb
69
87
 
70
88
  true
71
89
  end
90
+
91
+ def prepare_step(callable) = callable
72
92
  end
73
93
  end
data/lib/plumb/policy.rb CHANGED
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  # Wrap a policy composition ("step") in a Policy object.
7
7
  # So that visitors such as JSONSchema and Metadata visitors
8
8
  # can define dedicated handlers for policies, if they need to.
9
9
  class Policy
10
- include Steppable
10
+ include Composable
11
11
 
12
- attr_reader :policy_name, :arg, :step
12
+ attr_reader :policy_name, :arg, :children
13
13
 
14
14
  # @param policy_name [Symbol]
15
15
  # @param arg [Object, nil] the argument to the policy, if any.
@@ -18,9 +18,16 @@ module Plumb
18
18
  @policy_name = policy_name
19
19
  @arg = arg
20
20
  @step = step
21
+ @children = [step].freeze
21
22
  freeze
22
23
  end
23
24
 
25
+ def ==(other)
26
+ other.is_a?(self.class) &&
27
+ policy_name == other.policy_name &&
28
+ arg == other.arg
29
+ end
30
+
24
31
  # The standard Step interface.
25
32
  # @param result [Result::Valid]
26
33
  # @return [Result::Valid, Result::Invalid]
data/lib/plumb/schema.rb CHANGED
@@ -5,13 +5,13 @@ require 'plumb/json_schema_visitor'
5
5
 
6
6
  module Plumb
7
7
  class Schema
8
- include Steppable
8
+ include Composable
9
9
 
10
10
  def self.wrap(sch = nil, &block)
11
11
  raise ArgumentError, 'expected a block or a schema' if sch.nil? && !block_given?
12
12
 
13
13
  if sch
14
- raise ArgumentError, 'expected a Steppable' unless sch.is_a?(Steppable)
14
+ raise ArgumentError, 'expected a Composable' unless sch.is_a?(Composable)
15
15
 
16
16
  return sch
17
17
  end
@@ -49,8 +49,8 @@ module Plumb
49
49
  self
50
50
  end
51
51
 
52
- def json_schema
53
- JSONSchemaVisitor.call(_hash).to_h
52
+ def to_json_schema
53
+ _hash.to_json_schema(root: true)
54
54
  end
55
55
 
56
56
  def call(result)
@@ -120,7 +120,7 @@ module Plumb
120
120
  block_given? ? ArrayClass.new(element_type: Schema.new(&block)) : type
121
121
  when nil
122
122
  block_given? ? Schema.new(&block) : Types::Any
123
- when Steppable
123
+ when Composable
124
124
  type
125
125
  when Class
126
126
  if type == Array && block_given?
@@ -140,13 +140,14 @@ module Plumb
140
140
  self
141
141
  end
142
142
 
143
- def meta(md = nil)
144
- @_type = @_type.meta(md) if md
145
- self
143
+ def metadata(data = Undefined)
144
+ if data == Undefined
145
+ @_type.metadata
146
+ else
147
+ @_type = @_type.metadata(data)
148
+ end
146
149
  end
147
150
 
148
- def metadata = @_type.metadata
149
-
150
151
  def options(opts)
151
152
  @_type = @_type.options(opts)
152
153
  self
@@ -1,17 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class StaticClass
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :value
9
+ attr_reader :children
10
10
 
11
11
  def initialize(value = Undefined)
12
12
  raise ArgumentError, 'value must be frozen' unless value.frozen?
13
13
 
14
14
  @value = value
15
+ @children = [value].freeze
15
16
  freeze
16
17
  end
17
18
 
data/lib/plumb/step.rb CHANGED
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class Step
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :_metadata
9
+ attr_reader :_metadata, :children
10
10
 
11
11
  def initialize(callable = nil, inspect = nil, &block)
12
12
  @_metadata = callable.respond_to?(:metadata) ? callable.metadata : BLANK_HASH
13
13
  @callable = callable || block
14
+ @children = [@callable].freeze
14
15
  @inspect = inspect || @callable.inspect
15
16
  freeze
16
17
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'thread'
4
- require 'plumb/steppable'
4
+ require 'plumb/composable'
5
5
 
6
6
  module Plumb
7
7
  # A stream that validates each element.
@@ -15,18 +15,19 @@ module Plumb
15
15
  # result.value # => ['name', 10]
16
16
  # end
17
17
  class StreamClass
18
- include Steppable
18
+ include Composable
19
19
 
20
- attr_reader :element_type
20
+ attr_reader :children
21
21
 
22
- # @option element_type [Steppable] the type of the elements in the stream
22
+ # @option element_type [Composable] the type of the elements in the stream
23
23
  def initialize(element_type: Types::Any)
24
- @element_type = Steppable.wrap(element_type)
24
+ @element_type = Composable.wrap(element_type)
25
+ @children = [@element_type].freeze
25
26
  freeze
26
27
  end
27
28
 
28
29
  # return a new Stream definition.
29
- # @param element_type [Steppable] the type of the elements in the stream
30
+ # @param element_type [Composable] the type of the elements in the stream
30
31
  def [](element_type)
31
32
  self.class.new(element_type:)
32
33
  end
@@ -39,7 +40,7 @@ module Plumb
39
40
 
40
41
  enum = Enumerator.new do |y|
41
42
  result.value.each do |e|
42
- y << element_type.resolve(e)
43
+ y << @element_type.resolve(e)
43
44
  end
44
45
  end
45
46