sashite-epin 2.1.0 → 2.2.1

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: 7d7d828306ad61693e22bc32ebe246c320ee67ca61968eaccb1bca519af89fbd
4
- data.tar.gz: 0a254450dc845cd83ca5d5a545d0d267de8e16210871e8b8e69201fc30b62637
3
+ metadata.gz: b8b167c50614f455cefd311bd88371733b9814812cf2f4d088df9e236f3c1750
4
+ data.tar.gz: 92584852d10ecb7c170c487c8aa6dce7de4f93a554cb65d9b598b465a6045568
5
5
  SHA512:
6
- metadata.gz: 4668940a081b1c6e478f65f651fbf4045d76f04bb459623da4675f47c1ead9410d4b3c627cf0a2e43b1b76dcb4e7aaba7734ab631447b63f72e952293f02dc27
7
- data.tar.gz: 306339f389f69cec419b15e5e517e7050bca0d0c3bfb5c3dff4b0d39328215715ab3b11b11b34485a60e9e4808a401cab9ed1fda31dfd437cbccff22f4b680be
6
+ metadata.gz: 53e1413b668e75ae17fdb287b414ca7674da8d8f3b850235901b945ddd9f8d3bc8fa6565b6ab39d93c6b9d967b2989693036a9961656245059195d3ff63015d9
7
+ data.tar.gz: ac63eae948c8c503d68361ded298793c7798064a17c3e4dc009bf1d757c6651379e0585bd3aa76f3b0617b6a77375101c05e3914bb50dfa78a184d6d0ae030c9
data/README.md CHANGED
@@ -1,19 +1,17 @@
1
- # Sashite::Epin
1
+ # epin.rb
2
2
 
