Class: Sashite::Sin::Identifier
- Inherits:
-
Object
- Object
- Sashite::Sin::Identifier
- Defined in:
- lib/sashite/sin/identifier.rb
Overview
Represents an identifier in SIN (Style Identifier Notation) format.
An identifier consists of a single ASCII letter with case-based side encoding:
-
Uppercase letter: first player (A, B, C, …, Z)
-
Lowercase letter: second player (a, b, c, …, z)
All instances are immutable - transformation methods return new instances. This follows the SIN Specification v1.0.0 with Letter and Side attributes.
Constant Summary collapse
- SIN_PATTERN =
SIN validation pattern matching the specification
/\A[A-Za-z]\z/
- FIRST_PLAYER =
Player side constants
:first
- SECOND_PLAYER =
:second
- VALID_SIDES =
Valid sides
[FIRST_PLAYER, SECOND_PLAYER].freeze
- ERROR_INVALID_SIN =
Error messages
"Invalid SIN string: %s"
- ERROR_INVALID_LETTER =
"Letter must be a single ASCII letter symbol (A-Z, a-z), got: %s"
- ERROR_INVALID_SIDE =
"Side must be :first or :second, got: %s"
Instance Attribute Summary collapse
-
#letter ⇒ Symbol
readonly
The style letter (single ASCII letter as symbol).
-
#side ⇒ Symbol
readonly
The player side (:first or :second).
Class Method Summary collapse
-
.parse(sin_string) ⇒ Identifier
Parse an SIN string into an Identifier object.
-
.valid?(sin_string) ⇒ Boolean
Check if a string is a valid SIN notation.
-
.validate_letter(letter) ⇒ Object
Validate that the letter is a valid single ASCII letter symbol.
-
.validate_side(side) ⇒ Object
Validate that the side is a valid symbol.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
(also: #eql?)
Custom equality comparison.
-
#first_player? ⇒ Boolean
Check if the identifier belongs to the first player.
-
#flip ⇒ Identifier
Create a new identifier with opposite ownership (side).
-
#hash ⇒ Integer
Custom hash implementation for use in collections.
-
#initialize(letter, side) ⇒ Identifier
constructor
Create a new identifier instance.
-
#same_letter?(other) ⇒ Boolean
Check if this identifier has the same letter family as another.
-
#same_side?(other) ⇒ Boolean
Check if this identifier belongs to the same side as another.
-
#second_player? ⇒ Boolean
Check if the identifier belongs to the second player.
-
#to_s ⇒ String
Convert the identifier to its SIN string representation.
-
#with_letter(new_letter) ⇒ Identifier
Create a new identifier with a different letter (keeping same side).
-
#with_side(new_side) ⇒ Identifier
Create a new identifier with a different side (keeping same letter family).
Constructor Details
#initialize(letter, side) ⇒ Identifier
Create a new identifier instance
40 41 42 43 44 45 46 47 48 |
# File 'lib/sashite/sin/identifier.rb', line 40 def initialize(letter, side) self.class.validate_letter(letter) self.class.validate_side(side) @letter = letter @side = side freeze end |
Instance Attribute Details
#letter ⇒ Symbol (readonly)
Returns the style letter (single ASCII letter as symbol).
30 31 32 |
# File 'lib/sashite/sin/identifier.rb', line 30 def letter @letter end |
#side ⇒ Symbol (readonly)
Returns the player side (:first or :second).
33 34 35 |
# File 'lib/sashite/sin/identifier.rb', line 33 def side @side end |
Class Method Details
.parse(sin_string) ⇒ Identifier
Parse an SIN string into an Identifier object
59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/sashite/sin/identifier.rb', line 59 def self.parse(sin_string) string_value = String(sin_string) validate_sin_string(string_value) # Determine side from case identifier_side = string_value == string_value.upcase ? FIRST_PLAYER : SECOND_PLAYER # Use the letter directly as symbol identifier_letter = string_value.to_sym new(identifier_letter, identifier_side) end |
.valid?(sin_string) ⇒ Boolean
Check if a string is a valid SIN notation
81 82 83 84 85 |
# File 'lib/sashite/sin/identifier.rb', line 81 def self.valid?(sin_string) return false unless sin_string.is_a?(::String) sin_string.match?(SIN_PATTERN) end |
.validate_letter(letter) ⇒ Object
Validate that the letter is a valid single ASCII letter symbol
198 199 200 201 202 |
# File 'lib/sashite/sin/identifier.rb', line 198 def self.validate_letter(letter) return if valid_letter?(letter) raise ::ArgumentError, format(ERROR_INVALID_LETTER, letter.inspect) end |
.validate_side(side) ⇒ Object
Validate that the side is a valid symbol
208 209 210 211 212 |
# File 'lib/sashite/sin/identifier.rb', line 208 def self.validate_side(side) return if VALID_SIDES.include?(side) raise ::ArgumentError, format(ERROR_INVALID_SIDE, side.inspect) end |
Instance Method Details
#==(other) ⇒ Boolean Also known as: eql?
Custom equality comparison
178 179 180 181 182 |
# File 'lib/sashite/sin/identifier.rb', line 178 def ==(other) return false unless other.is_a?(self.class) letter == other.letter && side == other.side end |
#first_player? ⇒ Boolean
Check if the identifier belongs to the first player
141 142 143 |
# File 'lib/sashite/sin/identifier.rb', line 141 def first_player? side == FIRST_PLAYER end |
#flip ⇒ Identifier
Create a new identifier with opposite ownership (side)
103 104 105 106 |
# File 'lib/sashite/sin/identifier.rb', line 103 def flip new_letter = first_player? ? letter.to_s.downcase.to_sym : letter.to_s.upcase.to_sym self.class.new(new_letter, opposite_side) end |
#hash ⇒ Integer
Custom hash implementation for use in collections
190 191 192 |
# File 'lib/sashite/sin/identifier.rb', line 190 def hash [self.class, letter, side].hash end |
#same_letter?(other) ⇒ Boolean
Check if this identifier has the same letter family as another
158 159 160 161 162 |
# File 'lib/sashite/sin/identifier.rb', line 158 def same_letter?(other) return false unless other.is_a?(self.class) letter.to_s.upcase == other.letter.to_s.upcase end |
#same_side?(other) ⇒ Boolean
Check if this identifier belongs to the same side as another
168 169 170 171 172 |
# File 'lib/sashite/sin/identifier.rb', line 168 def same_side?(other) return false unless other.is_a?(self.class) side == other.side end |
#second_player? ⇒ Boolean
Check if the identifier belongs to the second player
148 149 150 |
# File 'lib/sashite/sin/identifier.rb', line 148 def second_player? side == SECOND_PLAYER end |
#to_s ⇒ String
Convert the identifier to its SIN string representation
94 95 96 |
# File 'lib/sashite/sin/identifier.rb', line 94 def to_s letter.to_s end |
#with_letter(new_letter) ⇒ Identifier
Create a new identifier with a different letter (keeping same side)
114 115 116 117 118 119 120 121 |
# File 'lib/sashite/sin/identifier.rb', line 114 def with_letter(new_letter) self.class.validate_letter(new_letter) return self if letter == new_letter # Ensure the new letter has the correct case for the current side adjusted_letter = first_player? ? new_letter.to_s.upcase.to_sym : new_letter.to_s.downcase.to_sym self.class.new(adjusted_letter, side) end |
#with_side(new_side) ⇒ Identifier
Create a new identifier with a different side (keeping same letter family)
129 130 131 132 133 134 135 136 |
# File 'lib/sashite/sin/identifier.rb', line 129 def with_side(new_side) self.class.validate_side(new_side) return self if side == new_side # Adjust letter case for the new side new_letter = new_side == FIRST_PLAYER ? letter.to_s.upcase.to_sym : letter.to_s.downcase.to_sym self.class.new(new_letter, new_side) end |