philiprehberger-struct_kit 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a50ed52bad42906d2452f7e16fa3713287f263582554a7f8d67ab404a47d65e
4
- data.tar.gz: a4e55b469fc1e50ca7388f66b309f69d3046a2100b58c50fb88a06c67150799e
3
+ metadata.gz: 68b7bec33faa5c7e50b69e236a0787c370b8303e8024ea4d2a26f6751e3e5850
4
+ data.tar.gz: c04c4c2eea2bbc45a7d12cf8e6b3560b1f75699917c105378e3b67f4c5a44e42
5
5
  SHA512:
6
- metadata.gz: 92f45e162b4c8e851bf33345ecc19bdbfd37a171174dd2a76351e98462bb0f44052b079a12651dd935aa46729e7368755c8b0926060e6c51af3411bd8907ed43
7
- data.tar.gz: 6ea2cb19cc04d6888b9aa31567cbcb3a22105f95138090b3b7308e4d4ed96e63fd082a1530de83f88bb440331fedaaa69b3941b563cd3d73068682f1cbb79549
6
+ metadata.gz: baafc26c5ed314e8968fffe950acfdec20de931582a47002ccb26bcba7906caf11add73365f3a637b15fa128be1e4467cbee907b7194fe926d3927a076e1a751
7
+ data.tar.gz: 56cda98ec744f87b058f66f0afa69d3ac7d087a0ba7350662707c12495758b2e4992210cd581fd01f6d79faaa3d2e08063f13e8a6d1377f11a501e8fd8336d03
data/CHANGELOG.md CHANGED
@@ -2,11 +2,24 @@
2
2
 
3
3
  All notable changes to this gem will be documented in this file.
4
4
 
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.0] - 2026-05-07
11
+
12
+ ### Added
13
+ - Generated structs gain `#match?(**pattern)` — returns `true` when every key in the pattern matches the struct's value via `===` (case equality). Pairs with `deconstruct_keys` for partial-attribute checks.
14
+
15
+ ### Changed
16
+ - CHANGELOG header normalised to reference Keep a Changelog v1.0.0 and "this project adheres" to match every other Ruby gem.
17
+
18
+ ## [0.5.0] - 2026-04-18
19
+
20
+ ### Added
21
+ - `.from_a(array)` class method on generated structs — constructs an instance from field values in declaration order; inverse of `#to_a`; raises `ArgumentError` on length mismatch
22
+
10
23
  ## [0.4.0] - 2026-04-16
11
24
 
12
25
  ### Added
@@ -117,7 +130,9 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
117
130
  - Value equality via `#==`
118
131
  - Keyword-only constructor
119
132
 
120
- [Unreleased]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.4.0...HEAD
133
+ [Unreleased]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.6.0...HEAD
134
+ [0.6.0]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.5.0...v0.6.0
135
+ [0.5.0]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.4.0...v0.5.0
121
136
  [0.4.0]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.3.1...v0.4.0
122
137
  [0.3.1]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.3.0...v0.3.1
123
138
  [0.3.0]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.2.0...v0.3.0
data/README.md CHANGED
@@ -124,6 +124,15 @@ in { role: :user }
124
124
  end
125
125
  ```
126
126
 
127
+ ### Pattern-Style Match
128
+
129
+ ```ruby
130
+ user = User.new(name: 'Alice', age: 30, role: :user)
131
+ user.match?(role: :user) # => true
132
+ user.match?(age: 18..30) # => true (uses === for case equality)
133
+ user.match?(name: /^A/) # => true
134
+ ```
135
+
127
136
  ### Non-destructive Updates
128
137
 
129
138
  ```ruby
@@ -177,6 +186,24 @@ Account.new(email: '', tags: ['a']) # ArgumentError: email must be present
177
186
  Account.new(email: 'a@b', tags: []) # ArgumentError: tags must be present
178
187
  ```
179
188
 
189
+ ### Positional constructor
190
+
191
+ ```ruby
192
+ require 'philiprehberger/struct_kit'
193
+
194
+ Point = Philiprehberger::StructKit.define do
195
+ field :x, Integer
196
+ field :y, Integer
197
+ end
198
+
199
+ p = Point.from_a([1, 2])
200
+ p.x # => 1
201
+ p.y # => 2
202
+
203
+ # Roundtrip with #to_a
204
+ Point.from_a(p.to_a) == p # => true
205
+ ```
206
+
180
207
  ### Introspection
181
208
 
182
209
  ```ruby
@@ -212,6 +239,7 @@ Define a new struct class. Evaluates the block in DSL context.
212
239
  | `#with(**changes)` | Return a new instance with the given fields changed |
213
240
  | `#with(**overrides)` | Immutable copy-with: return a new instance with selected fields replaced (re-validated) |
214
241
  | `#deconstruct_keys(keys)` | Pattern matching support |
242
+ | `#match?(**pattern)` | Returns true when every key in pattern matches via `===` |
215
243
  | `#==` | Value equality |
216
244
  | `#inspect` | Human-readable string representation |
217
245
 
@@ -220,6 +248,7 @@ Define a new struct class. Evaluates the block in DSL context.
220
248
  | Method | Description |
221
249
  |--------|-------------|
222
250
  | `.from_h(hash)` | Construct from hash (string or symbol keys) |
251
+ | `.from_a(array)` | Construct from an array of values in field-declaration order (inverse of `#to_a`) |
223
252
  | `.field_names` | Return the declared field names in order |
224
253
 
225
254
  ## Development
@@ -25,7 +25,7 @@ module Philiprehberger
25
25
  @validations[field_name] << block if block
26
26
  end
27
27
 
28
- def build # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
28
+ def build # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
29
29
  fields = @fields.dup
30
30
  mutable = @mutable
31
31
 
@@ -105,6 +105,15 @@ module Philiprehberger
105
105
  new(**sym_hash)
106
106
  end
107
107
 
108
+ define_singleton_method(:from_a) do |array|
109
+ if array.length != _fields.size
110
+ raise ArgumentError,
111
+ "expected #{_fields.size} values for #{_fields.keys}, got #{array.length}"
112
+ end
113
+
114
+ new(**_fields.keys.zip(array).to_h)
115
+ end
116
+
108
117
  define_singleton_method(:field_names) do
109
118
  _fields.keys
110
119
  end
@@ -114,6 +123,13 @@ module Philiprehberger
114
123
  keys ? h.slice(*keys) : h
115
124
  end
116
125
 
126
+ define_method(:match?) do |**pattern|
127
+ unknown = pattern.keys - self.class._fields.keys
128
+ raise ArgumentError, "unknown keyword: #{unknown.first}" unless unknown.empty?
129
+
130
+ pattern.all? { |k, v| v === instance_variable_get(:"@#{k}") } # rubocop:disable Style/CaseEquality
131
+ end
132
+
117
133
  define_method(:==) do |other|
118
134
  other.is_a?(self.class) && to_h == other.to_h
119
135
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module StructKit
5
- VERSION = '0.4.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-struct_kit
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
  - Philip Rehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-16 00:00:00.000000000 Z
11
+ date: 2026-05-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Define data classes with typed fields, default values, validation rules,
14
14
  and pattern matching support. Immutable by default with keyword-only construction,