fiber_stream 0.4.0 → 0.6.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.
@@ -85,6 +85,22 @@ module FiberStream
85
85
  Map.new(upstream, transform)
86
86
  end
87
87
 
88
+ def self.filter_map(upstream, transform)
89
+ FilterMap.new(upstream, transform)
90
+ end
91
+
92
+ def self.compact(upstream)
93
+ Compact.new(upstream)
94
+ end
95
+
96
+ def self.map_concat(upstream, transform)
97
+ MapConcat.new(upstream, transform)
98
+ end
99
+
100
+ def self.tap(upstream, observer)
101
+ Tap.new(upstream, observer)
102
+ end
103
+
88
104
  def self.parallel_map(upstream, concurrency, transform)
89
105
  ParallelMapBoundary.new(upstream, concurrency, transform)
90
106
  end
@@ -97,10 +113,18 @@ module FiberStream
97
113
  RactorMapBoundary.new(upstream, workers, input_transfer, output_transfer, transform)
98
114
  end
99
115
 
116
+ def self.ractor_unordered_map(upstream, workers, input_transfer, output_transfer, transform)
117
+ RactorUnorderedMapBoundary.new(upstream, workers, input_transfer, output_transfer, transform)
118
+ end
119
+
100
120
  def self.select(upstream, predicate)
101
121
  Select.new(upstream, predicate)
102
122
  end
103
123
 
124
+ def self.reject(upstream, predicate)
125
+ Reject.new(upstream, predicate)
126
+ end
127
+
104
128
  def self.take(upstream, count)
105
129
  Take.new(upstream, count)
106
130
  end
@@ -133,6 +157,10 @@ module FiberStream
133
157
  BufferBoundary.new(upstream, count)
134
158
  end
135
159
 
160
+ def self.throttle(upstream, limiter)
161
+ Throttle.new(upstream, limiter)
162
+ end
163
+
136
164
  def self.lines(upstream, chomp, max_length)
137
165
  Lines.new(upstream, chomp, max_length)
138
166
  end
@@ -154,7 +182,12 @@ require_relative "pull/concat"
154
182
  require_relative "pull/zip"
155
183
  require_relative "pull/merge"
156
184
  require_relative "pull/map"
185
+ require_relative "pull/filter_map"
186
+ require_relative "pull/compact"
187
+ require_relative "pull/map_concat"
188
+ require_relative "pull/tap"
157
189
  require_relative "pull/select"
190
+ require_relative "pull/reject"
158
191
  require_relative "pull/take"
159
192
  require_relative "pull/drop"
160
193
  require_relative "pull/grouped"
@@ -165,15 +198,18 @@ require_relative "pull/lines"
165
198
  require_relative "pull/split"
166
199
  require_relative "pull/async_boundary"
167
200
  require_relative "pull/buffer_boundary"
201
+ require_relative "pull/throttle"
168
202
  require_relative "pull/parallel_map_boundary"
169
203
  require_relative "pull/parallel_unordered_map_boundary"
170
204
  require_relative "pull/ractor_map_boundary"
205
+ require_relative "pull/ractor_unordered_map_boundary"
171
206
 
172
207
  module FiberStream
173
208
  module Pull
174
209
  private_constant :Each, :IOSource, :RactorPortSource, :RactorMergePortsSource, :RactorProducerSource, :Concat,
175
- :Zip, :Merge, :Map, :Select, :Take, :Drop, :Grouped, :Scan, :TakeWhile, :DropWhile, :Lines, :Split,
176
- :AsyncBoundary, :BufferBoundary, :ParallelMapBoundary, :ParallelUnorderedMapBoundary,
177
- :RactorMapBoundary
210
+ :Zip, :Merge, :Map, :FilterMap, :Compact, :MapConcat, :Tap, :Select, :Reject, :Take, :Drop,
211
+ :Grouped, :Scan, :TakeWhile, :DropWhile, :Lines, :Split, :AsyncBoundary, :BufferBoundary,
212
+ :Throttle, :ParallelMapBoundary, :ParallelUnorderedMapBoundary, :RactorMapBoundary,
213
+ :RactorUnorderedMapBoundary
178
214
  end
179
215
  end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FiberStream
