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" % currentVersionTo 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 notnullor blank (traitRequireAllSpecific)requireAllNotNull()requireAllNotBlank()(forIterable[String]values only)
Anyvalue is notnull(traitRequireAny)requireNotNull
Iterable[T]is notnulland 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()
Stringis not blank or satisfies the regular expression (traitRequireString)requireNotBlank()requirePattern()
Stringis correctUUIDor email (traitRequireStringFormat)requireEmail()requireUuid()requireUrl()
Stringcontains 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
RequireCoreand implement newrequireXXXmethods. - create instance of
Requirewith 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
Requireand 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)