Skip to content

Commit

Permalink
Replace TrimmedString regex with Trimmed predicate type
Browse files Browse the repository at this point in the history
This also adds `TrimmedString.trim` and is a replacement for fthomas#487 based
on the discussion there.
  • Loading branch information
ceedubs committed May 10, 2018
1 parent 25a9e4e commit d84e40b
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ object string extends StringInference {
/** Predicate that checks if a `String` is a valid XPath expression. */
final case class XPath()

/** Predicate that checks if a `String` has no leading or trailing whitespace. */
final case class Trimmed()

object EndsWith {
implicit def endsWithValidate[S <: String](
implicit ws: Witness.Aux[S]): Validate.Plain[String, EndsWith[S]] =
Expand Down Expand Up @@ -234,6 +237,11 @@ object string extends StringInference {
XPath()
)
}

object Trimmed {
implicit def trimmedValidate: Validate.Plain[String, Trimmed] =
Validate.fromPredicate(s => s.trim == s, t => s"$t is trimmed", Trimmed())
}
}

private[refined] trait StringInference {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package eu.timepit.refined.types
import eu.timepit.refined.W
import eu.timepit.refined.api.{Refined, RefinedType, RefinedTypeOps}
import eu.timepit.refined.collection.{MaxSize, NonEmpty}
import eu.timepit.refined.string.MatchesRegex
import eu.timepit.refined.string.{MatchesRegex, Trimmed}
import shapeless.Witness

/** Module for `String` refined types. */
Expand Down Expand Up @@ -52,9 +52,13 @@ object string {
object NonEmptyString extends RefinedTypeOps[NonEmptyString, String]

/** A `String` that contains no leading or trailing whitespace. */
type TrimmedString = String Refined MatchesRegex[W.`"""^(?!\\s).*(?<!\\s)"""`.T]
type TrimmedString = String Refined Trimmed

object TrimmedString extends RefinedTypeOps[TrimmedString, String]
object TrimmedString extends RefinedTypeOps[TrimmedString, String] {

/** Creates a `TrimmedString` from `s` by trimming it. */
def trim(s: String): TrimmedString = Refined.unsafeApply(s.trim)
}

/** A `String` representing a hexadecimal number */
type HexStringSpec = MatchesRegex[W.`"""^(([0-9a-f]+)|([0-9A-F]+))$"""`.T]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ class StringTypesSpec extends Properties("StringTypes") {
(truncated.value ?= str.take(FString3.maxLength))
}

property("""TrimmedString.trim(str)""") = forAll { (str: String) =>
val trimmed = TrimmedString.trim(str)
TrimmedString.from(str) ?= Right(trimmed)
}

// Hashes for ""
object EmptyString {
val md5 = "d41d8cd98f00b204e9800998ecf8427e"
Expand Down
2 changes: 1 addition & 1 deletion scalastyle-config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</check>
<check level="error" class="org.scalastyle.scalariform.NumberOfTypesChecker" enabled="true">
<parameters>
<parameter name="maxTypes"><![CDATA[40]]></parameter>
<parameter name="maxTypes"><![CDATA[45]]></parameter>
</parameters>
</check>
<check level="error" class="org.scalastyle.scalariform.CyclomaticComplexityChecker" enabled="true">
Expand Down

0 comments on commit d84e40b

Please sign in to comment.