I'm around trying to understand how "Menu.param" works with 2 params
I'm using this code as an example:
https://github.com/dpp/starting_point/blob/menu_fun/src/main/scala/code/snippet/AThread.scala
But I can not make it work
object APost {
// Create a menu for /user/santo
val menu = Menu.param[( User, Posts )]("ParamId1", "ParamId2",
{
case User(p1) :: Posts(p2) :: Nil =>
Full( (p1, p2) )
case _ =>
Empty
},
params => List(params._1.id.toString,params._2.id.toString)) / * / * >> LocGroup("UserPost")
lazy val loc = menu.toLoc
def render = "*" #> loc.currentValue.map(_.docId)
}
When compiling sends me the following error:
[error] /menu2params/src/main/scala/code/snippet/APost.scala:23: constructor cannot be instantiated to expected type;
[error] found : scala.collection.immutable.::[B]
[error] required: String
[error] case ParamId1(p1) :: ParamId1(p2) :: Nil =>
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
Someone who can help me please
Here is the copy of my project:
https://github.com/hectorgool/menu2params/blob/master/src/main/scala/code/snippet/APost.scala
Thanks for your attention
Menu.param is for use with a single parameter, hence the error requiring a String instead of a List. Menu.params allows you to specify multiple parameters in a list. Making that change to your code should resolve the issue.
Related
Hi I am trying to execute a for comprehension like
(for {
player <- playerRepository.findById(playerId) // findById returns EitherT[Future, String, Player]
teamOpt <- teamRepository.findByPlayer(playerId) // findByPlayer returns EitherT[Future, String, Option[Team]]
playedMatches <- teamOpt.map(team => playedMatchesRepository.findByTeamId(team.id)) // findByTeamId returns EitherT[Future, String, Seq[PlayedMatches]]
} yield (
player,
teamOpt,
playedMatches
)).fold(
error => {
logger.error(s"all error: $error")
Left(error)
},
tuple => {
logger.debug(s"get success -> $tuple")
Right(playerDetailResponse(tuple._1, tuple._2, tuple._3))
}
)
I can not get a corret structure for
playedMatches <- teamOpt.map(team => playedMatchesRepository.findByTeamId(team.id))
I am getting the following error when I compile the project
[error] /Users/agusgambina/code/soccer/app/services/impl/PlayerServiceImpl.scala:28:17: type mismatch;
[error] found : Option[(models.Player, Option[models.Team], cats.data.EitherT[scala.concurrent.Future,String,Seq[models.PlayedMatches]])]
[error] required: cats.data.EitherT[scala.concurrent.Future,?,?]
[error] playedMatches <- teamOpt.map(team => playedMatchesRepository.findByTeamId(team.id))
[error] ^
[error] one error found
I tried to wrap
playedMatches <- teamOpt.map(team => playedMatchesRepository.findByTeamId(team.id)) // findByTeamId returns EitherT[Future, String, Seq[PlayedMatches]]
in here, you are getting an Option[EitherT[Future, String, Seq[PlayedMatches]]] which doesn't compose with the EitherT[Future, String, ???] you are using as Monad for the for comprehension.
one option you have is to actually use a fold on teamOpt.
teamOpt.fold(EitherT(Future.successful(Left("Team not Found"): Either[String, Team]))){ team => playedMatchesRepository.findByTeamId(team.id) }
This way you unwrap the Option with the error case if is empty or the success case if non-empty. (create a function that takes the teamOPt as parameter and the for-comprehension will look much better)
Hope it helps
update
In case of the empty case be successful, and be happy returning an empty sequence:
teamOpt.fold(
EitherT(Future.successful(Right(Seq()): Either[String, Seq[PlayedMatches]))
){ team =>
playedMatchesRepository.findByTeamId(team.id)
}
I'm trying to implement an sbt task which collects all the source directories of projects specified using dependsOn method of a project. I end up with this piece of code:
def sourcesOfDependencies(p: Project): Def.Initialize[Task[Seq[File]]] =
Def.taskDyn {
p.dependencies
.map(dep => (sourceDirectory in dep.project).toTask.map(Seq(_)))
.reduce((t1, t2) =>
t1.flatMap(s1 => t2.map(s2 => s1 ++ s2).taskValue)
)
}
sources := Def.taskDyn { sourcesOfDependencies(myProject) }.value
As for me it should work but it fails to compile:
[error] /home/visa/src/Playtech-BIT/project/SparkDeployment.scala:57:32: The evaluation of `map` inside an anonymous function is prohibited.
[error]
[error] Problem: Task invocations inside anonymous functions are evaluated independently of whether the anonymous function is invoked or not.
[error]
[error] Solution:
[error] 1. Make `map` evaluation explicit outside of the function body if you don't care about its evaluation.
[error] 2. Use a dynamic task to evaluate `map` and pass that value as a parameter to an anonymous function.
[error]
[error] t1.flatMap(s1 => t2.map(s2 => s1 ++ s2).taskValue)
[error] ^
[error] /home/visa/src/Playtech-BIT/project/SparkDeployment.scala:57:26: Illegal dynamic reference: t2
[error] t1.flatMap(s1 => t2.map(s2 => s1 ++ s2).taskValue)
[error] ^
[error] /home/visa/src/Playtech-BIT/project/SparkDeployment.scala:57:39: Illegal dynamic reference: s1
[error] t1.flatMap(s1 => t2.map(s2 => s1 ++ s2).taskValue)
Could anyone advise on how to apply the proposed solution? Or maybe there is a simpler way to achieve my goal?
I've been struggling with a similar problem but finally found an answer.
So, what you may do is to define a dynamic task performing your complex computation, like
val buildMaping: Def.Initialize[Task[Seq[Def.Initialize[(ProjectRef, Seq[Seq[File]])]]]] = {
Def.taskDyn {
val refs = loadedBuild.value.allProjectRefs
val tt = refs.map(_._1).map {
ref =>
sourceDirectories.all(ScopeFilter(inProjects(ref)))
.zipWith(Def.setting(ref)) { case (a, b) => b -> a }
}
Def.task {
tt
}
}
}
So, this buildMapping allows you to get a map of project references to their source directories.
then invoke your task this way:
Def.task {
val sd = settingsData.in(Global).value
val mapping = buildMaping.value.map(_.evaluate(sd)).toMap
val allProjectRefs = loadedBuild.value.allProjectRefs.map(_._1)
//... now you may iterate over each project,
// get deps and use the mapping to resolve your values
}
I took this Scala quasiquote example from the book "Programming Scala" (2nd Edition)
I am getting this error: https://issues.scala-lang.org/browse/SI-9711
The type inference says "Trees#Tree", but the type inference is off.
import scala.reflect.api.Trees // For Trees#Tree (TreeNode)
import scala.reflect.macros.blackbox._
import scala.reflect.runtime.universe._ // To use Scala runtime reflection
/**
* Represents a macro invariant which is checked over the corresponding statements.
* Example:
* '''
* var mustBeHello = "Hello"
* invariant.execute(mustBeHello.equals("Hello")) {
* mustBeHello = "Goodbye"
* }
* // Throws invariant.InvariantFailure
* '''
*/
object invariant {
case class InvariantFailure(message: String) extends RuntimeException(message)
type SyntaxTree = scala.reflect.runtime.universe.Tree
type TreeNode = Trees#Tree // a syntax tree node that is in and of itself a tree
// These two methods are the same, but one is a function call and the other is a macro function call
def execute[RetType] (myPredicate: => Boolean)(block: => RetType): RetType = macro executeMacro
def executeMacro(context: Context)(myPredicate: SyntaxTree)(block: SyntaxTree) = {
val predicateString: String = showCode(myPredicate) // turn this predicate into a String
val q"..$statements" = block // make the block into a sequence of statements
val myStatements: Seq[TreeNode] = statements // the statements are a sequence of SyntaxTreeNodes, each node a little Tree
val invariantStatements = statements.flatMap { statement =>
// Error here:
val statementString: String = showCode(statement) /* Type mismatch, expected Tree, actual Trees#Tree */
val message: String =
s"FAILURE! $predicateString == false, for statement: " + statementString
val tif: SyntaxTree =
q"throw new metaprogramming.invariant.InvariantFailure($message)"
val predicate2: SyntaxTree =
q"if (false == $myPredicate) $tif"
val toReturn: List[SyntaxTree] =
List(q"{ val temp = $myStatements; $predicate2; temp };")
toReturn
}
val tif: SyntaxTree =
q"throw new metaprogramming.invariant.InvariantFailure($predicateString)"
val predicate: SyntaxTree =
q"if (false == $predicate) $tif"
val toReturn: SyntaxTree =
q"$predicate; ..$invariantStatements"
toReturn
}
}
^ The documentation should be self explanatory. The type inference says Tree#Tree, but adding ":Tree#Tree" to the example code kills compilation with error:
[info] Compiling 2 Scala sources to /home/johnreed/sbtProjects/scala-trace-debug/target/scala-2.11/test-classes...
[error] /home/johnreed/sbtProjects/scala-trace-debug/src/test/scala/mataprogramming/invariant2.scala:30: type mismatch;
[error] found : TreeNode
error scala.reflect.api.Trees#Tree
[error] required: context.universe.Tree
[error] val exceptionMessage = s"FAILURE! $predicateAsString == false, for statement: " + showCode(statement)
I'm getting "Type mismatch, expected Tree, actual Trees#Tree" in IntelliJ
[info] Compiling 2 Scala sources to /home/johnreed/sbtProjects/scala-trace-debug/target/scala-2.11/test-classes...
[error] /home/johnreed/sbtProjects/scala-trace-debug/src/test/scala/mataprogramming/invariant2.scala:30: type mismatch;
[error] found : TreeNode
error scala.reflect.api.Trees#Tree
[error] required: context.universe.Tree
[error] val exceptionMessage = s"FAILURE! $predicateAsString == false, for statement: " + showCode(statement)
There's something really funky with the types. Either IntelliJ is messing up the types or the notion escapes me.
The "normal" way to discover an inferred type is one of:
ask the REPL using :type
assign to a bad type and observe the error message
call a function that displays a TypeTag of the thing
For example,
[error] /home/apm/clones/prog-scala-2nd-ed-code-examples/src/main/scala/progscala2/metaprogramming/invariant2.scala:25: type mismatch;
[error] found : List[context.universe.Tree]
[error] required: Int
[error] val foo: Int = statements
[error] ^
This shows that the Tree is path-dependent in the context universe.
You can't feed it just any old tree.
Similar issue at this question.
My feeble Scala skills have me baffled about the right way to do something. The code below compiles (and works) only when I include the t match {... line. If I eliminate that line and of course, the diagnostic println on the preceding line, I get the compile time error as shown. Apparently the compiler regards the return of the fold as Unit (surprise to me). That might be reasonable, but I don't understand it. Would someone please enlighten me about a better way to code this, and perhaps give me more insight?
[error] /home/bill/activator/cherry/app/controllers/Application.scala:34: type mismatch;
[error] found : Unit
[error] required: play.api.mvc.Result
[error] }
[error] ^
Source:
def ptweets = Action { implicit request =>
import play.api.data._
val rqForm = Form(Forms.mapping(
"k" -> Forms.number,
"who" -> Forms.text,
"what" -> Forms.text)(TweetInquiry.apply)(TweetInquiry.unapply))
val t = rqForm.bindFromRequest.fold(
formWithErrors => BadRequest("That's not good"),
rq => Ok((views.html.properForm("POST tweets TBD.")(Html("<em>Blah</em>"))))
) // expect a play.api.mvc.Result
println(t.getClass.getName) // this confirms it in both run-time cases
t match { case v:Result => v } // yet this is required for compile
}
as m-z said in the comments, change
val t = rqForm.bindFromRequest.fold(
formWithErrors => BadRequest("That's not good"),
rq => Ok((views.html.properForm("POST tweets TBD.")(Html("<em>Blah</em>"))))
) // expect a play.api.mvc.Result
println(t.getClass.getName) // this confirms it in both run-time cases
t match { case v:Result => v } // yet this is required for compile
to just:
rqForm.bindFromRequest.fold(
formWithErrors => BadRequest("That's not good"),
rq => Ok((views.html.properForm("POST tweets TBD.")(Html("<em>Blah</em>"))))
)
The fold is evaluating to a Result, but in the code you posted, you're assigning that Result to the value t. Thus, instead of the Action block evaluating to the result of the fold, it's evaluating to an assignment (which is Unit, see here).
I have a test along these lines:
httpClient.post(anyString, anyString) returns (first, second)
//do my thing
there were two(httpClient).post(anyString, anyString)
This works fine, but I want to verify that the first call passes a different body than the second call. The body is rather big and I don't want to do precise matching on a strict example. I've tried this:
there was one(httpClientMock).postMessage(anyString, argThat(contain("FOO"))
there was one(httpClientMock).postMessage(anyString, argThat(contain("FOO"))
That makes Mockito complain:
InvalidUseOfMatchersException:
[error] Invalid use of argument matchers!
[error] 2 matchers expected, 3 recorded:
I've also tried:
there was one(httpClientMock).postMessage(argThat(contain("foo")), argThat(contain("FOO")))
there was one(httpClientMock).postMessage(argThat(contain("foo")), argThat(contain("FOO")))
which results in:
Wanted 1 time:
[error] -> ...
[error] But was 2 times. Undesired invocation: ...
It seems to me that something like this should be possible, but I can't seem to figure it out. Insights?
I think that this is more of a problem with Mockito to begin with. When you're using Mockito with specs2 and you're in doubt, always drop down to the direct Mockito API:
// simplified httpClient with only one parameter
val httpClient = mock[HttpClient]
httpClient.post(anyString) returns ""
httpClient.post("s1")
httpClient.post("s2")
// forget specs2
// there was two(httpClient).post(anyString)
org.mockito.Mockito.verify(httpClient, org.mockito.Mockito.times(1)).post("s1")
// I guess that you don't want this to pass but it does
org.mockito.Mockito.verify(httpClient, org.mockito.Mockito.times(1)).post("s1")
One possible way around this is to define a matcher that will check the successive values of an argument:
there was two(httpClient).post(consecutiveValues(===("s1"), ===("s2")))
And the consecutiveValues matcher is defined as such:
import matcher._
import MatcherImplicits._
// return a matcher that will check a value against a different
// `expected` matcher each time it is invoked
def consecutiveValues[T](expected: Matcher[T]*): Matcher[T] = {
// count the number of tested values
var i = -1
// store the results
var results: Seq[(Int, MatchResult[T])] = Seq()
def result(t: T) = {
i += 1
// with Mockito values are tested twice
// the first time we return the result (but also store it)
// the second time we return the computed result
if (i < expected.size) {
val mr = expected(i).apply(Expectable(t))
results = results :+ (i, mr)
mr
} else results(i - expected.size)._2
}
// return a function that is translated to a specs2 matcher
// thanks to implicits
// display the failing messages if there are any
(t: T) => (result(t).isSuccess,
results.filterNot(_._2.isSuccess).map { case (n, mr) =>
s"value $n is incorrect: ${mr.message}" }.mkString(", "))
}
You can test the code above. The failure messages are not the best but do the trick. In this situation:
httpClient.post("s1")
httpClient.post("s2")
there was two(httpClient).post(consecutiveValues(===("s1"), ===("s3")))
You will see:
[error] x test
[error] The mock was not called as expected:
[error] httpClient.post(
[error] value 1 is incorrect: 's2' is not equal to 's3'
[error] );
[error] Wanted 2 times:
[error] -> at ...
[error] But was 1 time:
[error] -> at ...