fiber_stream 0.1.0 → 0.3.0

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.
@@ -28,6 +28,22 @@ module FiberStream
28
28
  RactorPortSource.new(port, ack_port, ack_transfer, cancel)
29
29
  end
30
30
 
31
+ def self.ractor_merge_ports(port_pairs, ack_transfer, cancel)
32
+ RactorMergePortsSource.new(port_pairs, ack_transfer, cancel)
33
+ end
34
+
35
+ def self.concat(left_materializer, right_materializer)
36
+ Concat.new(left_materializer, right_materializer)
37
+ end
38
+
39
+ def self.zip(left_materializer, right_materializer)
40
+ Zip.new(left_materializer, right_materializer)
41
+ end
42
+
43
+ def self.merge(left_materializer, right_materializer)
44
+ Merge.new(left_materializer, right_materializer)
45
+ end
46
+
31
47
  def self.map(upstream, transform)
32
48
  Map.new(upstream, transform)
33
49
  end
@@ -48,6 +64,22 @@ module FiberStream
48
64
  Take.new(upstream, count)
49
65
  end
50
66
 
67
+ def self.drop(upstream, count)
68
+ Drop.new(upstream, count)
69
+ end
70
+
71
+ def self.grouped(upstream, count)
72
+ Grouped.new(upstream, count)
73
+ end
74
+
75
+ def self.take_while(upstream, predicate)
76
+ TakeWhile.new(upstream, predicate)
77
+ end
78
+
79
+ def self.drop_while(upstream, predicate)
80
+ DropWhile.new(upstream, predicate)
81
+ end
82
+
51
83
  def self.async(upstream)
52
84
  AsyncBoundary.new(upstream)
53
85
  end
@@ -60,6 +92,10 @@ module FiberStream
60
92
  Lines.new(upstream, chomp, max_length)
61
93
  end
62
94
 
95
+ def self.split(upstream, separator, keep_separator, max_length)
96
+ Split.new(upstream, separator, keep_separator, max_length)
97
+ end
98
+
63
99
  private_constant :DONE
64
100
  end
65
101
  end
@@ -67,10 +103,19 @@ end
67
103
  require_relative "pull/each"
68
104
  require_relative "pull/io_source"
69
105
  require_relative "pull/ractor_port_source"
106
+ require_relative "pull/ractor_merge_ports_source"
107
+ require_relative "pull/concat"
108
+ require_relative "pull/zip"
109
+ require_relative "pull/merge"
70
110
  require_relative "pull/map"
71
111
  require_relative "pull/select"
72
112
  require_relative "pull/take"
113
+ require_relative "pull/drop"
114
+ require_relative "pull/grouped"
115
+ require_relative "pull/take_while"
116
+ require_relative "pull/drop_while"
73
117
  require_relative "pull/lines"
118
+ require_relative "pull/split"
74
119
  require_relative "pull/async_boundary"
75
120
  require_relative "pull/buffer_boundary"
76
121
  require_relative "pull/parallel_map_boundary"
@@ -78,8 +123,8 @@ require_relative "pull/ractor_map_boundary"
78
123
 
79
124
  module FiberStream
80
125
  module Pull
81
- private_constant :Each, :IOSource, :RactorPortSource, :Map, :Select, :Take, :Lines,
82
- :AsyncBoundary, :BufferBoundary, :ParallelMapBoundary,
83
- :RactorMapBoundary
126
+ private_constant :Each, :IOSource, :RactorPortSource, :RactorMergePortsSource, :Concat, :Zip, :Merge, :Map,
127
+ :Select, :Take, :Drop, :Grouped, :TakeWhile, :DropWhile, :Lines, :Split, :AsyncBoundary,
128
+ :BufferBoundary, :ParallelMapBoundary, :RactorMapBoundary
84
129
  end
85
130
  end
@@ -6,7 +6,9 @@ module FiberStream
6
6
  # Producers send `Element`, `Complete`, and `Failure` messages to the data
