Type-level String Formats

Declare your string formats at the type level, and get parsers, writers, composition and generators for free.

Introduction

Everyone has come across code before that is stringly typed - where there are strong types for data structures, but fields that we know must match a certain format are represented simply as Strings. Things like email addresses, host names, post codes, user/product IDs etc. And often we don’t just need to validate the formats, but to be able to decompose and use specific parts of them

So, the aim of Ropes is to give a general way to define such strongly-typed strings, and give many useful ways to work with them.

Principles

The type of a Rope completely expresses the definition of what values are valid.

Every valid Rope can be:

  • Parsed safely from a String
  • Written precisely back to a String
  • Decomposed into its constituent parts
  • Composed with other Ropes to form a new ones
  • Generated through arbitrary values which always adhere to the definition

Current Status

At the moment, this is very much an alpha. Although lots of effort has been made to ensure good testing, the API may be subject to breaking and radical changes.

Also, because it supports literal types, for the moment we only support Scala 2.13, but it should be possible to also build against Scala 2.12 in the future.

Inspirations

Frank Thomas’s excellent refined library provides a way to enforce restrictions on a wide range of value and collection types in Scala, including Strings. It does this through predicates, which give great power to the user to define any refinement they choose.

However, because of this power, it is also problematic to provide the ability to decompose a refined String based on the given predicate, and is also not generally possible to generate arbitrary values matching predicates.