philiprehberger-ring_buffer 0.2.0 → 0.4.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: c769e36a185afb7b7b200d7fc7d29822c067460b135f64f32ca5157164f070fc
4
- data.tar.gz: 40ce5c2dc5f27dc4aab0ebf8fe376e5e971c31acac25cb47248c7b212eadeeed
3
+ metadata.gz: 8d3a987697f096aa8b9d085eeb0a4bcd6f83a5af1a0c2afcae477a6e789bbcdf
4
+ data.tar.gz: 66b3843e018fbb2f2e02d72d6b727e7cae71a64c299ac7e4e29747aebc8cf351
5
5
  SHA512:
6
- metadata.gz: a9a1dc2bdbbe335dccf1607aea535bbf7baf21e5b1bcbcd3e4d05f49a84f0a13f927abdc1086b70d3019c13e6ed495105a25e1145f73550135851ef2b05a0c7a
7
- data.tar.gz: 873932dfa685d64a5ceaa0d677241ffa821a917ced571dbbf5b97a737d53fcc85024ce28f6d01004b2045737bae0f1325a62f72607a6261bf8b6335a76b24716
6
+ metadata.gz: 10d2a15e1fc6afeb68d4c8a760170eddbec9c833c3c552fb72d9c3ea72d9efe5c741c1f0beca5375592344ffbac699b27d49fd3c18f75988bbc0e289078eb7f4
7
+ data.tar.gz: be638339a29c4492487f1aefca54a2235256b09a7a8f3c07eda3b72a7e5df29e9aea9f77d9e2a7225ef9c54735b6ab17a173e0b1153edb23549ca9e0a3b1f133
data/CHANGELOG.md CHANGED
@@ -7,6 +7,26 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.0] - 2026-04-14
11
+
12
+ ### Added
13
+ - `#resize(new_capacity)` to dynamically change buffer capacity while preserving elements
14
+ - `#inspect` for human-readable string representation
15
+
16
+ ### Fixed
17
+ - Bug report template: Ruby version now required, gem version field added
18
+ - Feature request template: added "Alternatives considered" field and API placeholder
19
+
20
+ ## [0.3.0] - 2026-04-09
21
+
22
+ ### Added
23
+ - `#shift` removes and returns the oldest element
24
+ - `#pop` removes and returns the newest element
25
+ - `#oldest` and `#newest` peek without mutating
26
+
27
+ ### Changed
28
+ - Internal `to_a` now derives the start index from `@head` and `@count`, supporting consumption via `shift`/`pop` while preserving all existing semantics
29
+
10
30
  ## [0.2.0] - 2026-04-03
11
31
 
12
32
  ### Added
@@ -57,3 +77,14 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
57
77
  - Statistics: average, sum, min, max
58
78
  - Last-n element retrieval
59
79
  - Enumerable support