4
+ # Scheduler-aware token-bucket rate limiter.
5
+ #
6
+ # `rate` permits refill every `per` seconds. `burst` is the maximum token
7
+ # capacity and defaults to `rate`. Immediate permit grants do not require a
8
+ # scheduler. When FiberStream must sleep, the current fiber must be
9
+ # non-blocking with an installed `Fiber.scheduler`.
10
+ class RateLimiter
11
+ Request = Data.define(:rate, :per, :burst, :permits, :now)
12
+
13
+ class << self
14
+ def validate_options!(rate:, per: 1, burst: nil) # :nodoc:
15
+ rate = validate_rate(rate)
16
+ validate_duration(:per, per)
17
+ validate_burst(burst.nil? ? rate : burst)
18
+ nil
19
+ end
20
+
21
+ private
22
+
23
+ def validate_rate(rate)
24
+ raise TypeError, "rate must be an Integer" unless rate.is_a?(Integer)
25
+ raise ArgumentError, "rate must be positive" unless rate.positive?
26
+
27
+ rate
28
+ end
29
+
30
+ def validate_burst(burst)
31
+ raise TypeError, "burst must be an Integer" unless burst.is_a?(Integer)
32
+ raise ArgumentError, "burst must be positive" unless burst.positive?
33
+
34
+ burst
35
+ end
36
+
37
+ def validate_duration(name, duration)
38
+ raise TypeError, "#{name} must be Numeric" unless duration.is_a?(Numeric)
39
+ raise ArgumentError, "#{name} must be finite and real" unless finite_real?(duration)
40
+ raise ArgumentError, "#{name} must be positive" unless duration.positive?
41
+
42
+ duration
43
+ end
44
+
45
+ def finite_real?(value)
46
+ return false if value.is_a?(Complex)
47
+ return value.finite? if value.respond_to?(:finite?)
48
+
49
+ true
50
+ end
51
+ end
52
+
53
+ def initialize(rate:, per: 1, burst: nil, &block)
54
+ self.class.validate_options!(rate:, per:, burst:)
55
+
56
+ @rate = rate
57
+ @per = per
58
+ @burst = burst.nil? ? @rate : burst
59
+ @policy = block
60
+ @mutex = Mutex.new
61
+ @tokens = @burst.to_f
62
+ @updated_at = monotonic_now
63
+ end
64
+
65
+ # Acquires `permits`, waiting when necessary.
66
+ #
67
+ # Waits are scheduler-backed and non-blocking. Requests larger than `burst`
68
+ # are rejected because the local token bucket could never satisfy them.
69
+ def acquire(permits: 1)
70
+ permits = validate_permits(permits)
71
+
72
+ if @policy
73
+ acquire_with_policy(permits)
74
+ else
75
+ acquire_with_token_bucket(permits)
76
+ end
77
+
78
+ nil
79
+ end
80
+
81
+ private
82
+
83
+ def acquire_with_policy(permits)
84
+ loop do
85
+ wait = normalize_policy_wait(@policy.call(request_for(permits)))
86
+ return if wait <= 0
87
+
88
+ scheduler_sleep(wait)
89
+ end
90
+ end
91
+
92
+ def acquire_with_token_bucket(permits)
93
+ loop do
94
+ wait = nil
95
+
96
+ @mutex.synchronize do
97
+ refill_tokens
98
+
99
+ if @tokens >= permits
100
+ @tokens -= permits
101
+ return
102
+ end
103
+
104
+ wait = (permits - @tokens) / permits_per_second
105
+ end
106
+
107
+ scheduler_sleep(wait)
108
+ end
109
+ end
110
+
111
+ def request_for(permits)
112
+ Request.new(rate: @rate, per: @per, burst: @burst, permits:, now: monotonic_now)
113
+ end
114
+
115
+ def refill_tokens
116
+ now = monotonic_now
117
+ elapsed = now - @updated_at
118
+ @updated_at = now
119
+ @tokens = [@burst, @tokens + (elapsed * permits_per_second)].min
120
+ end
121
+
122
+ def permits_per_second
123
+ @rate.to_f / @per.to_f
124
+ end
125
+
126
+ def scheduler_sleep(duration)
127
+ validate_scheduler!
128
+ sleep(duration)
129
+ end
130
+
131
+ def validate_scheduler!
132
+ return if Fiber.scheduler && !Fiber.current.blocking?
133
+
134
+ message =
135
+ if Fiber.scheduler
136
+ "RateLimiter#acquire requires a non-blocking fiber"
137
+ else
138
+ "RateLimiter#acquire requires Fiber.scheduler"
139
+ end
140
+ raise SchedulerRequiredError, message
141
+ end
142
+
143
+ def validate_permits(permits)
144
+ raise TypeError, "permits must be an Integer" unless permits.is_a?(Integer)
145
+ raise ArgumentError, "permits must be positive" unless permits.positive?
146
+ raise ArgumentError, "permits must be less than or equal to burst" if permits > @burst
147
+
148
+ permits
149
+ end
150
+
151
+ def normalize_policy_wait(wait)
152
+ return 0 if wait.nil?
153
+ raise TypeError, "custom wait duration must be Numeric or nil" unless wait.is_a?(Numeric)
154
+ raise ArgumentError, "custom wait duration must be finite and real" unless self.class.send(:finite_real?, wait)
155
+
156
+ wait.positive? ? wait : 0
157
+ end
158
+
159
+ def monotonic_now
160
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
161
+ end
162
+ end
163
+ end
@@ -29,6 +29,74 @@ module FiberStream
29
29
  end