3
3
  [![Version](https://img.shields.io/github/v/tag/sashite/epin.rb?label=Version&logo=github)](https://github.com/sashite/epin.rb/tags)
4
4
  [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/sashite/epin.rb/main)
5
- ![Ruby](https://github.com/sashite/epin.rb/actions/workflows/main.yml/badge.svg?branch=main)
6
- [![License](https://img.shields.io/github/license/sashite/epin.rb?label=License&logo=github)](https://github.com/sashite/epin.rb/raw/main/LICENSE.md)
5
+ [![CI](https://github.com/sashite/epin.rb/actions/workflows/ruby.yml/badge.svg?branch=main)](https://github.com/sashite/epin.rb/actions)
6
+ [![License](https://img.shields.io/github/license/sashite/epin.rb?label=License&logo=github)](https://github.com/sashite/epin.rb/raw/main/LICENSE)
7
7
 
8
8
  > **EPIN** (Extended Piece Identifier Notation) implementation for Ruby.
9
9
 
10
- ## What is EPIN?
10
+ ## Overview
11
11
 
12
- EPIN (Extended Piece Identifier Notation) extends [PIN](https://sashite.dev/specs/pin/1.0.0/) by adding a **derivation marker** to track piece style in cross-style games.
12
+ This library implements the [EPIN Specification v1.0.0](https://sashite.dev/specs/epin/1.0.0/).
13
13
 
14
- **EPIN is simply: PIN + optional style derivation marker (`'`)**
15
-
16
- This gem implements the [EPIN Specification v1.0.0](https://sashite.dev/specs/epin/1.0.0/) with a minimal compositional API.
14
+ EPIN extends [PIN](https://sashite.dev/specs/pin/1.0.0/) with an optional derivation marker (`'`) that flags whether a piece uses a native or derived style.
17
15
 
18
16
  ## Installation
19
17
 
@@ -28,67 +26,67 @@ Or install manually:
28
26
  gem install sashite-epin
29
27
  ```
30
28
 
31
- This will also install `sashite-pin` as a dependency.
32
-
33
- ## Core Concept
29
+ ## Dependencies
34
30
 
35
31
  ```ruby
36
- require "sashite/epin"
37
-
38
- # EPIN is just PIN + derived flag
39
- pin = Sashite::Pin.parse("K^")
40
- epin = Sashite::Epin.new(pin)
41
-
42
- epin.to_s # => "K^" (native)
43
- epin.pin # => #<Sashite::Pin K^>
44
- epin.derived # => false
45
-
46
- # Mark as derived
47
- derived_epin = epin.mark_derived
48
- derived_epin.to_s # => "K^'" (derived from opposite side's style)
32
+ gem "sashite-pin" # Piece Identifier Notation
49
33
  ```
50
34
 
51
- **That's it.** All piece attributes come from the PIN component.
52
-
53
35
  ## Usage
54
36
 
37
+ ### Parsing (String → Identifier)
38
+
39
+ Convert an EPIN string into an `Identifier` object.
40
+
55
41
  ```ruby
56
42
  require "sashite/epin"
57
43
 
58
- # Parse EPIN strings
44
+ # Standard parsing (raises on error)
59
45
  epin = Sashite::Epin.parse("K^'")
60
- epin.to_s # => "K^'"
46
+ epin.to_s # => "K^'"
47
+
48
+ # Access PIN attributes through the component
49
+ epin.pin.abbr # => :K
50
+ epin.pin.side # => :first
51
+ epin.pin.state # => :normal
52
+ epin.pin.terminal? # => true
61
53
 
62
- # Access five fundamental attributes through PIN component + derived flag
63
- epin.pin.type # => :K (Piece Name)
64
- epin.pin.side # => :first (Piece Side)
65
- epin.pin.state # => :normal (Piece State)
66
- epin.pin.terminal # => true (Terminal Status)
67
- epin.derived # => true (Piece Style: derived vs native)
54
+ # Access derivation status
55
+ epin.derived? # => true
56
+ epin.native? # => false
68
57
 
69
- # PIN component is a full Sashite::Pin instance
58
+ # PIN component is a full Sashite::Pin::Identifier instance
70
59
  epin.pin.enhanced? # => false
71
- epin.pin.letter # => "K"
72
60
  epin.pin.first_player? # => true
61
+
62
+ # Invalid input raises ArgumentError
63
+ Sashite::Epin.parse("invalid") # => raises ArgumentError
73
64
  ```
74
65
 
75
- ### Creating Identifiers
66
+ ### Formatting (Identifier → String)
76
67
 
77
- ```ruby
78
- # Parse from string
79
- epin = Sashite::Epin.parse("K^") # Native
80
- epin = Sashite::Epin.parse("K^'") # Derived
68
+ Convert an `Identifier` back to an EPIN string.
81
69
 
82
- # Create from PIN component
70
+ ```ruby
71
+ # From PIN component
83
72
  pin = Sashite::Pin.parse("K^")
84
- epin = Sashite::Epin.new(pin) # Native (default)
85
- epin = Sashite::Epin.new(pin, derived: true) # Derived
86
-
87
- # Validation
88
- Sashite::Epin.valid?("K^") # => true
89
- Sashite::Epin.valid?("K^'") # => true
90
- Sashite::Epin.valid?("K^''") # => false (multiple markers)
91
- Sashite::Epin.valid?("K'^") # => false (wrong order)
73
+ epin = Sashite::Epin::Identifier.new(pin)
74
+ epin.to_s # => "K^"
75
+
76
+ # With derivation
77
+ epin = Sashite::Epin::Identifier.new(pin, derived: true)
78
+ epin.to_s # => "K^'"
79
+ ```
80
+
81
+ ### Validation
82
+
83
+ ```ruby
84
+ # Boolean check
85
+ Sashite::Epin.valid?("K") # => true
86
+ Sashite::Epin.valid?("+R^'") # => true
87
+ Sashite::Epin.valid?("invalid") # => false
88
+ Sashite::Epin.valid?("K''") # => false
89
+ Sashite::Epin.valid?("K'^") # => false
92
90
  ```
93
91
 
94
92
  ### Accessing Components
@@ -97,16 +95,15 @@ Sashite::Epin.valid?("K'^") # => false (wrong order)
97
95
  epin = Sashite::Epin.parse("+R^'")
98
96
 
99
97
  # Get PIN component
100
- epin.pin # => #<Sashite::Pin +R^>
101
- epin.pin.to_s # => "+R^"
98
+ epin.pin # => #<Sashite::Pin::Identifier +R^>
99
+ epin.pin.to_s # => "+R^"
102
100
 
103
101
  # Check derivation
104
- epin.derived # => true
105
- epin.derived? # => true
106
- epin.native? # => false
102
+ epin.derived? # => true
103
+ epin.native? # => false
107
104
 
108
105
  # Serialize
109
- epin.to_s # => "+R^'"
106
+ epin.to_s # => "+R^'"
110
107
  ```
111
108
 
112
109
  ### Transformations
@@ -116,17 +113,13 @@ All transformations return new immutable instances.
116
113
  ```ruby
117
114
  epin = Sashite::Epin.parse("K^")
118
115
 
119
- # Mark as derived
120
- derived = epin.mark_derived
121
- derived.to_s # => "K^'"
122
-
123
- # Mark as native
124
- native = derived.unmark_derived
125
- native.to_s # => "K^"
116
+ # Derivation transformations
117
+ epin.derive.to_s # => "K^'"
118
+ epin.native.to_s # => "K^"
126
119
 
127
- # Set explicitly
128
- toggled = epin.with_derived(true)
129
- toggled.to_s # => "K^'"
120
+ # Replace PIN component
121
+ new_pin = Sashite::Pin.parse("+Q^")
122
+ epin.with_pin(new_pin).to_s # => "+Q^"
130
123
  ```
131
124
 
132
125
  ### Transform via PIN Component
@@ -134,33 +127,17 @@ toggled.to_s # => "K^'"
134
127
  ```ruby
135
128
  epin = Sashite::Epin.parse("K^'")
136
129
 
137
- # Replace PIN component
138
- new_pin = epin.pin.with_type(:Q)
139
- epin.with_pin(new_pin).to_s # => "Q^'"
130
+ # Change abbr
131
+ epin.with_pin(epin.pin.with_abbr(:Q)).to_s # => "Q^'"
140
132
 
141
133
  # Change state
142
- new_pin = epin.pin.enhance
143
- epin.with_pin(new_pin).to_s # => "+K^'"
144
-
145
- # Remove terminal marker
146
- new_pin = epin.pin.unmark_terminal
147
- epin.with_pin(new_pin).to_s # => "K'"
134
+ epin.with_pin(epin.pin.enhance).to_s # => "+K^'"
148
135
 
149
136
  # Change side
150
- new_pin = epin.pin.flip
151
- epin.with_pin(new_pin).to_s # => "k^'"
152
- ```
137
+ epin.with_pin(epin.pin.flip).to_s # => "k^'"
153
138
 
154
- ### Multiple Transformations
155
-
156
- ```ruby
157
- epin = Sashite::Epin.parse("K^")
158
-
159
- # Transform PIN and derivation
160
- new_pin = epin.pin.with_type(:Q).enhance
161
- transformed = epin.with_pin(new_pin).mark_derived
162
-
163
- transformed.to_s # => "+Q^'"
139
+ # Remove terminal
140
+ epin.with_pin(epin.pin.non_terminal).to_s # => "K'"
164
141
  ```
165
142
 
166
143
  ### Component Queries
@@ -170,255 +147,131 @@ Use the PIN API directly:
170
147
  ```ruby
171
148
  epin = Sashite::Epin.parse("+P^'")
172
149
 
173
- # PIN queries (name, side, state, terminal)
174
- epin.pin.type # => :P
175
- epin.pin.side # => :first
176
- epin.pin.state # => :enhanced
177
- epin.pin.terminal # => true
178
- epin.pin.first_player? # => true
179
- epin.pin.enhanced? # => true
180
- epin.pin.letter # => "P"
181
- epin.pin.prefix # => "+"
182
- epin.pin.suffix # => "^"
183
-
184
- # EPIN queries (style)
185
- epin.derived? # => true
186
- epin.native? # => false
150
+ # PIN queries
151
+ epin.pin.abbr # => :P
152
+ epin.pin.side # => :first
153
+ epin.pin.state # => :enhanced
154
+ epin.pin.terminal? # => true
155
+ epin.pin.first_player? # => true
156
+ epin.pin.enhanced? # => true
157
+
158
+ # EPIN queries
159
+ epin.derived? # => true
160
+ epin.native? # => false
187
161
 
188
162
  # Compare EPINs
189
163
  other = Sashite::Epin.parse("+P^")
190
- epin.pin.same_type?(other.pin) # => true (both P)
191
- epin.pin.same_state?(other.pin) # => true (both enhanced)
192
- epin.same_derived?(other) # => false (different derivation)
193
- ```
194
-
195
- ## Five Fundamental Attributes
196
-
197
- EPIN exposes all five attributes from the [Sashité Game Protocol](https://sashite.dev/game-protocol/):
198
-
199
- | Protocol Attribute | EPIN Access | Example |
200
- |-------------------|-------------|---------|
201
- | **Piece Name** | `epin.pin.type` | `:K` (King), `:R` (Rook) |
202
- | **Piece Side** | `epin.pin.side` | `:first`, `:second` |
203
- | **Piece State** | `epin.pin.state` | `:normal`, `:enhanced`, `:diminished` |
204
- | **Terminal Status** | `epin.pin.terminal` | `true`, `false` |
205
- | **Piece Style** | `epin.derived` | `false` (native), `true` (derived) |
206
-
207
- ## Format Specification
208
-
209
- ### Structure
210
-
211
- ```
212
- <pin>[']
213
- ```
214
-
215
- Where:
216
- - `<pin>` is any valid PIN token
217
- - `'` is the optional derivation marker
218
-
219
- ### Grammar (EBNF)
220
-
221
- ```ebnf
222
- epin ::= pin | pin "'"
223
- pin ::= ["+" | "-"] letter ["^"]
224
- letter ::= "A" | ... | "Z" | "a" | ... | "z"
225
- ```
226
-
227
- ### Regular Expression
228
-
229
- ```ruby
230
- /\A[-+]?[A-Za-z]\^?'?\z/
231
- ```
232
-
233
- ### Examples
234
-
235
- | EPIN | Side | State | Terminal | Derived | Description |
236
- |------|------|-------|----------|---------|-------------|
237
- | `K` | First | Normal | No | No | Standard native king |
238
- | `K'` | First | Normal | No | Yes | Derived king |
239
- | `K^` | First | Normal | Yes | No | Terminal native king |
240
- | `K^'` | First | Normal | Yes | Yes | Terminal derived king |
241
- | `+R'` | First | Enhanced | No | Yes | Enhanced derived rook |
242
- | `-p` | Second | Diminished | No | No | Diminished native pawn |
243
-
244
- ## Cross-Style Game Example
245
-
246
- In a chess-vs-makruk cross-style match where:
247
- - First side native style = chess
248
- - Second side native style = makruk
249
-
250
- ```ruby
251
- # First player pieces
252
- chess_king = Sashite::Epin.parse("K^") # Native Chess king
253
- makruk_pawn = Sashite::Epin.parse("P'") # Derived Makruk pawn (foreign)
254
-
255
- chess_king.native? # => true (uses own style)
256
- makruk_pawn.derived? # => true (uses opponent's style)
257
-
258
- # Second player pieces
259
- makruk_king = Sashite::Epin.parse("k^") # Native Makruk king
260
- chess_pawn = Sashite::Epin.parse("p'") # Derived Chess pawn (foreign)
261
-
262
- makruk_king.native? # => true
263
- chess_pawn.derived? # => true
164
+ epin.pin.same_abbr?(other.pin) # => true
165
+ epin.pin.same_state?(other.pin) # => true
166
+ epin.same_derived?(other) # => false
264
167
  ```
265
168
 
266
169
  ## API Reference
267
170
 
268
- ### Parsing and Validation
171
+ ### Types
269
172
 
270
173
  ```ruby
271
- Sashite::Epin.parse(epin_string) # => Sashite::Epin | raises ArgumentError
272
- Sashite::Epin.valid?(epin_string) # => boolean
174
+ # Identifier represents a parsed EPIN combining PIN with derivation status.
175
+ class Sashite::Epin::Identifier
176
+ # Creates an Identifier from a PIN component.
177
+ # Raises ArgumentError if the PIN is invalid.
178
+ #
179
+ # @param pin [Sashite::Pin::Identifier] PIN component
180
+ # @param derived [Boolean] Derived status
181
+ # @return [Identifier]
182
+ def initialize(pin, derived: false)
183
+
184
+ # Returns the PIN component.
185
+ #
186
+ # @return [Sashite::Pin::Identifier]
187
+ def pin
188
+
189
+ # Returns true if derived style.
190
+ #
191
+ # @return [Boolean]
192
+ def derived?
193
+
194
+ # Returns true if native style.
195
+ #
196
+ # @return [Boolean]
197
+ def native?
198
+
199
+ # Returns the EPIN string representation.
200
+ #
201
+ # @return [String]
202
+ def to_s
203
+ end
273
204
  ```
274
205
 
275
- ### Creation
206
+ ### Parsing
276
207
 
277
208
  ```ruby
278
- Sashite::Epin.new(pin) # Native (default)
279
- Sashite::Epin.new(pin, derived: true) # Derived
209
+ # Parses an EPIN string into an Identifier.
210
+ # Raises ArgumentError if the string is not valid.
211
+ #
212
+ # @param string [String] EPIN string
213
+ # @return [Identifier]
214
+ # @raise [ArgumentError] if invalid
215
+ def Sashite::Epin.parse(string)
280
216
  ```
281
217
 
282
- ### Conversion
218
+ ### Validation
283
219
 
284
220
  ```ruby
285
- epin.to_s # => String
221
+ # Reports whether string is a valid EPIN.
222
+ #
223
+ # @param string [String] EPIN string
224
+ # @return [Boolean]
225
+ def Sashite::Epin.valid?(string)
286
226
  ```
287
227
 
288
228
  ### Transformations
289
229
 
290
- All transformations return new `Sashite::Epin` instances:
291
-
292
230
  ```ruby
293
- # PIN replacement
294
- epin.with_pin(new_pin) # => Sashite::Epin with different PIN
231
+ # PIN replacement (returns new Identifier)
232
+ def with_pin(new_pin) # => Identifier with different PIN
295
233
 
296
- # Derivation
297
- epin.mark_derived # => Sashite::Epin with derived: true
298
- epin.unmark_derived # => Sashite::Epin with derived: false
299
- epin.with_derived(boolean) # => Sashite::Epin with specified derivation
234
+ # Derivation transformations
235
+ def derive # => Identifier with derived: true
236
+ def native # => Identifier with derived: false
300
237
  ```
301
238
 
302
- ### Queries
303
-
304
- ```ruby
305
- # Derivation
306
- epin.derived? # => true if derived
307
- epin.native? # => true if not derived
308
-
309
- # Comparison
310
- epin.same_derived?(other) # => true if same derivation status
311
- ```
239
+ ### Errors
312
240
 
313
- ## Data Structure
241
+ All parsing and validation errors raise `ArgumentError` with descriptive messages:
314
242
 
315
- ```ruby
316
- Sashite::Epin
317
- #pin => Sashite::Pin # Underlying PIN instance
318
- #derived => true | false # Derivation status
319
- ```
243
+ | Message | Cause |
244
+ |---------|-------|
245
+ | `"invalid derivation marker"` | Derivation marker misplaced or duplicated |
246
+ | `"invalid PIN component: ..."` | PIN parsing failed |
320
247
 
321
- ## Comparison with PIN
248
+ ## PIN Compatibility
322
249
 
323
- ### What EPIN Adds
250
+ Every valid PIN is a valid EPIN (native by default):
324
251
 
325
252
  ```ruby
326
- # PIN: 4 attributes
327
- pin = Sashite::Pin.parse("K^")
328
- pin.type # Piece Name
329
- pin.side # Piece Side
330
- pin.state # Piece State
331
- pin.terminal # Terminal Status
332
-
333
- # EPIN: 5 attributes (PIN + style)
334
- epin = Sashite::Epin.parse("K^'")
335
- epin.pin.type # Piece Name
336
- epin.pin.side # Piece Side
337
- epin.pin.state # Piece State
338
- epin.pin.terminal # Terminal Status
339
- epin.derived # Piece Style (5th attribute)
340
- ```
341
-
342
- ### When to Use EPIN vs PIN
343
-
344
- **Use PIN when:**
345
- - Single-style games (both players use same style)
346
- - Style information not needed
347
- - Maximum compatibility required
348
-
349
- **Use EPIN when:**
350
- - Cross-style games (different styles per player)
351
- - Pieces can change style (promotion to foreign piece)
352
- - Need to track native vs derived pieces
353
-
354
- ## Design Principles
355
-
356
- ### 1. Pure Composition
357
-
358
- EPIN doesn't reimplement PIN features — it extends PIN minimally:
359
-
360
- ```ruby
361
- def initialize(pin, derived: false)
362
- @pin = pin
363
- @derived = !!derived
364
- freeze
253
+ %w[K +R -p K^ +R^].each do |pin_token|
254
+ epin = Sashite::Epin.parse(pin_token)
255
+ epin.native? # => true
256
+ epin.to_s # => pin_token
365
257
  end
366
258
  ```
367
259
 
368
- ### 2. Minimal API
369
-
370
- **6 core methods only:**
371
- 1. `new` — create from PIN
372
- 2. `pin` — get PIN component
373
- 3. `derived` / `derived?` — check derivation
374
- 4. `to_s` — serialize
375
- 5. `with_pin` — replace PIN
376
- 6. `with_derived` / `mark_derived` / `unmark_derived` — change derivation
377
-
378
- Everything else uses the PIN API directly.
379
-
380
- ### 3. Component Transparency
381
-
382
- Access PIN directly — no wrappers:
383
-
384
- ```ruby
385
- # Use PIN API directly
386
- epin.pin.type
387
- epin.pin.with_type(:Q)
388
- epin.pin.enhanced?
389
- epin.pin.flip
390
-
391
- # No need for wrapper methods like:
392
- # epin.type
393
- # epin.with_type(:Q)
394
- # epin.enhanced?
395
- # epin.flip
396
- ```
397
-
398
- ### 4. Backward Compatibility
260
+ ## Design Principles
399
261
 
400
- Every valid PIN is a valid EPIN (without derivation marker):
401
-
402
- ```ruby
403
- # All PIN identifiers work as EPIN
404
- %w[K +R -p K^ +R^].each do |token|
405
- epin = Sashite::Epin.parse(token)
406
- epin.native? # => true
407
- epin.to_s # => token
408
- end
409
- ```
262
+ - **Pure composition**: EPIN composes PIN without reimplementing features
263
+ - **Minimal API**: Core methods (`pin`, `derived?`, `native?`, `to_s`) plus transformations
264
+ - **Component transparency**: Access PIN directly, no wrapper methods
265
+ - **Immutable identifiers**: Frozen instances prevent mutation
266
+ - **Ruby idioms**: `valid?` predicate, `to_s` conversion, `ArgumentError` for invalid input
410
267
 
411
268
  ## Related Specifications
412
269
 
413
- - [EPIN Specification v1.0.0](https://sashite.dev/specs/epin/1.0.0/) — Technical specification
270
+ - [Game Protocol](https://sashite.dev/game-protocol/) — Conceptual foundation
271
+ - [EPIN Specification](https://sashite.dev/specs/epin/1.0.0/) — Official specification
414
272
  - [EPIN Examples](https://sashite.dev/specs/epin/1.0.0/examples/) — Usage examples
415
- - [PIN Specification v1.0.0](https://sashite.dev/specs/pin/1.0.0/) — Base component
416
- - [Sashité Game Protocol](https://sashite.dev/game-protocol/) — Foundation
273
+ - [PIN Specification](https://sashite.dev/specs/pin/1.0.0/) — Base component
417
274
 
418
275
  ## License
419
276
 
420
- Available as open source under the [MIT License](https://opensource.org/licenses/MIT).
421
-
422
- ## About
423
-
424
- Maintained by [Sashité](https://sashite.com/) — promoting chess variants and sharing the beauty of board game cultures.
277
+ Available as open source under the [Apache License 2.0](https://opensource.org/licenses/Apache-2.0).
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sashite
4
+ module Epin
5
+ # Constants for EPIN (Extended Piece Identifier Notation).
6
+ #
7
+ # EPIN extends PIN with a single derivation marker.
8
+ # PIN constants (VALID_TYPES, VALID_SIDES, VALID_STATES, etc.)
9
+ # are accessed through the sashite-pin dependency.
10
+ module Constants
11
+ # Derivation marker suffix.
12
+ DERIVATION_SUFFIX = "'"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sashite
4
+ module Epin
5
+ module Errors
6
+ class Argument < ::ArgumentError
7
+ # Centralized error messages for EPIN parsing and validation.
8
+ #
9
+ # PIN-related errors (empty input, must contain exactly one letter, etc.)
10
+ # are propagated from the sashite-pin dependency.
11
+ #
12
+ # @example
13
+ # raise Errors::Argument, Messages::INVALID_DERIVATION_MARKER
14
+ module Messages
15
+ # Parsing error
16
+ INVALID_DERIVATION_MARKER = "invalid derivation marker"
17
+
18
+ # Validation errors (constructor)
19
+ INVALID_PIN = "pin must be a Sashite::Pin::Identifier"
20
+ INVALID_DERIVED = "derived must be true or false"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "argument/messages"
4
+
5
+ module Sashite
6
+ module Epin
7
+ module Errors
8
+ # Error raised when EPIN parsing or validation fails.
9
+ #
10
+ # @example
11
+ # raise Argument, Argument::Messages::INVALID_DERIVATION_MARKER
12
+ class Argument < ::ArgumentError
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "errors/argument"