philiprehberger-struct_kit 0.3.1 → 0.5.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: 060eddbc858baf2efcdca822e058cec8816d86e3fadc155ec945af905ee396d6
4
- data.tar.gz: 5e2701e97abcf3e3b714169cb2eea451d4c4f8fb3eec05daec75bbf09595ec24
3
+ metadata.gz: 66d55207190faed7e2f44c1b5917c0c61740b9bbf4e285de11dd93c105d31cac
4
+ data.tar.gz: 5c263bcd332817762a19a4d01ae73209a8f98ae33f1fcbd9178881181af014e0
5
5
  SHA512:
6
- metadata.gz: 463cba608aa49db99449dc5064ca41664d13ac0a8cb919b995d2dd2928c2d731a5361aac0bc1dadc3e4b0f93087037eaf250b8a301a2999f26e0c33dead47bbd
7
- data.tar.gz: 57d159e69465225e616471143a80a6758ab3217c804c46f6c99e62d65d34577c78523301228c8744d00bee9cb3fbe680cb8f35790616e9b2da00acac1271d7cc
6
+ metadata.gz: eccb9ffe556b54ba950157125c6a7e6e7a4fdda5a121b4ffa193956d9ebd313e0810dde4d37b7f51d4508807903d9cd06ba22b464f1cfd4552cb2b0951b11ea8
7
+ data.tar.gz: 18b5d0674d7b1d7d87c395cc0f284e225d735852f826399902cde508ad2527c0bebc788f66f31a53e4155c99f5d82f8f50386d01be364aa988d9151d7f9733a4
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.0] - 2026-04-18
11
+
12
+ ### Added
13
+ - `.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
14
+
15
+ ## [0.4.0] - 2026-04-16
16
+
17
+ ### Added
18
+ - `#with(**overrides)` instance method on generated structs for immutable copy-with-changes
19
+
10
20
  ## [0.3.1] - 2026-04-15
11
21
 
12
22
  ### Changed
@@ -112,7 +122,9 @@ and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
112
122
  - Value equality via `#==`
113
123
  - Keyword-only constructor
114
124
 
115
- [Unreleased]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.3.1...HEAD
125
+ [Unreleased]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.5.0...HEAD
126
+ [0.5.0]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.4.0...v0.5.0
127
+ [0.4.0]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.3.1...v0.4.0
116
128
  [0.3.1]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.3.0...v0.3.1
117
129
  [0.3.0]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.2.0...v0.3.0
118
130
  [0.2.0]: https://github.com/philiprehberger/rb-struct-kit/compare/v0.1.0...v0.2.0
data/README.md CHANGED
@@ -141,6 +141,28 @@ alice.age # => 30 (unchanged)
141
141
  older.age # => 31
142
142
  ```
143
143
 
144
+ ### Copy With Changes
145
+
146
+ ```ruby
147
+ require 'philiprehberger/struct_kit'
148
+
149
+ User = Philiprehberger::StructKit.define do
150
+ field :name, String
151
+ field :age, Integer, default: 0
152
+ end
153
+
154
+ alice = User.new(name: 'Alice', age: 30)
155
+ bob = alice.with(name: 'Bob')
156
+
157
+ alice.name # => "Alice" (unchanged)
158
+ bob.name # => "Bob"
159
+ bob.age # => 30 (retained)
160
+
161
+ # Overrides are re-validated through the existing type/validation system:
162
+ alice.with(age: 'oops') # TypeError: age must be Integer, got String
163
+ alice.with(nope: 1) # ArgumentError: unknown keyword: nope
164
+ ```
165
+
144
166
  ### Presence Validation
145
167
 
146
168
  ```ruby
@@ -155,6 +177,24 @@ Account.new(email: '', tags: ['a']) # ArgumentError: email must be present
155
177
  Account.new(email: 'a@b', tags: []) # ArgumentError: tags must be present
156
178
  ```
157
179
 
180
+ ### Positional constructor
181
+
182
+ ```ruby
183
+ require 'philiprehberger/struct_kit'
184
+
185
+ Point = Philiprehberger::StructKit.define do
186
+ field :x, Integer
187
+ field :y, Integer
188
+ end
189
+
190
+ p = Point.from_a([1, 2])
191
+ p.x # => 1
192
+ p.y # => 2
193
+
194
+ # Roundtrip with #to_a
195
+ Point.from_a(p.to_a) == p # => true
196
+ ```
197
+
158
198
  ### Introspection
159
199
 
160
200
  ```ruby
@@ -188,6 +228,7 @@ Define a new struct class. Evaluates the block in DSL context.
188
228
  | `#to_a` | Convert to an array of values in field-declaration order |
189
229
  | `#to_json` | Convert to JSON string |
190
230
  | `#with(**changes)` | Return a new instance with the given fields changed |
231
+ | `#with(**overrides)` | Immutable copy-with: return a new instance with selected fields replaced (re-validated) |
191
232
  | `#deconstruct_keys(keys)` | Pattern matching support |
192
233
  | `#==` | Value equality |
193
234
  | `#inspect` | Human-readable string representation |
@@ -197,6 +238,7 @@ Define a new struct class. Evaluates the block in DSL context.
197
238
  | Method | Description |
198
239
  |--------|-------------|
199
240
  | `.from_h(hash)` | Construct from hash (string or symbol keys) |
241
+ | `.from_a(array)` | Construct from an array of values in field-declaration order (inverse of `#to_a`) |
200
242
  | `.field_names` | Return the declared field names in order |
201
243
 
202
244
  ## Development
@@ -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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module StructKit
5
- VERSION = '0.3.1'
5
+ VERSION = '0.5.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.3.1
4
+ version: 0.5.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-15 00:00:00.000000000 Z
11
+ date: 2026-04-19 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,