Refined Argument Types

Decline has support for refined types via the decline-refined module. Refined types add an extra layer of safety by decorating standard types with predicates that get validated automatically at compile time.

Whilst in the case of command line arguments such validation can not happen at compile time since the values are not know at the moment of building the code, runtime validation can still be done right before any value of the command arguments is passed into the application logic, preventing the introduction of invalid values by the user.

Defining Refined Type Arguments

To make use of the refined types add the following to your build.sbt:

libraryDependencies += "com.monovore" %% "decline-refined" % "0.4.0"

And now we need to add a series of imports into our current scope:

import com.monovore.decline._
import com.monovore.decline.refined._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric.Positive

Following there is a very simple example of a numeric option which needs to be positive. We start by defining a new type that can only hold positive integers:

type PosInt = Int Refined Positive
// defined type alias PosInt

And now we define an option parameterised on that specific type and a command so we can test it:

val lines = Opts.option[PosInt]("lines", short = "n", metavar = "count", help = "Set a number of lines.")
// lines: com.monovore.decline.Opts[PosInt] = Opts(--lines <count>)

val cmd = Command("echoLines", "Echoes the number of lines")(lines)
// cmd: com.monovore.decline.Command[PosInt] = com.monovore.decline.Command@5315175d

If we now try to parse a command line in which we have a --lines 10 argument pair we should be able to parse the lines option:

cmd.parse(Seq("--lines", "10"))
// res0: Either[com.monovore.decline.Help,PosInt] = Right(10)

However if we pass a 0 or a non positive value, the parse operation should fail:

cmd.parse(Seq("--lines", "0"))
// res1: Either[com.monovore.decline.Help,PosInt] =
// Left(Predicate failed: (0 > 0).
// 
// Usage: echoLines --lines <count>
// 
// Echoes the number of lines
// 
// Options and flags:
//     --help
//         Display this help text.
//     --lines <count>, -n <count>
//         Set a number of lines.)

Check the documentation for refined to see how you can define your own refined types.