Scala library that provides extendable API to check method preconditions.
- predicates and method precondition checkers for most common cases
- fully tested (code coverage is more than 97%)
- well-formed failure messages
- easy customisation (single place)
- easy extensibility (traits)
- Scala 2.11 and 2.12
Add dependency to build.sbt
:
libraryDependencies += "ru.ars-co" %% "scala-preconditions" % currentVersion
To use default implementation:
- add imports
import ars.precondition.require.Require.Default._ // requireXXX methods import ars.precondition.implicits._ // implicit conversions
- add preconditions to your methods, for example:
def foo(name: String, age: Int, email: Option[String], code: String, custom: MyValue) = { requireNotBlank(name, "name") requireNonNegative(age, "age") optional(email, "email")(requireEmail) requirePattern(code, "[A-Z]{4,7}".r, "code") require(myCustomCheck(custom), "The argument `custom` is not valid.") . . . }
The library provides predicates and precondition checkers to test that
- all elements of
Iterable[T]
meet the requirements (traitRequireAll
)requireAll()
requireAllPredicate()
- all elements of
Iterable[T]
is notnull
or blank (traitRequireAllSpecific
)requireAllNotNull()
requireAllNotBlank()
(forIterable[String]
values only)
Any
value is notnull
(traitRequireAny
)requireNotNull
Iterable[T]
is notnull
and empty (traitRequireIterable
)requireNotBlank()
- numeric value is positive or negative (trait
RequireNumeric
)requirePositive()
requireNegative()
requireNonPositive()
requireNonNegative()
- numeric value in range (trait
RequireNumericRange
)requireNumber()
requireNumberFrom()
requireNumberUntil()
requireNumberInRange()
- numeric specific ranges
requirePort()
Option[T]
value meets the requirements (traitRequireOptional
)optional()
optionalPredicate()
- size of
Iterable[T]
in range (traitRequireSize
)requireSize()
requireSizeFrom()
requireSizeUntil()
requireSizeInRange()
String
is not blank or satisfies the regular expression (traitRequireString
)requireNotBlank()
requirePattern()
String
is correctUUID
or email (traitRequireStringFormat
)requireEmail()
requireUuid()
requireUrl()
String
contains correct numeric value (traitRequireStringNumeric
)requireByte()
requireShort()
requireInt()
requireLong()
requireFloat()
requireDouble()
The library is based on concepts of Predef.require()
method from Scala standard library. It reimplements
similar method with enhancements.
The core trait is RequireCore
. It contains 4 methods which is used to implement all other precondition checkers:
exception()
- encapsulates exception creationfailureMessage()
- encapsulates failure message generationfail()
- creates exception and throws itrequire()
- tests requirement and throws exception if it's fail
All other RequireXXX
traits extend RequireCore
and their requireXXX
are based on these 4 methods
and specific predicates.
Require
class is the default implementation of all RequireXXX
traits. Its companion object
has default instance Require.Default
. The best practice is to import all methods of Require.Default
:
import ars.precondition.require.Require.Default._
If you want to use custom prefixes or postfixes for all generated messages, create
new instance of Require
with PrefixPostfixMessage
and override prefix
and/or postfix
methods.
Example:
val PrefixedRequire = new Require extends PrefixPostfixMessage {
override def prefix: String = "PREFIX "
override def postfix: String = " POSTFIX"
}
To implement custom RequireXXX
trait
- create new trait that extends
RequireCore
and implement newrequireXXX
methods. - create instance of
Require
with new trait
Example:
trait RequireNew extends RequireCore {
def requireNew(value: String, name: String = NoParameterName): Unit = {
require(value == "new", s"Parameter `$new` is not new.")
}
}
final val MyRequire = new RequireNew
import MyRequire._
def foo(newValue: String) = {
requireNew(newValue, "newValue")
}
To customize exception type
- create new class that extends
Require
and overrideexception()
method. - create instance of new class
Example:
class RequireWithMyException extends Require {
override def exception(message: String, cause: Option[RuntimeException] = None): RuntimeException = {
//...
}
}
final val MyRequire = new RequireWithMyException
import MyRequire._
Copyright 2018-2020 Arsen Ibragimov (ars)