7
7
  # port. FiberStream sends `Ack` and `Cancel` messages to the producer-owned
8
8
  # acknowledgment port. The envelopes keep stream values distinct from control
9
- # messages and support Ruby pattern matching.
9
+ # messages and support Ruby pattern matching. `Failure` cause metadata is
10
+ # producer-provided and is surfaced through `RactorPortSourceError`; producers
11
+ # should sanitize it before crossing trust boundaries.
10
12
  module RactorPort
11
13
  Element = ::Data.define(:value)
12
14
  Complete = ::Data.define
@@ -2,6 +2,11 @@
2
2
 
3
3
  module FiberStream
4
4
  class RunningPipeline
5
+ ValueMessage = Data.define(:value)
6
+ ErrorMessage = Data.define(:error)
7
+ CancelledMessage = Data.define(:error)
8
+ private_constant :ValueMessage, :ErrorMessage, :CancelledMessage
9
+
5
10
  def initialize(scheduler, &run)
6
11
  @scheduler = scheduler
7
12
  @completion = nil
@@ -82,16 +87,19 @@ module FiberStream
82
87
  private
83
88
 
84
89
  def run_background(run)
85
- complete([:value, run.call])
90
+ complete(ValueMessage.new(value: run.call))
91
+ rescue SystemExit, SignalException => error
92
+ complete(ErrorMessage.new(error:))
93
+ raise
86
94
  rescue Exception => error # rubocop:disable Lint/RescueException
87
95
  complete(classify_error(error))
88
96
  end
89
97
 
90
98
  def classify_error(error)
91
99
  if cancellation_error?(error)
92
- [:cancelled, error]
100
+ CancelledMessage.new(error:)
93
101
  else
94
- [:error, error]
102
+ ErrorMessage.new(error:)
95
103
  end
96
104
  end
97
105
 
@@ -114,11 +122,13 @@ module FiberStream
114
122
  end
115
123
 
116
124
  def deliver(message)
117
- case message.fetch(0)
118
- when :value
119
- message.fetch(1)
120
- when :error, :cancelled
121
- raise message.fetch(1)
125
+ case message
126
+ in ValueMessage[value:]
127
+ value
128
+ in ErrorMessage[error:]
129
+ raise error
130
+ in CancelledMessage[error:]
131
+ raise error
122
132
  end
123
133
  end
124
134
 
@@ -56,6 +56,30 @@ module FiberStream
56
56
  end
57
57
  end
58
58
 
59
+ # Creates a sink that runs a block for each stream element.
60
+ #
61
+ # The sink consumes upstream until normal completion, calls the block once
62
+ # per element in input order, and returns the number of elements whose block
63
+ # completed successfully. Exceptions raised by the block fail the stream and
64
+ # are re-raised from `Source#run_with`.
65
+ def self.foreach(&block)
66
+ raise ArgumentError, "missing block" unless block
67
+
68
+ new do |stream|
69
+ count = 0
70
+
71
+ loop do
72
+ value = stream.next
73
+ break if Pull.done?(value)
74
+
75
+ block.call(value)
76
+ count += 1
77
+ end
78
+
79
+ count
80
+ end
81
+ end
82
+
59
83
  # Creates a sink that writes String chunks to an IO-like object.
60
84
  #
61
85
  # The sink consumes upstream until normal completion and returns the number
@@ -2,6 +2,9 @@
2
2
 
3
3
  module FiberStream
4
4
  class Source
5
+ RactorMergePortPair = Data.define(:port, :ack_port)
6
+ private_constant :RactorMergePortPair
7
+
5
8
  # Creates a source definition from an Enumerable.
6
9
  #
7
10
  # The enumerable is not consumed until values are pulled by `run_with`. Each
@@ -17,7 +20,9 @@ module FiberStream
17
20
  # The IO object is not read until values are pulled by `run_with`. Each
18
21
  # materialization reads from the same IO object's current position; this
19
22
  # source does not snapshot, reopen, or guarantee replayability. The IO is
