Section 2 - Letters

Restricting with Repeated and Letter

But wait! The handles we made in section 1 don’t look very realistic. Only 15 letters are allowed for the username portion of the handle. Let’s update our specification:

import ropes.core._

type Username      = Repeated[1, 15, Letter]
type TwitterHandle = Literal['@'] Concat Username

Being more precise, we’ve stated that the Username must consist of letter characters, repeated 1 to 15 times. It now will not allow usernames which are too long or have non-letter characters:

Rope.parseTo[TwitterHandle]("@HowyP")
// res0: Either[Rope.InvalidValue.type, TwitterHandle] = Right(
//   value = Concat(
//     prefix = Literal(value = '@'),
//     suffix = Repeated(
//       values = List(
//         First(value = CharacterClass(value = 'H')),
//         Second(value = CharacterClass(value = 'o')),
//         Second(value = CharacterClass(value = 'w')),
//         Second(value = CharacterClass(value = 'y')),
//         First(value = CharacterClass(value = 'P'))
//       )
//     )
//   )
// )
Rope.parseTo[TwitterHandle]("@TwoManyCharactersForAUsername")
// res1: Either[Rope.InvalidValue.type, TwitterHandle] = Left(
//   value = InvalidValue
// )
Rope.parseTo[TwitterHandle]("@foo&bar")
// res2: Either[Rope.InvalidValue.type, TwitterHandle] = Left(
//   value = InvalidValue
// )

Now, let’s try generating some handles again:

import org.scalacheck.Arbitrary.arbitrary
import ropes.scalacheck._

List.fill(5)(arbitrary[TwitterHandle].sample).flatten.map(_.write + '\n')
// res3: List[String] = List(
//   """@fpuZklUDFin
// """,
//   """@syWdaCXUJWTPUIu
// """,
//   """@q
// """,
//   """@zMAZLuDJqjXtCrJ
// """,
//   """@fpGJhiuiVNUun
// """
// )

Restricting allowed characters with Range

Letter comes pre-defined in ropes as:

type Letter = Letter.Uppercase Or Letter.Lowercase
object Letter {
    type Uppercase = Range['A', 'Z']
    type Lowercase = Range['a', 'z']
}

It defines the upper and lower case characters using a Range, which takes two literal type parameters specifying the minimum and maximum characters allowed. Or lets us to join the two, allowing characters from either range.