30
30
  end
31
31
 
32
+ # Creates a sink that returns the first element matching a predicate.
33
+ #
34
+ # The sink pulls upstream until the block returns a truthy value or
35
+ # upstream completes. It returns the original matching element, or `nil`
36
+ # when no element matches. Matching `nil` elements are returned as `nil`,
37
+ # following Ruby's `Enumerable#find` ambiguity.
38
+ def self.find(&block)
39
+ raise ArgumentError, "missing block" unless block
40
+
41
+ new do |stream|
42
+ loop do
43
+ value = stream.next
44
+ break nil if Pull.done?(value)
45
+ break value if block.call(value)
46
+ end
47
+ end
48
+ end
49
+
50
+ # Creates a sink that returns whether any element matches a predicate.
51
+ #
52
+ # The sink pulls upstream until the block returns a truthy value or upstream
53
+ # completes. It returns `true` after a truthy predicate result and `false`
54
+ # when no element matches.
55
+ def self.any?(&block)
56
+ raise ArgumentError, "missing block" unless block
57
+
58
+ new do |stream|
59
+ loop do
60
+ value = stream.next
61
+ break false if Pull.done?(value)
62
+ break true if block.call(value)
63
+ end
64
+ end
65
+ end
66
+
67
+ # Creates a sink that returns whether all elements match a predicate.
68
+ #
69
+ # The sink pulls upstream until the block returns false or nil, or upstream
70
+ # completes. It returns `false` after a falsey predicate result and `true`
71
+ # when every predicate result is truthy, including for empty upstream.
72
+ def self.all?(&block)
73
+ raise ArgumentError, "missing block" unless block
74
+
75
+ new do |stream|
76
+ loop do
77
+ value = stream.next
78
+ break true if Pull.done?(value)
79
+ break false unless block.call(value)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Creates a sink that counts all stream elements.
85
+ #
86
+ # The sink consumes upstream until normal completion and returns the number
87
+ # of elements observed. It does not store consumed elements.
88
+ def self.count
89
+ new do |stream|
90
+ count = 0
91
+
92
+ Pull.each_value(stream) do
93
+ count += 1
94
+ end
95
+
96
+ count
97
+ end
98
+ end
99
+
32
100
  # Creates a sink that folds all stream elements into an accumulator.
33
101
  #
34
102
  # The sink consumes upstream until normal completion. It returns the final
@@ -178,6 +178,35 @@ module FiberStream
178
178
  via(Flow.map(&block))
179
179
  end
180
180
 
181
+ # Returns a new source definition that emits truthy transformed values.
182
+ #
183
+ # This is a convenience wrapper around
184
+ # `via(FiberStream::Flow.filter_map { ... })` and has the same falsey-drop,
185
+ # lazy construction, error, and backpressure behavior as the underlying
186
+ # flow.
187
+ def filter_map(&block)
188
+ via(Flow.filter_map(&block))
189
+ end
190
+
191
+ # Returns a new source definition that drops nil elements.
192
+ #
193
+ # This is a convenience wrapper around `via(FiberStream::Flow.compact)` and
194
+ # preserves the same nil-only filtering, lazy construction, and
195
+ # backpressure behavior as the underlying flow.
196
+ def compact
197
+ via(Flow.compact)
198
+ end
199
+
200
+ # Returns a new source definition that emits each mapped expansion.
201
+ #
202
+ # This is a convenience wrapper around
203
+ # `via(FiberStream::Flow.map_concat { ... })` and has the same one-level
204
+ # flattening, lazy construction, error, and backpressure behavior as the
205
+ # underlying flow.
206
+ def map_concat(&block)
207
+ via(Flow.map_concat(&block))
208
+ end
209
+
181
210
  # Returns a new source definition that maps elements concurrently.
