Skip to content

sashite/sin.ex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sin.ex

Hex.pm Docs License

SIN (Style Identifier Notation) implementation for Elixir.

Overview

This library implements the SIN Specification v1.0.0.

Installation

Add sashite_sin to your list of dependencies in mix.exs:

def deps do
  [
    {:sashite_sin, "~> 2.0"}
  ]
end

Usage

Parsing (String → Identifier)

Convert a SIN string into an Identifier struct.

alias Sashite.Sin.Identifier

# Standard parsing (returns {:ok, _} or {:error, _})
{:ok, sin} = Sashite.Sin.parse("C")
sin.style  # => :C
sin.side   # => :first

# Lowercase indicates second player
{:ok, sin} = Sashite.Sin.parse("c")
sin.style  # => :C
sin.side   # => :second

# Bang version (raises on error)
sin = Sashite.Sin.parse!("C")

# Invalid input returns error tuple
{:error, :empty_input} = Sashite.Sin.parse("")
{:error, :input_too_long} = Sashite.Sin.parse("CC")

Formatting (Identifier → String)

Convert an Identifier back to a SIN string.

alias Sashite.Sin.Identifier

# From Identifier struct
sin = Identifier.new(:C, :first)
Identifier.to_string(sin)  # => "C"

sin = Identifier.new(:C, :second)
Identifier.to_string(sin)  # => "c"

Validation

# Boolean check
Sashite.Sin.valid?("C")   # => true
Sashite.Sin.valid?("c")   # => true
Sashite.Sin.valid?("")    # => false
Sashite.Sin.valid?("CC")  # => false
Sashite.Sin.valid?("1")   # => false

Accessing Identifier Data

sin = Sashite.Sin.parse!("C")

# Get attributes (struct fields)
sin.style  # => :C
sin.side   # => :first

# Get string component
Sashite.Sin.Identifier.letter(sin)  # => "C"

Transformations

All transformations return new immutable Identifier structs.

alias Sashite.Sin.Identifier

sin = Sashite.Sin.parse!("C")

# Side transformation
Identifier.flip(sin) |> Identifier.to_string()  # => "c"

# Attribute changes
Identifier.with_style(sin, :S) |> Identifier.to_string()  # => "S"
Identifier.with_side(sin, :second) |> Identifier.to_string()  # => "c"

Queries

alias Sashite.Sin.Identifier

sin = Sashite.Sin.parse!("C")

# Side queries
Identifier.first_player?(sin)   # => true
Identifier.second_player?(sin)  # => false

# Comparison queries
other = Sashite.Sin.parse!("c")
Identifier.same_style?(sin, other)  # => true
Identifier.same_side?(sin, other)   # => false

API Reference

Types

# Identifier represents a parsed SIN identifier with style and side.
%Sashite.Sin.Identifier{
  style: :A..:Z,          # Piece style (always uppercase atom)
  side: :first | :second  # Player side
}

# Create an Identifier from style and side.
# Raises ArgumentError if attributes are invalid.
Sashite.Sin.Identifier.new(style, side)

Constants

Sashite.Sin.Constants.valid_styles()  # => [:A, :B, ..., :Z]
Sashite.Sin.Constants.valid_sides()   # => [:first, :second]
Sashite.Sin.Constants.max_string_length()  # => 1

Parsing

# Parses a SIN string into an Identifier.
# Returns {:ok, identifier} or {:error, reason}.
@spec Sashite.Sin.parse(String.t()) :: {:ok, Identifier.t()} | {:error, atom()}

# Parses a SIN string into an Identifier.
# Raises ArgumentError if the string is not valid.
@spec Sashite.Sin.parse!(String.t()) :: Identifier.t()

Validation

# Reports whether string is a valid SIN identifier.
@spec Sashite.Sin.valid?(String.t()) :: boolean()

Transformations

All transformations return new Sashite.Sin.Identifier structs:

# Side transformation
@spec Identifier.flip(Identifier.t()) :: Identifier.t()

# Attribute changes
@spec Identifier.with_style(Identifier.t(), atom()) :: Identifier.t()
@spec Identifier.with_side(Identifier.t(), atom()) :: Identifier.t()

Queries

# Side queries
@spec Identifier.first_player?(Identifier.t()) :: boolean()
@spec Identifier.second_player?(Identifier.t()) :: boolean()

# Comparison queries
@spec Identifier.same_style?(Identifier.t(), Identifier.t()) :: boolean()
@spec Identifier.same_side?(Identifier.t(), Identifier.t()) :: boolean()

Errors

Parsing errors are returned as atoms:

Atom Cause
:empty_input String length is 0
:input_too_long String exceeds 1 character
:must_be_letter Character is not A-Z or a-z

Design Principles

  • Bounded values: Explicit validation of styles and sides
  • Struct-based: Identifier struct enables pattern matching and encapsulation
  • Elixir idioms: {:ok, _} / {:error, _} tuples, parse! bang variant
  • Immutable data: All transformations return new structs
  • No dependencies: Pure Elixir standard library only

Related Specifications

License

Available as open source under the Apache License 2.0.

About

SIN (Style Identifier Notation) implementation for Elixir with immutable style objects.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages