I am writing tests for the Json output of some API calls in my API, written with Play on Scala. In my tests, this pattern keeps appearing, and I would like to deduplicate it.
val response = sut.index()(FakeRequest())
val expected = Json.parse("""{ "channels":[] }""")
status(response) must equalTo(OK)
contentType(response) must beSome.which(_ == "application/json")
contentAsJson(response) mustEqual expected
My first approach was this:
def assertSameJson(response: Future[Result], expected: JsValue): Unit = {
status(response) must equalTo(OK)
contentType(response) must beSome.which(_ == "application/json")
contentAsJson(response) mustEqual expected
}
But this does not feel idiomatic at all. Is seems like I am adding xUnit asserts in my specs
I would like something leading to
response must beSameJson(expected)
The closest thing I managed was
def beSameJson(other:Any) =
be_==(other) ^^ ((t: Future[Result]) => contentAsJson(t)) and
be_==(OK) ^^ ((t: Future[Result]) => status(t))
But this does not check for the content-type, and I feel it's just very hard to read.
Is there a better way to write this Matcher?
I don't think there is a better way to do that.
The ^^ operator is exactly there for this purpose to transform the information before applying an other matcher. and can be used to combine more than two matchers.
So the only thing you could do is to try to write it a bit cleaner:
def beSameJson(data: String) =
equalTo(OK) ^^ {status(_: Future[Result])}
and beSome.which(_ == "application/json") ^^ {contentType(_: Future[Result])}
and be_==(other) ^^ {contentAsJson(_: Future[Result])}
If you need to decompose responses more often, you could try to do this more generically
object Dummy extends Matcher[Any] {
def apply[S <: Any](s: Expectable[S]) = {
result(true,
s.description + " is ignored",
s.description + " is ignored",
s)
}
}
def beResponseWhere(json: Matcher[JsValue] = Dummy, stat: Matcher[Int] = Dummy, tpe: Matcher[Option[String]] = Dummy) =
stat ^^ {status(_: Future[Result])}
and tpe ^^ {contentType(_: Future[Result])}
and json ^^ {contentAsJson(_: Future[Result])}
}
You should probably use nicer parameter names (I tried to avoid conflict with the methods from your context for this example) and be more complete on the available attributes.
Now you should be able to write something like this:
response must beResponseWhere(
json = equalTo(expected),
tpe = beSome.which(_ == "application/json"),
stat = equalTo(OK)
)
The DummyMatcher allows you to leave some parts out.
I obviously did not try this code as I do not have your complete setting. I also had to guess some types that are not clear from your code snippet.
Related
I have a function that makes an HTTP request using the Softwaremill sttp client. I am also using the Cats library for the leftMap functionality. Here is the function:
def tags(repositoryName: String): Either[String, List[Tag]] = {
val uri = uri"$gitLabBaseUrl/api/v4/projects/$repositoryName/repository/tags"
val request = sttp.get(uri).header("PRIVATE-TOKEN", privateToken).response(asJson[List[Tag]])
request
.send()
.body
.flatMap(
_.leftMap(
e => Left(e.message)
)
)
.leftMap(_.toString)
}
So as you can see I want the signature of the function to be Either[String, List[Tag]]. However, to achieve this I need to do two leftMap statements, where in my reasoning just the first leftMap should be sufficient. I broke the statement down to get the type signatures:
val foo: Id[Response[Either[DeserializationError[circe.Error], List[Tag]]]] = request.send()
val foo2: Either[String, Either[DeserializationError[circe.Error], List[Tag]]] = request.send().body
val foo3: Either[io.Serializable, List[Tag]] = request.send().body.flatMap(_.leftMap(e => Left(e.message)))
And as you can see the Either that is returned by the flatMap is of type [io.Serializable, List[Tag]]. However, the signature from request.send().body is:
Either[String, Either[DeserializationError[circe.Error], List[Tag]]]
so therefore e.message results in a String and as such I was expecting the
_.leftMap(e => Left(e.message))
statement to already result in a
Either[String, List[Tag]]
But instead it has as signature
Either[io.Serializable, List[Tag]]
So I need to do the second leftMap to get to the correct signature of
Either[String, List[Tag]]
Could someone please help me out how I can avoid having to do the second leftMap? It seems like it shouldn't be necessary but I have not been able to figure out how to solve it.
Thanks!
Try
request
.send()
.body
.flatMap { _.left.map(_.message) }
Is it possible to run multiple extractors in one match statement?
object CoolStuff {
def unapply(thing: Thing): Option[SomeInfo] = ...
}
object NeatStuff {
def unapply(thing: Thing): Option[OtherInfo] = ...
}
// is there some syntax similar to this?
thing match {
case t # CoolStuff(someInfo) # NeatStuff(otherInfo) => process(someInfo, otherInfo)
case _ => // neither Cool nor Neat
}
The intent here being that there are two extractors, and I don't have to do something like this:
object CoolNeatStuff {
def unapply(thing: Thing): Option[(SomeInfo, OtherInfo)] = thing match {
case CoolStuff(someInfo) => thing match {
case NeatStuff(otherInfo) => Some(someInfo -> otherInfo)
case _ => None // Cool, but not Neat
case _ => None// neither Cool nor Neat
}
}
Can try
object ~ {
def unapply[T](that: T): Option[(T,T)] = Some(that -> that)
}
def too(t: Thing) = t match {
case CoolStuff(a) ~ NeatStuff(b) => ???
}
I've come up with a very similar solution, but I was a bit too slow, so I didn't post it as an answer. However, since #userunknown asks to explain how it works, I'll dump my similar code here anyway, and add a few comments. Maybe someone finds it a valuable addition to cchantep's minimalistic solution (it looks... calligraphic? for some reason, in a good sense).
So, here is my similar, aesthetically less pleasing proposal:
object && {
def unapply[A](a: A) = Some((a, a))
}
// added some definitions to make your question-code work
type Thing = String
type SomeInfo = String
type OtherInfo = String
object CoolStuff {
def unapply(thing: Thing): Option[SomeInfo] = Some(thing.toLowerCase)
}
object NeatStuff {
def unapply(thing: Thing): Option[OtherInfo] = Some(thing.toUpperCase)
}
def process(a: SomeInfo, b: OtherInfo) = s"[$a, $b]"
val res = "helloworld" match {
case CoolStuff(someInfo) && NeatStuff(otherInfo) =>
process(someInfo, otherInfo)
case _ =>
}
println(res)
This prints
[helloworld, HELLOWORLD]
The idea is that identifiers (in particular, && and ~ in cchantep's code) can be used as infix operators in patterns. Therefore, the match-case
case CoolStuff(someInfo) && NeatStuff(otherInfo) =>
will be desugared into
case &&(CoolStuff(someInfo), NeatStuff(otherInfo)) =>
and then the unapply method method of && will be invoked which simply duplicates its input.
In my code, the duplication is achieved by a straightforward Some((a, a)). In cchantep's code, it is done with fewer parentheses: Some(t -> t). The arrow -> comes from ArrowAssoc, which in turn is provided as an implicit conversion in Predef. This is just a quick way to create pairs, usually used in maps:
Map("hello" -> 42, "world" -> 58)
Another remark: notice that && can be used multiple times:
case Foo(a) && Bar(b) && Baz(c) => ...
So... I don't know whether it's an answer or an extended comment to cchantep's answer, but maybe someone finds it useful.
For those who might miss the details on how this magic actually works, just want to expand the answer by #cchantep anf #Andrey Tyukin (comment section does not allow me to do that).
Running scalac with -Xprint:parser option will give something along those lines (scalac 2.11.12)
def too(t: String) = t match {
case $tilde(CoolStuff((a # _)), NeatStuff((b # _))) => $qmark$qmark$qmark
}
This basically shows you the initial steps compiler does while parsing source into AST.
Important Note here is that the rules why compiler makes this transformation are described in Infix Operation Patterns and Extractor Patterns. In particular, this allows you to use any object as long as it has unapply method, like for example CoolStuff(a) AndAlso NeatStuff(b). In previous answers && and ~ were picked up as also possible but not the only available valid identifiers.
If running scalac with option -Xprint:patmat which is a special phase for translating pattern matching one can see something similar to this
def too(t: String): Nothing = {
case <synthetic> val x1: String = t;
case9(){
<synthetic> val o13: Option[(String, String)] = main.this.~.unapply[String](x1);
if (o13.isEmpty.unary_!)
{
<synthetic> val p3: String = o13.get._1;
<synthetic> val p4: String = o13.get._2;
{
<synthetic> val o12: Option[String] = main.this.CoolStuff.unapply(p3);
if (o12.isEmpty.unary_!)
{
<synthetic> val o11: Option[String] = main.this.NeatStuff.unapply(p4);
if (o11.isEmpty.unary_!)
matchEnd8(scala.this.Predef.???)
Here ~.unapply will be called on input parameter t which will produce Some((t,t)). The tuple values will be extracted into variables p3 and p4. Then, CoolStuff.unapply(p3) will be called and if the result is not None NeatStuff.unapply(p4) will be called and also checked if it is not empty. If both are not empty then according to Variable Patterns a and b will be bound to returned results inside corresponding Some.
I'm finding the following pattern popping up repeatedly in my code, and my intuition says there must be some idiomatic Scala way to better express this (Monadic or otherwise):
val someCollection: Seq[Thing] = ...
val makeBlah: Seq[Thing] => Blah = ...
...
if (someCollection.nonEmpty) Some(makeBlah(someCollection)) else None
To be more specific, I'm looking for something along the lines of what you can do with Option[T]:
val someOption: Option[Thing] = ...
val makeBlah: Thing => Blah = ...
...
val result: Option[Blah] = someOption.map(makeBlah)
...but with evaluation semantics based on some predicate rather than Some/None pattern matching in map.
While the example above uses a collection--first performing a test on it, optionally followed by an operation--I don't mean to imply a collections specific use case. You could imagine a case where Boolean is lifted or coerced into some monad:
val aThing: Thing = ...
val makeBlah: Thing => Blah = ...
val thingTest: Thing => Boolean ...
// theoretical
implicit def optionOnBoolean(b: Boolean): MonadOps[Option[Boolean]] = ...
...
// NB: map could either have a Boolean parameter
// that's always true, or be Unit.
// Neither seem like good design
val result: Option[Blah] = thingTest(aThing).map(makeBlah(aThing))
Intuitively this seems like a bad idea to me because it explicitly splits the data flow since you don't really have anything to pass via map.
When looking for a general approach that has "monadic-like" behavior without a closure to capture data, one has to answer the question of what to pass to map and how its connection to the predicate. Here's the type of construct that comes to mind:
val thing: Thing = ....
val makeBlah: Thing => Blah = ...
val thingTest: (Thing) => Boolean = ...
val result: Option[Blah] = WhenOption(thing, thingTest).map(makeBlah)
My question: Does something already exist in Scala proper, or does one have to venture out to Scalaz to get this sort of construct?
Or is there some other approach that is customary/idiomatic Scala?
Edit: My question is close to Scala - "if(true) Some(1)" without having to type "else None" but I wish to address the issue of achieving it without a closure.
For completeness:
val someCollection: Seq[Thing] = ...
val makeBlah: Seq[Thing] => Blah = ...
You can use some methods on Option:
Some(someCollection).filterNot(_.isEmpty).map(makeBlah)
or as for comprehension
for(sc <- Some(someCollection) if !someCollection.isEmpty) yield makeBla(sc)
or as pattern match
someCollection match {
case Seq() => None
case x => Some(makeBlah(x))
}
But I think the if-then-else approach is the most readable one.
I would just continue doing what you're doing unless you find yourself repeating that same logic ad nauseum within the same function scope. It's readable and makes sense. That said, if you really need to, you can "lift" a PartialFunction (see here):
def foo: PartialFunction[Seq[A], B]
def fooLifted: (Seq[A] => Option[B]) = foo.lift
Now all you have to do is make your conditional logic explicit
def foo ={
case seq if predicate(seq) => doStuff(seq)
}
This is a lot more boilerplate than what you're doing.
FWIW, I do the same thing you propose:
implicit class RichBoolean(val b: Boolean) extends AnyVal {
def map[T](f: => T): Option[T] = if (b) Some(f) else None
def flatMap[T](f: => Option[T]): Option[T] = if (b) f else None
}
"map" doesn't feel right here, but I can't think of anything better. I really like this construct, it can really help keep the "flow" when doing a few consecutive operations on your data.
Suppose I would like to code the following logic in Scala
val xdir = System.getProperty("XDir")
if (xdir == null)
error("No XDir") // log the error and exit
val ydir = System.getProperty("YDir")
if (ydir == null)
error("No YDir")
if (!new File(xdir).isDirectory)
error("XDir is not a directory")
if (!new File(ydir).isDirectory)
error("YDir is not a directory")
if (!new File(xdir).exists)
error("XDir does not exis")
if (!new File(ydir).exists)
error("YDir does not exist")
...
(and so on)
What is the best way to code this chain of validations in Scala?
Here's some useful things:
def sysValue(prop: String) = Option(System.getProperty(prop)) //returns Option[String]
def trySysValue(prop: String) = //returns Either[String, String]
sysValue(prop) map Right getOrElse Left("Absent property: " + prop)
Then you can use monadic composition of Either through its right-projection
val batch = //batch is Either[String, (File, File)]
for {
x <- trySysValue("XDir")).right
xf <- dir(x).right
y <- trySysValue("YDir").right
yf <- dir(y).right
}
yield (xf, yf)
Where:
def dir(s: String) = { //returns Either[String, File]
val f = new File(s)
if (!f.exists()) Left("Does not exist: " + f)
else if (!f.isDir()) Left("Is not a directory: " + f)
else Right(f)
}
The left-hand-side of the Either will be an error message. This monadic composition is fail fast. You can achieve composition which will accumulate all failures (for example, if neither XDir nor YDir exist, you would see both messages) using scalaz Validation. In that case, the code would look like this:
def trySysValue(prop: String) = //returns Validation[String, String]
sysValue(prop) map Success getOrElse ("Absent property: " + prop).fail
def dir(s: String) = {
val f = new File(s)
if (!f.exists())("Does not exist: " + f).fail
else if (!f.isDir()) ("Is not a directory: " + f).fail
else f.success
}
val batch = //batch is ValidationNEL[String, (File, File)]
(trySysValue("XDir")) flatMap dir).liftFailNel <|*|> (trySysValue("YDir")) flatMap dir).liftFailNel
something like:
val batch = for{
a <- safe(doA, "A failed") either
b <- safe(doB, "B failed") either
c <- safe(doC, "C failed") either
} yield(a,b,c)
batch fold( error(_), doSuccess(_) )
Where safe performs a, you guessed it, safe (try/catch) operation that takes a failure (Left outcome) message and returns an Either RightProjection (which allows you to do above batch operation while threading through the point-of-failure error message)
class Catching[T](f: => T) {
def either(msg: String) = {
try { Right(f).right } catch { Left(msg).right }
}
}
def safe[T](f: => T) = new Catching(f)
Can add an option method to Catching class as well, along with logging if you want to log particular error types.
See Jason Zaugg's solution for right biasing Either and this thread from scala-debate on the subject as well. No consensus as yet, but most scala "heavies" seem to be in favor.
One limitation of this approach is that if you attempt to add conditionals (if a = b) to the for{} block, it won't compile (since default Either filter method returns Option). The workaround is to implement filter and withFilter, returning Either, something I have yet to figure out/do (if someone has already done so, please post)
Yes you can use validation without scalaz, see here for a self containt implementation :
http://applicative-errors-scala.googlecode.com/svn/artifacts/0.6/chunk-xhtml/apa.html
HTH
Basically, I would like to be able to build a custom extractor without having to store it in a variable prior to using it.
This isn't a real example of how I would use it, it would more likely be used in the case of a regular expression or some other string pattern like construct, but hopefully it explains what I'm looking for:
def someExtractorBuilder(arg:Boolean) = new {
def unapply(s:String):Option[String] = if(arg) Some(s) else None
}
//I would like to be able to use something like this
val {someExtractorBuilder(true)}(result) = "test"
"test" match {case {someExtractorBuilder(true)}(result) => result }
//instead I would have to do this:
val customExtractor = someExtractorBuilder(true)
val customExtractor(result) = "test"
"test" match {case customExtractor(result) => result}
When just doing a single custom extractor it doesn't make much difference, but if you were building a large list of extractors for a case statement, it could make things more difficult to read by separating all of the extractors from their usage.
I expect that the answer is no you can't do this, but I thought I'd ask around first :D
Parameterising extractors would be cool, but we don't have the resources to implement them right now.
Nope.
8.1.7 Extractor Patterns
An extractor pattern x (p 1 , . . . ,
p n ) where n ≥ 0 is of the same
syntactic form as a constructor
pattern. However, instead of a case
class, the stable identifier x denotes
an object which has a member method
named unapply or unapplySeq that
matches the pattern.
One can customize extractors to certain extent using implicit parameters, like this:
object SomeExtractorBuilder {
def unapply(s: String)(implicit arg: Boolean): Option[String] = if (arg) Some(s) else None
}
implicit val arg: Boolean = true
"x" match {
case SomeExtractorBuilder(result) =>
result
}
Unfortunately this cannot be used when you want to use different variants in one match, as all case statements are in the same scope. Still, it can be useful sometimes.
Late but there is a scalac plugin in one of my lib providing syntax ~(extractorWith(param), bindings):
x match {
case ~(parametrizedExtractor(param)) =>
"no binding"
case ~(parametrizedExtractor(param), (a, b)) =>
s"extracted bindings: $a, $b"
}
https://github.com/cchantep/acolyte/blob/master/scalac-plugin/readme.md
Though what you are asking isn't directly possible,
it is possible to create an extractor returning a contaner that gets evaluated value in the if-part of the case evaluation. In the if part it is possible to provide parameters.
object DateExtractor {
def unapply(in: String): Option[DateExtractor] = Some(new DateExtractor(in));
}
class DateExtractor(input:String){
var value:LocalDate=null;
def apply():LocalDate = value;
def apply(format: String):Boolean={
val formater=DateTimeFormatter.ofPattern(format);
try{
val parsed=formater.parse(input, TemporalQueries.localDate());
value=parsed
true;
} catch {
case e:Throwable=>{
false
}
}
}
}
Usage:
object DateExtractorUsage{
def main(args: Array[String]): Unit = {
"2009-12-31" match {
case DateExtractor(ext) if(ext("dd-MM-yyyy"))=>{
println("Found dd-MM-yyyy date:"+ext())
}
case DateExtractor(ext) if(ext("yyyy-MM-dd"))=>{
println("Found yyyy-MM-dd date:"+ext())
}
case _=>{
println("Unable to parse date")
}
}
}
}
This pattern preserves the PartialFunction nature of the piece of code. I find this useful since I am quite a fan of the collect/collectFirst methods, which take a partial function as a parameter and typically does not leave room for precreating a set of extractors.