182
211
  #
183
212
  # This is a convenience wrapper around
@@ -217,6 +246,25 @@ module FiberStream
217
246
  )
218
247
  end
219
248
 
249
+ # Returns a new source definition that maps elements in Ractor workers and
250
+ # emits mapped values as workers complete.
251
+ #
252
+ # This is a convenience wrapper around
253
+ # `via(FiberStream::Flow.ractor_unordered_map(workers:) { ... })` and
254
+ # preserves the same shareable mapper requirement, unordered delivery,
255
+ # transfer policy, bounded upstream run-ahead, and cooperative worker
256
+ # shutdown behavior.
257
+ def ractor_unordered_map(workers:, input_transfer: :copy, output_transfer: :copy, &block)
258
+ via(
259
+ Flow.ractor_unordered_map(
260
+ workers: workers,
261
+ input_transfer: input_transfer,
262
+ output_transfer: output_transfer,
263
+ &block
264
+ )
265
+ )
266
+ end
267
+
220
268
  # Returns a new source definition that keeps elements matching `block`.
221
269
  #
222
270
  # This is a convenience wrapper around
@@ -226,6 +274,15 @@ module FiberStream
226
274
  via(Flow.select(&block))
227
275
  end
228
276
 
277
+ # Returns a new source definition that drops elements matching `block`.
278
+ #
279
+ # This is a convenience wrapper around
280
+ # `via(FiberStream::Flow.reject { ... })` and has the same truthiness and
281
+ # lazy construction behavior as the underlying flow.
282
+ def reject(&block)
283
+ via(Flow.reject(&block))
284
+ end
285
+
229
286
  # Returns a new source definition that emits at most `count` elements.
230
287
  #
231
288
  # This is a convenience wrapper around `via(FiberStream::Flow.take(count))`
@@ -297,6 +354,15 @@ module FiberStream
297
354
  via(Flow.buffer(count))
298
355
  end
299
356
 
357
+ # Returns a new source definition that rate-limits emitted elements.
358
+ #
359
+ # This is a convenience wrapper around `via(FiberStream::Flow.throttle(...))`.
360
+ # The `rate:` form creates a fresh default limiter for each materialization;
361
+ # pass `limiter:` to share quota state across sources or runs.
362
+ def throttle(**options)
363
+ via(Flow.throttle(**options))
364
+ end
365
+
300
366
  # Returns a new source definition that splits String chunks into lines.
301
367
  #
302
368
  # This is a convenience wrapper around
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FiberStream
4
- VERSION = "0.4.0"
4
+ VERSION = "0.6.0"
5
5
  end
data/lib/fiber_stream.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require_relative "fiber_stream/pull"
4
4
  require_relative "fiber_stream/version"
5
5
  require_relative "fiber_stream/errors"
6
+ require_relative "fiber_stream/rate_limiter"
6
7
  require_relative "fiber_stream/internal/ractor_transfer_policy"
7
8
  require_relative "fiber_stream/ractor_port"
8
9
  require_relative "fiber_stream/ractor_producer"
data/sig/fiber_stream.rbs CHANGED
@@ -14,6 +14,19 @@ module FiberStream
14
14
  class PipelineCancelledError < RuntimeError
15
15
  end
16
16
 
17
+ class RateLimiter
18
+ class Request < Data
19
+ attr_reader rate: Integer
20
+ attr_reader per: Numeric
21
+ attr_reader burst: Integer
22
+ attr_reader permits: Integer
23
+ attr_reader now: Float
24
+ end
25
+
26
+ def initialize: (rate: Integer, ?per: Numeric, ?burst: Integer?) ?{ (Request request) -> Numeric? } -> void
27
+ def acquire: (?permits: Integer) -> nil
28
+ end
29
+
17
30
  class RactorPortSourceError < RuntimeError
18
31
  attr_reader kind: ractor_port_source_error_kind
19
32
  attr_reader cause_class_name: String
@@ -74,7 +87,12 @@ module FiberStream
74
87
  def parallel_map: [Out] (concurrency: Integer) { (Elem) -> Out } -> Source[Out]
75
88
  def parallel_unordered_map: [Out] (concurrency: Integer) { (Elem) -> Out } -> Source[Out]
76
89
  def ractor_map: [Out] (workers: Integer, ?input_transfer: ractor_transfer_policy, ?output_transfer: ractor_transfer_policy) { (Elem) -> Out } -> Source[Out]