20
- # closed only when `close: true` is passed.
23
+ # closed only when `close: true` is passed. `chunk_size` is the maximum byte
24
+ # count passed to `readpartial` for one downstream pull; very large values
25
+ # may cause the IO implementation to attempt large allocations.
21
26
  def self.io(io, chunk_size: 16 * 1024, close: false)
22
27
  raise TypeError, "io must respond to readpartial" unless io.respond_to?(:readpartial)
23
28
  raise TypeError, "chunk_size must be an Integer" unless chunk_size.is_a?(Integer)
@@ -34,7 +39,8 @@ module FiberStream
34
39
  # producer-owned port that receives `RactorPort::Ack` and
35
40
  # `RactorPort::Cancel` control messages. The producer must wait for an ack
36
41
  # before sending each `RactorPort::Element`, `RactorPort::Complete`, or
37
- # `RactorPort::Failure` message.
42
+ # `RactorPort::Failure` message. Failure metadata is producer-provided and
43
+ # should be sanitized before crossing trust boundaries.
38
44
  def self.ractor_port(port, ack_port:, ack_transfer: :copy, cancel: true)
39
45
  raise TypeError, "port must respond to receive" unless port.respond_to?(:receive)
40
46
  unless ack_port.respond_to?(:send) && ack_port.method(:send).owner != Kernel
@@ -47,6 +53,24 @@ module FiberStream
47
53
  new(-> { Pull.ractor_port(port, ack_port, ack_transfer, cancel) })
48
54
  end
49
55
 
56
+ # Creates a backpressure-aware source definition from multiple Ractor port
57
+ # pairs.
58
+ #
59
+ # Each pair must be a Hash with `:port` and `:ack_port`. The source sends
60
+ # at most one outstanding `RactorPort::Ack` to each active producer and
61
+ # emits producer values in coordinator-observed ready order. Producer work
62
+ # is isolated in Ractors, so demanding this source does not require a
63
+ # `Fiber.scheduler`. Failure metadata is producer-provided and should be
64
+ # sanitized before crossing trust boundaries.
65
+ def self.ractor_merge_ports(ports, ack_transfer: :copy, cancel: true)
66
+ pairs = normalize_ractor_merge_port_pairs(ports)
67
+
68
+ Flow.__send__(:validate_ractor_transfer_policy!, :ack_transfer, ack_transfer)
69
+ raise TypeError, "cancel must be true or false" unless [true, false].include?(cancel)
70
+
71
+ new(-> { Pull.ractor_merge_ports(pairs, ack_transfer, cancel) })
72
+ end
73
+
50
74
  def initialize(source_factory, flows = [])
51
75
  @source_factory = source_factory
52
76
  @flows = flows
@@ -62,6 +86,54 @@ module FiberStream
62
86
  self.class.__send__(:new, @source_factory, @flows + [flow])
63
87
  end
64
88
 
89
+ # Returns a new source definition that emits this source, then `source`.
90
+ #
91
+ # Construction is lazy. The appended source is not materialized or pulled
92
+ # until downstream demand observes completion from this source. Flows
93
+ # attached before concat stay scoped to their source; flows attached after
94
+ # concat apply to the combined output.
95
+ def concat(source)
96
+ raise TypeError, "expected FiberStream::Source" unless source.is_a?(Source)
97
+
98
+ self.class.__send__(
99
+ :new,
100
+ -> { Pull.concat(materializer, source.__send__(:materializer)) }
101
+ )
102
+ end
103
+
104
+ # Returns a new source definition that emits pairs from this source and
105
+ # `source`.
106
+ #
107
+ # Construction is lazy. The receiver side is materialized only when
108
+ # downstream demand reaches the zip stage; the other side is materialized
109
+ # only after the receiver produces an element for a pair. The zipped source
110
+ # completes when either input completes.
111
+ def zip(source)
112
+ raise TypeError, "expected FiberStream::Source" unless source.is_a?(Source)
113
+
114
+ self.class.__send__(
115
+ :new,
116
+ -> { Pull.zip(materializer, source.__send__(:materializer)) }
117
+ )
118
+ end
119
+
120
+ # Returns a new source definition that emits values from this source and
121
+ # `source` in scheduler-observed ready order.
122
+ #
123
+ # Construction is lazy. The merged source starts one scheduled producer
124
+ # fiber per input source only when downstream demand reaches the merge. Each
125
+ # input's own element order is preserved, but cross-input ordering is not
126
+ # deterministic and requires an installed `Fiber.scheduler` from a
127
+ # non-blocking fiber when demanded.
128
+ def merge(source)
129
+ raise TypeError, "expected FiberStream::Source" unless source.is_a?(Source)
130
+
131
+ self.class.__send__(
132
+ :new,
133
+ -> { Pull.merge(materializer, source.__send__(:materializer)) }
134
+ )
135
+ end
136
+
65
137
  # Returns a new source definition that maps each element with `block`.
