philiprehberger-ring_buffer 0.6.0 → 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +29 -0
- data/lib/philiprehberger/ring_buffer/version.rb +1 -1
- data/lib/philiprehberger/ring_buffer.rb +43 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7c4971ce57872af1d067144dcc2f47be6361c2223b33f3d3fe64e52be9a5b436
|
|
4
|
+
data.tar.gz: da55e74cbcb7de740c01f7867f4667de5e605f64cb3d2c87e36dd7ab5cfe80ac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1d3172843fb04b1c5a1119899b1977cfaf1e4d8f04d5035615a05813cc364377f86b05dd2206e845582e23fa4eee273adfa7bd6f34a5b1f9fd4ebfdff531d91
|
|
7
|
+
data.tar.gz: c644de2e1a605a9675b318aae413e5de527ed08e51d2987ffd936bde5de97391ac8c005b60402799f605e01ff93f1281336a1659f3caf11d21f00628c6bbc7ff
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-04-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `RingBuffer#each_chunk(size)` — yield successive non-overlapping chunks of `size` elements (oldest first). Returns an Enumerator without a block. Raises `Error` for non-positive sizes.
|
|
14
|
+
|
|
15
|
+
## [0.7.0] - 2026-04-21
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `RingBuffer#range` — spread between min and max
|
|
19
|
+
- `RingBuffer#count_by` — bucketed counts by block return value
|
|
20
|
+
|
|
10
21
|
## [0.6.0] - 2026-04-15
|
|
11
22
|
|
|
12
23
|
### Added
|
|
@@ -91,6 +102,7 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
91
102
|
- Last-n element retrieval
|
|
92
103
|
- Enumerable support
|
|
93
104
|
|
|
105
|
+
[0.7.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.7.0
|
|
94
106
|
[0.6.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.6.0
|
|
95
107
|
[0.5.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.5.0
|
|
96
108
|
[0.4.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.4.0
|
data/README.md
CHANGED
|
@@ -147,6 +147,16 @@ buf.moving_average(window: 3) # => [2.0, 3.0, 4.0]
|
|
|
147
147
|
buf.ema(alpha: 0.5) # => 4.0625
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
+
### Descriptive Helpers
|
|
151
|
+
|
|
152
|
+
```ruby
|
|
153
|
+
buf = Philiprehberger::RingBuffer.new(10)
|
|
154
|
+
[1, 2, 3, 4, 5, 6].each { |v| buf.push(v) }
|
|
155
|
+
|
|
156
|
+
buf.range # => 5 (max - min)
|
|
157
|
+
buf.count_by(&:even?) # => { false => 3, true => 3 }
|
|
158
|
+
```
|
|
159
|
+
|
|
150
160
|
### Random Sampling
|
|
151
161
|
|
|
152
162
|
```ruby
|
|
@@ -157,6 +167,22 @@ buf.sample # => random element
|
|
|
157
167
|
buf.sample(2) # => [random, random]
|
|
158
168
|
```
|
|
159
169
|
|
|
170
|
+
### Chunked Iteration
|
|
171
|
+
|
|
172
|
+
Yield successive non-overlapping chunks of fixed size in oldest-first order.
|
|
173
|
+
The final chunk may be shorter:
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
buf = Philiprehberger::RingBuffer.new(10)
|
|
177
|
+
(1..7).each { |v| buf.push(v) }
|
|
178
|
+
|
|
179
|
+
buf.each_chunk(2).to_a # => [[1, 2], [3, 4], [5, 6], [7]]
|
|
180
|
+
|
|
181
|
+
buf.each_chunk(3) do |chunk|
|
|
182
|
+
process_batch(chunk)
|
|
183
|
+
end
|
|
184
|
+
```
|
|
185
|
+
|
|
160
186
|
### Enumerable
|
|
161
187
|
|
|
162
188
|
```ruby
|
|
@@ -198,6 +224,9 @@ buf.select(&:odd?) # => [1, 3]
|
|
|
198
224
|
| `#median` | Median value |
|
|
199
225
|
| `#moving_average(window:)` | Sliding window averages (oldest to newest) |
|
|
200
226
|
| `#ema(alpha:)` | Exponential moving average (single float) |
|
|
227
|
+
| `#range` | Spread between min and max numeric elements |
|
|
228
|
+
| `#count_by(&block)` | Bucketed counts by block return value |
|
|
229
|
+
| `#each_chunk(size)` | Yield successive non-overlapping chunks of `size` elements (oldest first) |
|
|
201
230
|
|
|
202
231
|
## Development
|
|
203
232
|
|
|
@@ -335,5 +335,48 @@ module Philiprehberger
|
|
|
335
335
|
def each(&)
|
|
336
336
|
to_a.each(&)
|
|
337
337
|
end
|
|
338
|
+
|
|
339
|
+
# Spread between the minimum and maximum numeric elements
|
|
340
|
+
#
|
|
341
|
+
# @return [Numeric] the difference between max and min
|
|
342
|
+
# @raise [Error] if the buffer is empty
|
|
343
|
+
def range
|
|
344
|
+
raise Error, 'buffer is empty' if empty?
|
|
345
|
+
|
|
346
|
+
max - min
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Bucket elements by the block's return value and count each bucket
|
|
350
|
+
#
|
|
351
|
+
# Iterates oldest-to-newest via {#each}. An empty buffer returns `{}`.
|
|
352
|
+
#
|
|
353
|
+
# @yield [element] block whose return value is used as the bucket key
|
|
354
|
+
# @yieldparam element [Object] each element in oldest-to-newest order
|
|
355
|
+
# @return [Hash{Object => Integer}] bucket key to count mapping
|
|
356
|
+
# @return [Enumerator] if no block is given
|
|
357
|
+
def count_by(&block)
|
|
358
|
+
return enum_for(:count_by) unless block
|
|
359
|
+
|
|
360
|
+
result = Hash.new(0)
|
|
361
|
+
each { |element| result[block.call(element)] += 1 }
|
|
362
|
+
result
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# Yield successive non-overlapping chunks of `size` elements (oldest first)
|
|
366
|
+
#
|
|
367
|
+
# The final chunk may be shorter than `size` if the buffer length is not
|
|
368
|
+
# a multiple of `size`. An empty buffer yields nothing.
|
|
369
|
+
#
|
|
370
|
+
# @param size [Integer] chunk size (must be positive)
|
|
371
|
+
# @yield [chunk] each chunk in oldest-to-newest order
|
|
372
|
+
# @yieldparam chunk [Array] up to `size` elements
|
|
373
|
+
# @return [Enumerator] when no block is given
|
|
374
|
+
# @raise [Error] when `size` is not a positive integer
|
|
375
|
+
def each_chunk(size, &block)
|
|
376
|
+
raise Error, 'size must be a positive integer' unless size.is_a?(Integer) && size.positive?
|
|
377
|
+
return enum_for(:each_chunk, size) unless block
|
|
378
|
+
|
|
379
|
+
to_a.each_slice(size, &block)
|
|
380
|
+
end
|
|
338
381
|
end
|
|
339
382
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-ring_buffer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Fixed-capacity ring buffer that overwrites oldest entries on overflow,
|
|
14
14
|
with index access, push/pop/shift mutation, oldest/newest peek, built-in statistics
|