90
+ def ractor_unordered_map: [Out] (workers: Integer, ?input_transfer: ractor_transfer_policy, ?output_transfer: ractor_transfer_policy) { (Elem) -> Out } -> Source[Out]
91
+ def filter_map: [Out] () { (Elem) -> (Out | false | nil) } -> Source[Out]
92
+ def compact: () -> Source[Elem]
93
+ def map_concat: [Out] () { (Elem) -> Enumerable[Out] } -> Source[Out]
77
94
  def select: () { (Elem) -> boolish } -> Source[Elem]
95
+ def reject: () { (Elem) -> boolish } -> Source[Elem]
78
96
  def take: (Integer count) -> Source[Elem]
79
97
  def drop: (Integer count) -> Source[Elem]
80
98
  def grouped: (Integer count) -> Source[Array[Elem]]
@@ -83,6 +101,7 @@ module FiberStream
83
101
  def drop_while: () { (Elem) -> boolish } -> Source[Elem]
84
102
  def async: () -> Source[Elem]
85
103
  def buffer: (Integer count) -> Source[Elem]
104
+ def throttle: (?rate: Integer, ?per: Numeric, ?burst: Integer?, ?limiter: untyped) -> Source[Elem]
86
105
  def lines: (?chomp: bool, ?max_length: Integer?) -> Source[String]
87
106
  def split: (String separator, ?keep_separator: bool, ?max_length: Integer?) -> Source[String]
88
107
  def to: [Mat] (Sink[Elem, Mat] sink) -> Pipeline[Mat]
@@ -91,10 +110,16 @@ module FiberStream
91
110
 
92
111
  class Flow[In, Out]
93
112
  def self.map: [In, Out] () { (In) -> Out } -> Flow[In, Out]
113
+ def self.tap: [Elem] () { (Elem) -> void } -> Flow[Elem, Elem]
94
114
  def self.parallel_map: [In, Out] (concurrency: Integer) { (In) -> Out } -> Flow[In, Out]
95
115
  def self.parallel_unordered_map: [In, Out] (concurrency: Integer) { (In) -> Out } -> Flow[In, Out]
96
116
  def self.ractor_map: [In, Out] (workers: Integer, ?input_transfer: ractor_transfer_policy, ?output_transfer: ractor_transfer_policy) { (In) -> Out } -> Flow[In, Out]
117
+ def self.ractor_unordered_map: [In, Out] (workers: Integer, ?input_transfer: ractor_transfer_policy, ?output_transfer: ractor_transfer_policy) { (In) -> Out } -> Flow[In, Out]
118
+ def self.filter_map: [In, Out] () { (In) -> (Out | false | nil) } -> Flow[In, Out]
119
+ def self.compact: [Elem] () -> Flow[Elem, Elem]
120
+ def self.map_concat: [In, Out] () { (In) -> Enumerable[Out] } -> Flow[In, Out]
97
121
  def self.select: [Elem] () { (Elem) -> boolish } -> Flow[Elem, Elem]
122
+ def self.reject: [Elem] () { (Elem) -> boolish } -> Flow[Elem, Elem]
98
123
  def self.take: [Elem] (Integer count) -> Flow[Elem, Elem]
99
124
  def self.drop: [Elem] (Integer count) -> Flow[Elem, Elem]
100
125
  def self.grouped: [Elem] (Integer count) -> Flow[Elem, Array[Elem]]
@@ -103,6 +128,7 @@ module FiberStream
103
128
  def self.drop_while: [Elem] () { (Elem) -> boolish } -> Flow[Elem, Elem]
104
129
  def self.async: [Elem] () -> Flow[Elem, Elem]
105
130
  def self.buffer: [Elem] (Integer count) -> Flow[Elem, Elem]
131
+ def self.throttle: [Elem] (?rate: Integer, ?per: Numeric, ?burst: Integer?, ?limiter: untyped) -> Flow[Elem, Elem]
106
132
  def self.lines: (?chomp: bool, ?max_length: Integer?) -> Flow[String, String]
107
133
  def self.split: (String separator, ?keep_separator: bool, ?max_length: Integer?) -> Flow[String, String]
108
134
  def via: [Next] (Flow[Out, Next] flow) -> Flow[In, Next]
@@ -112,6 +138,10 @@ module FiberStream
112
138
  class Sink[In, Mat]
113
139
  def self.to_a: [Elem] () -> Sink[Elem, Array[Elem]]