66
138
  #
67
139
  # This is a convenience wrapper around `via(FiberStream::Flow.map { ... })`
@@ -115,6 +187,43 @@ module FiberStream
115
187
  via(Flow.take(count))
116
188
  end
117
189
 
190
+ # Returns a new source definition that drops the first `count` elements.
191
+ #
192
+ # This is a convenience wrapper around `via(FiberStream::Flow.drop(count))`
193
+ # and preserves the same validation and pull-driven backpressure behavior.
194
+ def drop(count)
195
+ via(Flow.drop(count))
196
+ end
197
+
198
+ # Returns a new source definition that groups adjacent elements into arrays.
199
+ #
200
+ # This is a convenience wrapper around
201
+ # `via(FiberStream::Flow.grouped(count))` and preserves the same validation,
202
+ # ordering, final partial group, and pull-driven backpressure behavior.
203
+ def grouped(count)
204
+ via(Flow.grouped(count))
205
+ end
206
+
207
+ # Returns a new source definition that emits leading elements while `block`
208
+ # is truthy.
209
+ #
210
+ # This is a convenience wrapper around
211
+ # `via(FiberStream::Flow.take_while { ... })` and preserves the same
212
+ # predicate truthiness, early completion, and upstream close behavior.
213
+ def take_while(&block)
214
+ via(Flow.take_while(&block))
215
+ end
216
+
217
+ # Returns a new source definition that drops leading elements while `block`
218
+ # is truthy.
219
+ #
220
+ # This is a convenience wrapper around
221
+ # `via(FiberStream::Flow.drop_while { ... })` and preserves the same
222
+ # predicate truthiness, prefix-dropping, and pass-through behavior.
223
+ def drop_while(&block)
224
+ via(Flow.drop_while(&block))
225
+ end
226
+
118
227
  # Returns a new source definition with an asynchronous boundary.
119
228
  #
120
229
  # This is a convenience wrapper around `via(FiberStream::Flow.async)` and
@@ -135,11 +244,25 @@ module FiberStream
135
244
  # Returns a new source definition that splits String chunks into lines.
136
245
  #
137
246
  # This is a convenience wrapper around
138
- # `via(FiberStream::Flow.lines(chomp:, max_length:))`.
247
+ # `via(FiberStream::Flow.lines(chomp:, max_length:))`. With
248
+ # `max_length: nil`, one unterminated line can buffer without bound. Set a
249
+ # positive `max_length` for untrusted, network-facing, or otherwise
250
+ # unbounded streams.
139
251
  def lines(chomp: true, max_length: nil)
140
252
  via(Flow.lines(chomp: chomp, max_length: max_length))
141
253
  end
142
254
 
255
+ # Returns a new source definition that splits String chunks into frames.
256
+ #
257
+ # This is a convenience wrapper around
258
+ # `via(FiberStream::Flow.split(separator, keep_separator:, max_length:))`.
259
+ # With `max_length: nil`, one unterminated frame can buffer without bound.
260
+ # Set a positive `max_length` for untrusted, network-facing, or otherwise
261
+ # unbounded streams.
262
+ def split(separator, keep_separator: false, max_length: nil)
263
+ via(Flow.split(separator, keep_separator: keep_separator, max_length: max_length))
264
+ end
265
+
143
266
  # Returns a runnable pipeline from this source to `sink`.
