class Sashite::Snn::Style
This follows the SNN Specification v1.0.0 with Letter and Side attributes.
All instances are immutable - transformation methods return new instances.
- Lowercase letter: second player (a, b, c, …, z)
- Uppercase letter: first player (A, B, C, …, Z)
A style consists of a single ASCII letter with case-based side encoding:
Represents a style in SNN (Style Name Notation) format.
def self.parse(snn_string)
- Example: Parse SNN strings with case-based side inference -
Raises:
-
(ArgumentError)
- if the SNN string is invalid
Returns:
-
(Style)
- parsed style object with letter and inferred side
Parameters:
-
snn_string
(String
) -- SNN notation string (single ASCII letter)
def self.parse(snn_string) string_value = String(snn_string) validate_snn_string(string_value) # Determine side from case style_side = string_value == string_value.upcase ? FIRST_PLAYER : SECOND_PLAYER # Use the letter directly as symbol style_letter = string_value.to_sym new(style_letter, style_side) end
def self.valid?(snn_string)
- Example: Validate SNN strings -
Returns:
-
(Boolean)
- true if valid SNN, false otherwise
Parameters:
-
snn_string
(String
) -- the string to validate
def self.valid?(snn_string) return false unless snn_string.is_a?(::String) snn_string.match?(SNN_PATTERN) end
def self.valid_letter?(letter)
-
(Boolean)
- true if valid
Parameters:
-
letter
(Object
) -- the letter to check
def self.valid_letter?(letter) return false unless letter.is_a?(::Symbol) letter_string = letter.to_s return false if letter_string.empty? # Must be exactly one ASCII letter letter_string.match?(SNN_PATTERN) end
def self.validate_letter(letter)
-
(ArgumentError)
- if invalid
Parameters:
-
letter
(Symbol
) -- the letter to validate
def self.validate_letter(letter) return if valid_letter?(letter) raise ::ArgumentError, format(ERROR_INVALID_LETTER, letter.inspect) end
def self.validate_side(side)
-
(ArgumentError)
- if invalid
Parameters:
-
side
(Symbol
) -- the side to validate
def self.validate_side(side) return if VALID_SIDES.include?(side) raise ::ArgumentError, format(ERROR_INVALID_SIDE, side.inspect) end
def self.validate_snn_string(string)
-
(ArgumentError)
- if string doesn't match SNN pattern
Parameters:
-
string
(String
) -- string to validate
def self.validate_snn_string(string) return if string.match?(SNN_PATTERN) raise ::ArgumentError, format(ERROR_INVALID_SNN, string) end
def ==(other)
-
(Boolean)
- true if both objects are styles with identical letter and side
Parameters:
-
other
(Object
) -- object to compare with
def ==(other) return false unless other.is_a?(self.class) letter == other.letter && side == other.side end
def first_player?
-
(Boolean)
- true if first player
def first_player? side == FIRST_PLAYER end
def flip
- Example: Flip player sides -
Returns:
-
(Style)
- new immutable style instance with flipped side
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
def hash
-
(Integer)
- hash value based on class, letter, and side
def hash [self.class, letter, side].hash end
def initialize(letter, side)
-
(ArgumentError)
- if parameters are invalid
Parameters:
-
side
(Symbol
) -- player side (:first or :second) -
letter
(Symbol
) -- style letter (single ASCII letter as symbol)
def initialize(letter, side) self.class.validate_letter(letter) self.class.validate_side(side) @letter = letter @side = side freeze end
def opposite_side
-
(Symbol)
- the opposite side
def opposite_side first_player? ? SECOND_PLAYER : FIRST_PLAYER end
def same_letter?(other)
- Example: Compare style letter families -
Returns:
-
(Boolean)
- true if both styles use the same letter family (case-insensitive)
Parameters:
-
other
(Style
) -- style to compare with
def same_letter?(other) return false unless other.is_a?(self.class) letter.to_s.upcase == other.letter.to_s.upcase end
def same_side?(other)
-
(Boolean)
- true if both styles belong to the same side
Parameters:
-
other
(Style
) -- style to compare with
def same_side?(other) return false unless other.is_a?(self.class) side == other.side end
def second_player?
-
(Boolean)
- true if second player
def second_player? side == SECOND_PLAYER end
def to_s
- Example: Display styles -
Returns:
-
(String)
- SNN notation string (single ASCII letter)
def to_s letter.to_s end
def with_letter(new_letter)
- Example: Change style letter -
Returns:
-
(Style)
- new immutable style instance with different letter
Parameters:
-
new_letter
(Symbol
) -- new letter (single ASCII letter as symbol)
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
def with_side(new_side)
- Example: Change player side -
Returns:
-
(Style)
- new immutable style instance with different side
Parameters:
-
new_side
(Symbol
) -- :first or :second
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