114
140
  def self.first: [Elem] () -> Sink[Elem, Elem?]
141
+ def self.find: [Elem] () { (Elem) -> boolish } -> Sink[Elem, Elem?]
142
+ def self.any?: [Elem] () { (Elem) -> boolish } -> Sink[Elem, bool]
143
+ def self.all?: [Elem] () { (Elem) -> boolish } -> Sink[Elem, bool]
144
+ def self.count: [Elem] () -> Sink[Elem, Integer]
115
145
  def self.fold: [Elem, Acc] (Acc initial) { (Acc, Elem) -> Acc } -> Sink[Elem, Acc]
116
146
  def self.foreach: [Elem] () { (Elem) -> void } -> Sink[Elem, Integer]
117
147
  def self.io: (untyped io, ?close: bool, ?flush: bool) -> Sink[String, Integer]
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.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dai Akatsuka
@@ -120,6 +120,7 @@ files:
120
120
  - examples/ractor_merge_ports_and_map.rb
121
121
  - examples/ractor_port_source.rb
122
122
  - examples/ractor_producer_sources.rb
123
+ - examples/ractor_unordered_map_hashing.rb
123
124
  - lib/fiber_stream.rb
124
125
  - lib/fiber_stream/errors.rb
125
126
  - lib/fiber_stream/flow.rb
@@ -128,14 +129,17 @@ files:
128
129
  - lib/fiber_stream/pull.rb
129
130
  - lib/fiber_stream/pull/async_boundary.rb
130
131
  - lib/fiber_stream/pull/buffer_boundary.rb
132
+ - lib/fiber_stream/pull/compact.rb
131
133
  - lib/fiber_stream/pull/concat.rb
132
134
  - lib/fiber_stream/pull/drop.rb
133
135
  - lib/fiber_stream/pull/drop_while.rb
134
136
  - lib/fiber_stream/pull/each.rb
137
+ - lib/fiber_stream/pull/filter_map.rb
135
138
  - lib/fiber_stream/pull/grouped.rb
136
139
  - lib/fiber_stream/pull/io_source.rb
137
140
  - lib/fiber_stream/pull/lines.rb
138
141
  - lib/fiber_stream/pull/map.rb
142
+ - lib/fiber_stream/pull/map_concat.rb
139
143
  - lib/fiber_stream/pull/merge.rb
140
144
  - lib/fiber_stream/pull/parallel_map_boundary.rb
141
145
  - lib/fiber_stream/pull/parallel_unordered_map_boundary.rb
@@ -143,14 +147,19 @@ files:
143
147
  - lib/fiber_stream/pull/ractor_merge_ports_source.rb
144
148
  - lib/fiber_stream/pull/ractor_port_source.rb
145
149
  - lib/fiber_stream/pull/ractor_producer_source.rb
150
+ - lib/fiber_stream/pull/ractor_unordered_map_boundary.rb
151
+ - lib/fiber_stream/pull/reject.rb
146
152
  - lib/fiber_stream/pull/scan.rb
147
153
  - lib/fiber_stream/pull/select.rb
148
154
  - lib/fiber_stream/pull/split.rb
149
155
  - lib/fiber_stream/pull/take.rb
150
156
  - lib/fiber_stream/pull/take_while.rb
157
+ - lib/fiber_stream/pull/tap.rb
158
+ - lib/fiber_stream/pull/throttle.rb
151
159
  - lib/fiber_stream/pull/zip.rb
152
160
  - lib/fiber_stream/ractor_port.rb
153
161
  - lib/fiber_stream/ractor_producer.rb
162
+ - lib/fiber_stream/rate_limiter.rb
154
163
  - lib/fiber_stream/running_pipeline.rb
155
164
  - lib/fiber_stream/sink.rb
156
165
  - lib/fiber_stream/source.rb
@@ -162,7 +171,7 @@ licenses:
162
171
  metadata:
163
172
  allowed_push_host: https://rubygems.org
164
173
  homepage_uri: https://github.com/dakatsuka/fiber_stream
165
- source_code_uri: https://github.com/dakatsuka/fiber_stream/tree/v0.4.0
174
+ source_code_uri: https://github.com/dakatsuka/fiber_stream/tree/v0.6.0
166
175
  changelog_uri: https://github.com/dakatsuka/fiber_stream/blob/main/CHANGELOG.md
167
176
  rubygems_mfa_required: 'true'
168
177
  rdoc_options: []