philiprehberger-ring_buffer 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14989919be86bb2eda368bc258ce97204162a5435b48c2d1187f6890934ed5b8
4
- data.tar.gz: 74276b96e9b504278022d5c64c089048eb48fa08e629a441c1064e71947dd95d
3
+ metadata.gz: 296d9b4ccfe2ca3cacba6bf34911e142381b0f8e40d2cdf0ed8f23432ff957a3
4
+ data.tar.gz: cfe72d59c6b58f6d0be55488a17d1760c3914ecad2ed5a91bd2dc903c8d8c8a1
5
5
  SHA512:
6
- metadata.gz: 218f50092f5d9f13b4c22e627a4773c06053bc8fd417b5f98a5728bf44aab035ea7253355b695bf76bb0323c161d7c4e8201bf8ccca411d95467ef6fac71d46a
7
- data.tar.gz: 115237b8ffc4260f1bdab21d4529c0e9dc0ff996de8549904c3bdf4bd653a61fecd72e874c0286973973a6fe1a3f0d37222ece924c74b1836444d08e38e25573
6
+ metadata.gz: 5268f470fe0f0ca1ba767f7e4c5c4f121686d2b6ae57a83b2aafae19600f88dc1dbef2b5a097001d407afeaa8d0e48613df80aafccf7cf745aff47b247fd8f7f
7
+ data.tar.gz: 00c612791299049a02e35df9c4d3ff9fe8e0106beb37408b351df13a8875b7ea40b53540d61139f98ec814122dbee73bee7a6c62ba5b571dd7c1bf0101d9fe77
data/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0] - 2026-04-15
11
+
12
+ ### Added
13
+ - `#moving_average(window:)` for sliding window averages over buffer elements
14
+ - `#ema(alpha:)` for exponential moving average calculation
15
+
10
16
  ## [0.5.0] - 2026-04-14
11
17
 
12
18
  ### Added
@@ -85,6 +91,7 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
85
91
  - Last-n element retrieval
86
92
  - Enumerable support
87
93
 
94
+ [0.6.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.6.0
88
95
  [0.5.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.5.0
89
96
  [0.4.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.4.0
90
97
  [0.3.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.3.0
data/README.md CHANGED
@@ -137,6 +137,16 @@ buf.percentile(75) # => 75.25
137
137
  buf.percentile(90) # => 90.1
138
138
  ```
139
139
 
140
+ ### Moving Averages
141
+
142
+ ```ruby
143
+ buf = Philiprehberger::RingBuffer.new(5)
144
+ [1, 2, 3, 4, 5].each { |v| buf.push(v) }
145
+
146
+ buf.moving_average(window: 3) # => [2.0, 3.0, 4.0]
147
+ buf.ema(alpha: 0.5) # => 4.0625
148
+ ```
149
+
140
150
  ### Random Sampling
141
151
 
142
152
  ```ruby
@@ -186,6 +196,8 @@ buf.select(&:odd?) # => [1, 3]
186
196
  | `#variance` | Population variance |
187
197
  | `#stddev` | Population standard deviation |
188
198
  | `#median` | Median value |
199
+ | `#moving_average(window:)` | Sliding window averages (oldest to newest) |
200
+ | `#ema(alpha:)` | Exponential moving average (single float) |
189
201
 
190
202
  ## Development
191
203
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  class RingBuffer
5
- VERSION = '0.5.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
@@ -287,6 +287,41 @@ module Philiprehberger
287
287
  n.nil? ? arr.sample : arr.sample(n)
288
288
  end
289
289
 
290
+ # Sliding window averages over elements oldest to newest
291
+ #
292
+ # @param window [Integer] window size
293
+ # @return [Array<Float>]
294
+ def moving_average(window:)
295
+ raise Error, 'buffer is empty' if empty?
296
+ raise Error, 'window must be a positive integer' unless window.is_a?(Integer) && window.positive?
297
+ raise Error, 'window exceeds buffer size' if window > @count
298
+
299
+ arr = to_a
300
+ arr.each { |v| raise Error, 'all elements must be numeric' unless v.is_a?(Numeric) }
301
+
302
+ (0..(arr.length - window)).map do |i|
303
+ arr[i, window].sum.to_f / window
304
+ end
305
+ end
306
+
307
+ # Exponential moving average
308
+ #
309
+ # @param alpha [Float] smoothing factor (0 < alpha <= 1)
310
+ # @return [Float]
311
+ def ema(alpha:)
312
+ raise Error, 'buffer is empty' if empty?
313
+ raise Error, 'alpha must be between 0 (exclusive) and 1 (inclusive)' unless alpha.is_a?(Numeric) && alpha.positive? && alpha <= 1
314
+
315
+ arr = to_a
316
+ arr.each { |v| raise Error, 'all elements must be numeric' unless v.is_a?(Numeric) }
317
+
318
+ result = arr.first.to_f
319
+ arr.drop(1).each do |v|
320
+ result = (alpha * v) + ((1 - alpha) * result)
321
+ end
322
+ result
323
+ end
324
+
290
325
  # Human-readable string representation
291
326
  #
292
327
  # @return [String]
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.5.0
4
+ version: 0.6.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-14 00:00:00.000000000 Z
11
+ date: 2026-04-16 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