80
+
81
+ [0.4.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.4.0
82
+ [0.3.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.3.0
83
+ [0.2.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.2.0
84
+ [0.1.6]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.1.6
85
+ [0.1.5]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.1.5
86
+ [0.1.4]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.1.4
87
+ [0.1.3]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.1.3
88
+ [0.1.2]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.1.2
89
+ [0.1.1]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.1.1
90
+ [0.1.0]: https://github.com/philiprehberger/rb-ring-buffer/releases/tag/v0.1.0
data/README.md CHANGED
@@ -70,6 +70,24 @@ buf.size # => 0
70
70
  buf.empty? # => true
71
71
  ```
72
72
 
73
+ ### Consuming Elements
74
+
75
+ ```ruby
76
+ buf = Philiprehberger::RingBuffer.new(3)
77
+ [1, 2, 3].each { |v| buf.push(v) }
78
+
79
+ buf.shift # => 1 (removes oldest)
80
+ buf.pop # => 3 (removes newest)
81
+ buf.to_a # => [2]
82
+
83
+ buf.push(4)
84
+ buf.push(5)
85
+ buf.oldest # => 2 (peek, no mutation)
86
+ buf.newest # => 5
87
+ ```
88
+
89
+ `shift`, `pop`, `oldest`, and `newest` all return `nil` when the buffer is empty.
90
+
73
91
  ### Statistics
74
92
 
75
93
  ```ruby
@@ -85,6 +103,20 @@ buf.stddev # => 8.16496580927726
85
103
  buf.median # => 20.0
86
104
  ```
87
105
 
106
+ ### Resize
107
+
108
+ ```ruby
109
+ buf = Philiprehberger::RingBuffer.new(3)
110
+ [1, 2, 3].each { |v| buf.push(v) }
111
+
112
+ buf.resize(5)
113
+ buf.capacity # => 5
114
+ buf.to_a # => [1, 2, 3]
115
+
116
+ buf.resize(2)
117
+ buf.to_a # => [2, 3] (keeps most recent)
118
+ ```
119
+
88
120
  ### Enumerable
89
121
 
90
122
  ```ruby
@@ -100,6 +132,10 @@ buf.select(&:odd?) # => [1, 3]
100
132
  |--------|-------------|
101
133
  | `RingBuffer.new(capacity)` | Create a buffer with fixed capacity |
102
134
  | `#push(value)` | Add a value, overwriting oldest if full |
135
+ | `#shift` | Remove and return the oldest element (or `nil`) |
136
+ | `#pop` | Remove and return the newest element (or `nil`) |
137
+ | `#oldest` | Peek the oldest element without removing (or `nil`) |
138
+ | `#newest` | Peek the newest element without removing (or `nil`) |
103
139
  | `#[](index)` | Access by index (0 = oldest, -1 = newest) |
104
140
  | `#to_a` | Convert to array (oldest first) |
105
141
  | `#size` | Number of elements in the buffer |
@@ -108,6 +144,8 @@ buf.select(&:odd?) # => [1, 3]
108
144
  | `#first(n)` | First n elements (oldest) |
109
145
  | `#last(n)` | Last n elements (most recent) |
110
146
  | `#clear` | Remove all elements, reset state |
147
+ | `#resize(new_capacity)` | Change buffer capacity, keeping most recent elements |
148
+ | `#inspect` | Human-readable string representation |
111
149
  | `#average` | Average of numeric elements |
112
150
  | `#sum` | Sum of numeric elements |
113
151
  | `#min` | Minimum element |
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  class RingBuffer
5
- VERSION = '0.2.0'
5
+ VERSION = '0.4.0'
6
6
  end
7
7
  end
@@ -39,12 +39,53 @@ module Philiprehberger
39
39
  def to_a
40
40
  return [] if @count.zero?
41
41
 
42
- if @count < @capacity
43
- @buffer[0...@count]
44
- else
45
- start = @head
46
- Array.new(@capacity) { |i| @buffer[(start + i) % @capacity] }
47
- end
42
+ start = (@head - @count) % @capacity
43
+ Array.new(@count) { |i| @buffer[(start + i) % @capacity] }
44
+ end
45
+
46
+ # Remove and return the oldest element
47
+ #
48
+ # @return [Object, nil]
49
+ def shift
50
+ return nil if empty?
51
+
52
+ start = (@head - @count) % @capacity
53
+ value = @buffer[start]
54
+ @buffer[start] = nil
55
+ @count -= 1
56
+ value
57
+ end
58
+
59
+ # Remove and return the newest element
60
+ #
61
+ # @return [Object, nil]
62
+ def pop
63
+ return nil if empty?
64
+
65
+ newest_idx = (@head - 1) % @capacity
66
+ value = @buffer[newest_idx]
67
+ @buffer[newest_idx] = nil
68
+ @head = newest_idx
69
+ @count -= 1
70
+ value
71
+ end
72
+
73
+ # Return the oldest element without removing it
74
+ #
75
+ # @return [Object, nil]
76
+ def oldest
77
+ return nil if empty?
78
+
79
+ @buffer[(@head - @count) % @capacity]
80
+ end
81
+
82
+ # Return the newest element without removing it
83
+ #
84
+ # @return [Object, nil]
85
+ def newest
86
+ return nil if empty?
87
+
88
+ @buffer[(@head - 1) % @capacity]
48
89
  end
49
90
 
50
91
  # Number of elements currently in the buffer
@@ -180,6 +221,36 @@ module Philiprehberger
180
221
  end
181
222
  end
182
223
 
224
+ # Change the buffer capacity, preserving elements
225
+ #
226
+ # If the new capacity is smaller than the current element count,
227
+ # the oldest elements are discarded and only the most recent
228
+ # new_capacity elements are kept.
229
+ #
230
+ # @param new_capacity [Integer] the new maximum number of elements
231
+ # @return [self]
232
+ def resize(new_capacity)
233
+ raise Error, 'capacity must be a positive integer' unless new_capacity.is_a?(Integer) && new_capacity.positive?
234
+ return self if new_capacity == @capacity
235
+
236
+ elements = to_a
237
+ elements = elements.last(new_capacity) if elements.length > new_capacity
238
+
239
+ @capacity = new_capacity
240
+ @buffer = Array.new(new_capacity)
241
+ @head = 0
242
+ @count = 0
243
+ elements.each { |e| push(e) }
244
+ self
245
+ end
246
+
247
+ # Human-readable string representation
248
+ #
249
+ # @return [String]
250
+ def inspect
251
+ "#<#{self.class} capacity=#{@capacity} size=#{@count} elements=#{to_a.inspect}>"
252
+ end
253
+
183
254
  # Iterate over elements (oldest first)
184
255
  #
185
256
  # @yield [element]
metadata CHANGED
@@ -1,18 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-ring_buffer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.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-03 00:00:00.000000000 Z
11
+ date: 2026-04-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Fixed-capacity ring buffer that overwrites oldest entries on overflow,
14
- with index access, built-in statistics (average, sum, min, max, variance, stddev,
15
- median), first/last-n retrieval, and Enumerable support.
14
+ with index access, push/pop/shift mutation, oldest/newest peek, built-in statistics
15
+ (average, sum, min, max, variance, stddev, median), first/last-n retrieval, and
16
+ Enumerable support.
16
17
  email:
17
18
  - me@philiprehberger.com
18
19
  executables: []