144
267
  #
145
268
  # Construction is lazy. The source and sink are not materialized until
@@ -161,10 +284,7 @@ module FiberStream
161
284
  primary_error = nil
162
285
 
163
286
  begin
164
- stream = @source_factory.call
165
- @flows.each do |flow|
166
- stream = flow.__send__(:attach, stream)
167
- end
287
+ stream = materialize
168
288
 
169
289
  sink.__send__(:run, stream)
170
290
  rescue StandardError => error
@@ -180,5 +300,68 @@ module FiberStream
180
300
  end
181
301
 
182
302
  private_class_method :new
303
+
304
+ def self.normalize_ractor_merge_port_pairs(ports)
305
+ raise TypeError, "ports must respond to each" unless ports.respond_to?(:each)
306
+
307
+ data_port_ids = {}
308
+ ack_port_ids = {}
309
+ pairs =
310
+ ports.each.map do |pair|
311
+ normalize_ractor_merge_port_pair(pair, data_port_ids, ack_port_ids)
312
+ end
313
+
314
+ raise ArgumentError, "ractor_merge_ports requires at least two port pairs" if pairs.size < 2
315
+
316
+ pairs.freeze
317
+ end
318
+
319
+ def self.normalize_ractor_merge_port_pair(pair, data_port_ids, ack_port_ids)
320
+ raise TypeError, "port pair must be a Hash" unless pair.is_a?(Hash)
321
+ raise TypeError, "port pair must include :port and :ack_port" unless pair.key?(:port) && pair.key?(:ack_port)
322
+
323
+ port = pair.fetch(:port)
324
+ ack_port = pair.fetch(:ack_port)
325
+ raise TypeError, "port must respond to receive" unless port.respond_to?(:receive)
326
+ unless ack_port.respond_to?(:send) && ack_port.method(:send).owner != Kernel
327
+ raise TypeError, "ack_port must provide Ractor-style send"
328
+ end
329
+
330
+ port_id = port.object_id
331
+ ack_port_id = ack_port.object_id
332
+ raise ArgumentError, "data ports must be distinct" if data_port_ids.key?(port_id)
333
+ raise ArgumentError, "ack ports must be distinct" if ack_port_ids.key?(ack_port_id)
334
+
335
+ data_port_ids[port_id] = true
336
+ ack_port_ids[ack_port_id] = true
337
+ RactorMergePortPair.new(port:, ack_port:)
338
+ end
339
+
340
+ private_class_method :normalize_ractor_merge_port_pairs, :normalize_ractor_merge_port_pair
341
+
342
+ private
343
+
344
+ def materializer
345
+ -> { materialize }
346
+ end
347
+
348
+ def materialize
349
+ stream = nil
350
+
351
+ begin
352
+ stream = @source_factory.call
353
+ @flows.each do |flow|
354
+ stream = flow.__send__(:attach, stream)
355
+ end
356
+ stream
357
+ rescue StandardError
358
+ begin
359
+ stream&.close
360
+ rescue StandardError
361
+ nil
362
+ end
363
+ raise
364
+ end
365
+ end
183
366
  end
184
367
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FiberStream
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/sig/fiber_stream.rbs CHANGED
@@ -1,7 +1,9 @@
1
1
  module FiberStream
2
2
  type ractor_transfer_policy = :copy | :move
3
+ type ractor_port_pair = { port: untyped, ack_port: untyped }
3
4
  type ractor_map_error_kind = :input_transfer | :output_transfer | :worker | :worker_termination | :isolation
4
5
  type ractor_port_source_error_kind = :invalid_message | :producer_failure | :receive | :ack_transfer | :cancel_transfer
6
+ type ractor_port_cancel_reason = :closed
5
7
 
