/regex_spec

Regular Expression specification compiler for Elixir

Primary LanguageElixirMIT LicenseMIT

Regex.Spec

Generates type specifications for Regular Expressions at compile time allowing Dialyzer to detect type errors.

Build Status Hex.pm

This library is a work in progress that was inspired by Stephanie Weirich's talk Dependent Types in Haskell at Strange Loop 2017. The design is evolving based on the constraints imposed by Elixir:

  1. we cannot specify a list of n elements, so we need to return a tuple
  2. we use String.t() | nil to represent a maybe type based on a (...)? pattern
  3. we generate a map of results with optional and required keys for named captures
  4. can we pass in a list of parse functions that can be applied to the matches and modify the return type e.g. from String.t() -> integer()

This library generates the common Regex functions for your regular expression with a type spec. Create a module for your type and use:

defmodule MyApp do

  defmodule MMYYDDDD do
    use Regex.Spec, regex: ~r/(\d{2})\-(\d{2})\-(\d{4})/
  end

  IO.inspect(MMYYDDDD.matches?("2020-12-31")) # false
  IO.inspect(MMYYDDDD.run("12-31-2020")) # ["12-31-2020", "12", "31", "2020"]
  IO.inspect(MMYYDDDD.runt("12-31-2020")) # {"12-31-2020", "12", "31", "2020"}

end

The specification for run/3 is a list of Strings, and we cannot specify a dependent type such as a list of length 4. Therefore we implement the normal run function and also runt which can be read as run typed or run tuple which returns a typed tuple.

Installation

This library is incomplete, but you can append to your mix.exs deps:

    {:regex_spec, "~> 0.21"}

Design

This library uses leex and yecc to compile your regular expression into a tree of capture groups and then into a Dialyzer tuple type specification.

The docs can be found at https://hexdocs.pm/regex_spec.