6
8
  class SchedulerRequiredError < RuntimeError
7
9
  end
@@ -42,7 +44,7 @@ module FiberStream
42
44
  end
43
45
 
44
46
  class Cancel < Data
45
- attr_reader reason: Symbol
47
+ attr_reader reason: ractor_port_cancel_reason
46
48
  end
47
49
  end
48
50
 
@@ -50,15 +52,24 @@ module FiberStream
50
52
  def self.each: [Elem] (Enumerable[Elem] enumerable) -> Source[Elem]
51
53
  def self.io: (untyped io, ?chunk_size: Integer, ?close: bool) -> Source[String]
52
54
  def self.ractor_port: [Elem] (untyped port, ack_port: untyped, ?ack_transfer: ractor_transfer_policy, ?cancel: bool) -> Source[Elem]
55
+ def self.ractor_merge_ports: [Elem] (Enumerable[ractor_port_pair] ports, ?ack_transfer: ractor_transfer_policy, ?cancel: bool) -> Source[Elem]
53
56
  def via: [Out] (Flow[Elem, Out] flow) -> Source[Out]
57
+ def concat: [Other] (Source[Other] source) -> Source[Elem | Other]
58
+ def zip: [Other] (Source[Other] source) -> Source[[Elem, Other]]
59
+ def merge: [Other] (Source[Other] source) -> Source[Elem | Other]
54
60
  def map: [Out] () { (Elem) -> Out } -> Source[Out]
55
61
  def parallel_map: [Out] (concurrency: Integer) { (Elem) -> Out } -> Source[Out]
56
62
  def ractor_map: [Out] (workers: Integer, ?input_transfer: ractor_transfer_policy, ?output_transfer: ractor_transfer_policy) { (Elem) -> Out } -> Source[Out]
57
63
  def select: () { (Elem) -> boolish } -> Source[Elem]
58
64
  def take: (Integer count) -> Source[Elem]
65
+ def drop: (Integer count) -> Source[Elem]
66
+ def grouped: (Integer count) -> Source[Array[Elem]]
67
+ def take_while: () { (Elem) -> boolish } -> Source[Elem]
68
+ def drop_while: () { (Elem) -> boolish } -> Source[Elem]
59
69
  def async: () -> Source[Elem]
60
70
  def buffer: (Integer count) -> Source[Elem]
61
71
  def lines: (?chomp: bool, ?max_length: Integer?) -> Source[String]
72
+ def split: (String separator, ?keep_separator: bool, ?max_length: Integer?) -> Source[String]
62
73
  def to: [Mat] (Sink[Elem, Mat] sink) -> Pipeline[Mat]
63
74
  def run_with: [Mat] (Sink[Elem, Mat] sink) -> Mat
64
75
  end
@@ -69,9 +80,14 @@ module FiberStream
69
80
  def self.ractor_map: [In, Out] (workers: Integer, ?input_transfer: ractor_transfer_policy, ?output_transfer: ractor_transfer_policy) { (In) -> Out } -> Flow[In, Out]
70
81
  def self.select: [Elem] () { (Elem) -> boolish } -> Flow[Elem, Elem]
71
82
  def self.take: [Elem] (Integer count) -> Flow[Elem, Elem]
83
+ def self.drop: [Elem] (Integer count) -> Flow[Elem, Elem]
84
+ def self.grouped: [Elem] (Integer count) -> Flow[Elem, Array[Elem]]
85
+ def self.take_while: [Elem] () { (Elem) -> boolish } -> Flow[Elem, Elem]
86
+ def self.drop_while: [Elem] () { (Elem) -> boolish } -> Flow[Elem, Elem]
72
87
  def self.async: [Elem] () -> Flow[Elem, Elem]
73
88
  def self.buffer: [Elem] (Integer count) -> Flow[Elem, Elem]
74
89
  def self.lines: (?chomp: bool, ?max_length: Integer?) -> Flow[String, String]
90
+ def self.split: (String separator, ?keep_separator: bool, ?max_length: Integer?) -> Flow[String, String]
75
91
  def via: [Next] (Flow[Out, Next] flow) -> Flow[In, Next]
76
92
  def to: [Mat] (Sink[Out, Mat] sink) -> Sink[In, Mat]
77
93
  end
@@ -80,6 +96,7 @@ module FiberStream
80
96
  def self.to_a: [Elem] () -> Sink[Elem, Array[Elem]]
81
97
  def self.first: [Elem] () -> Sink[Elem, Elem?]
82
98
  def self.fold: [Elem, Acc] (Acc initial) { (Acc, Elem) -> Acc } -> Sink[Elem, Acc]
99
+ def self.foreach: [Elem] () { (Elem) -> void } -> Sink[Elem, Integer]
83
100
  def self.io: (untyped io, ?close: bool, ?flush: bool) -> Sink[String, Integer]
84
101
  end
85
102
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fiber_stream
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dai Akatsuka
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: async-http
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0.95'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0.95'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: minitest
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -95,6 +109,7 @@ files:
95
109
  - README.md
96
110
  - examples/README.md
97
111
  - examples/async_http_requests.rb
112
+ - examples/async_http_streaming_body.rb
98
113
  - examples/background_execution.rb
99
114
  - examples/backpressure_buffer.rb
100
115
  - examples/basic_pipeline.rb
@@ -102,6 +117,7 @@ files:
102
117
  - examples/file_copy.rb
103
118
  - examples/line_processing.rb
104
119
  - examples/ractor_map_hashing.rb
120
+ - examples/ractor_merge_ports_and_map.rb
105
121
  - examples/ractor_port_source.rb
106
122
  - lib/fiber_stream.rb
107
123
  - lib/fiber_stream/errors.rb
@@ -110,15 +126,24 @@ files:
110
126
  - lib/fiber_stream/pull.rb
111
127
  - lib/fiber_stream/pull/async_boundary.rb
112
128
  - lib/fiber_stream/pull/buffer_boundary.rb
129
+ - lib/fiber_stream/pull/concat.rb
130
+ - lib/fiber_stream/pull/drop.rb
131
+ - lib/fiber_stream/pull/drop_while.rb
113
132
  - lib/fiber_stream/pull/each.rb
133
+ - lib/fiber_stream/pull/grouped.rb
114
134
  - lib/fiber_stream/pull/io_source.rb
115
135
  - lib/fiber_stream/pull/lines.rb
116
136
  - lib/fiber_stream/pull/map.rb
137
+ - lib/fiber_stream/pull/merge.rb
117
138
  - lib/fiber_stream/pull/parallel_map_boundary.rb
118
139
  - lib/fiber_stream/pull/ractor_map_boundary.rb
140
+ - lib/fiber_stream/pull/ractor_merge_ports_source.rb
119
141
  - lib/fiber_stream/pull/ractor_port_source.rb
120
142
  - lib/fiber_stream/pull/select.rb
143
+ - lib/fiber_stream/pull/split.rb
121
144
  - lib/fiber_stream/pull/take.rb
145
+ - lib/fiber_stream/pull/take_while.rb
146
+ - lib/fiber_stream/pull/zip.rb
122
147
  - lib/fiber_stream/ractor_port.rb
123
148
  - lib/fiber_stream/running_pipeline.rb
124
149
  - lib/fiber_stream/sink.rb
@@ -131,7 +156,7 @@ licenses:
131
156
  metadata:
132
157
  allowed_push_host: https://rubygems.org
133
158
  homepage_uri: https://github.com/dakatsuka/fiber_stream
134
- source_code_uri: https://github.com/dakatsuka/fiber_stream/tree/v0.1.0
159
+ source_code_uri: https://github.com/dakatsuka/fiber_stream/tree/v0.3.0
135
160
  changelog_uri: https://github.com/dakatsuka/fiber_stream/blob/main/CHANGELOG.md
136
161
  rubygems_mfa_required: 'true'
137
162
  rdoc_options: []