Play! + Scala: Split string by commnas then Foreach loop - scala

I have a long string similar to this:
"tag1, tag2, tag3, tag4"
Now in my play template I would like to create a foreach loop like this:
#posts.foreach { post =>
#for(tag <- #post.tags.split(",")) {
<span>#tag</span>
}
}
With this, I'm getting this error: ')' expected but '}' found.
I switched ) for a } & it just throws back more errors.
How would I do this in Play! using Scala?
Thx in advance
With the help of #Xyzk, here's the answer: stackoverflow.com/questions/13860227/split-string-assignment

Posting this because the answer marked correct isn't necessarily true, as pointed out in my comment. There are only two things wrong with the original code. One, the foreach returns Unit, so it has no output. The code should actually run, but nothing would get printed to the page. Two, you don't need the magic # symbol within #for(...).
This will work:
#for(post <- posts)
#for(tag <- post.tags.split(",")) {
<span>#tag</span>
}
}
There is in fact nothing wrong with using other functions in play templates.

This should be the problem
#for(tag <- post.tags.split(",")) {
<span>#tag</span>
}

Related

Filtering a collection of IO's: List[IO[Page]] scala

I am refactoring a scala http4s application to remove some pesky side effects causing my app to block. I'm replacing .unsafeRunSync with cats.effect.IO. The problem is as follows:
I have 2 lists: alreadyAccessible: IO[List[Page]] and pages: List[Page]
I need to filter out the pages that are not contained in alreadyAccessible.
Then map over the resulting list to "grant Access" in the database to these pages. (e.g. call another method that hits the database and returns an IO[Page].
val addable: List[Page] = pages.filter(p => !alreadyAccessible.contains(p))
val added: List[Page] = addable.map((p: Page) => {
pageModel.grantAccess(roleLst.head.id, p.id) match {
case Right(p) => p
}
})
This is close to what I want; However, it does not work because filter requires a function that returns a Boolean but alreadyAccessible is of type IO[List[Page]] which precludes you from removing anything from the IO monad. I understand you can't remove data from the IO so maybe transform it:
val added: List[IO[Page]] = for(page <- pages) {
val granted = alreadyAccessible.flatMap((aa: List[Page]) => {
if (!aa.contains(page))
pageModel.grantAccess(roleLst.head.id, page.id) match { case Right(p) => p }
else null
})
} yield granted
this unfortunately does not work with the following error:
Error:(62, 7) ';' expected but 'yield' found.
} yield granted
I think because I am somehow mistreating the for comprehension syntax, I just don't understand why I cannot do what I'm doing.
I know there must be a straight forward solution to such a problem, so any input or advice is greatly appreciates. Thank you for your time in reading this!
granted is going to be an IO[List[Page]]. There's no particular point in having IO inside anything else unless you truly are going to treat the actions like values and reorder them/filter them etc.
val granted: IO[List[Page]] = for {
How do you compute it? Well, the first step is to execute alreadyAccessible to get the actual list. In fact, alreadyAccessible is misnamed. It is not the list of accessible pages; it is an action that gets the list of accessible pages. I would recommend you rename it getAlreadyAccessible.
alreadyAccessible <- getAlreadyAccessible
Then you filter pages with it
val required = pages.filterNot(alreadyAccessible.contains)
Now, I cannot decipher what you're doing to these pages. I'm just going to assume you have some kind of function grantAccess: Page => IO[Page]. If you map this function over required, you will get a List[IO[Page]], which is not desirable. Instead, we should traverse with grantAccess, which will produce a IO[List[Page]] that executes each IO[Page] and then assembles all the results into a List[Page].
granted <- required.traverse(grantAccess)
And we're done
} yield granted

Babel: replaceWithSourceString giving Unexpected token (1:1)

I am trying to replace dynamically "import" statements.
Here is an example that checks if the import ends with a Plus.
module.exports = function(babel) {
return {
visitor: {
ImportDeclaration: function(path, state) {
// import abc from "./logic/+"
if( ! path.node.source.value.endsWith("/+"))
return;
path.replaceWithSourceString('import all from "./logic/all"')
}
}
}
}
This gives an error of
SyntaxError: src/boom.js: Unexpected token (1:1) - make sure this is an expression.
> 1 | (import all from "./logic/all")
The problem is that replaceWithSourceString is wrapping the string in rounded braces.
If I change the replaceWithSourceString to
path.replaceWithSourceString('console.log("Hi")')
and this works.. ¯_(ツ)_/¯
Any and all help you be great
replaceWithSourceString should really be avoided, because it is just not a very good API, as you are seeing. The recommended approach for creating ASTs to insert into the script is to use template. Assuming this is for Babel 7.x, you can do
const importNode = babel.template.statement.ast`import all from "./logic/all"`;
path.replaceWith(importNode);

Should 'require' go inside or outside of the Future?

How do I replace my first conditional with the require function in the context of a Future? Should I wrap the entire inRange method in a Future, and if I do that, how do I handle the last Future so that it doesn't return a Future[Future[List[UserId]], or is there a better way?
I have a block of code that looks something like this:
class RetrieveHomeownersDefault(depA: DependencyA, depB: DependencyB) extends RetrieveHomeowners {
def inRange(range: GpsRange): Future[List[UserId]] = {
// I would like to replace this conditional with `require(count >= 0, "The offset…`
if (count < 0) {
Future.failed(new IllegalArgumentException("The offset must be a positive integer.")
} else {
val retrieveUsers: Future[List[UserId]] = depA.inRange(range)
for (
userIds <- retrieveUsers
homes <- depB.homesForUsers(userIds)
) yield FilterUsers.withoutHomes(userIds, homes)
}
}
}
I started using the require function in other areas of my code, but when I tried to use it in the context of Futures I ran into some hiccups.
class RetrieveHomeownersDefault(depA: DependencyA, depB: DependencyB) extends RetrieveHomeowners {
// Wrapped the entire method with Future, but is that the correct approach?
def inRange(range: GpsRange): Future[List[UserId]] = Future {
require(count >= 0, "The offset must be a positive integer.")
val retrieveUsers: Future[List[UserId]] = depA.inRange(range)
// Now I get Future[Future[List[UserId]]] error in the compiler.
for (
userIds <- retrieveUsers
homes <- depB.homesForUsers(userIds)
) yield FilterUsers.withoutHomes(userIds, homes)
}
}
Any tips, feedback, or suggestions would be greatly appreciated. I'm just getting started with Futures and still having a tough time wrapping my head around many concepts.
Thanks a bunch!
Just remove the outer Future {...} wrapper. It's not necessary. There's no good reason for the require call to go inside the Future. It's actually better outside since then it will report immediately (in the same thread) to the caller that the argument is invalid.
By the way, the original code is wrong too. The Future.failed(...) is created but not returned. So essentially it didn't do anything.

How to stop the execution or throw an error in scala play framework

I'm developing a scala application with play framework, but i got something strange.
i can't stop the execution nor throwing an error in order to send a response for the client, it always continue the code and it always returning okay, however i made a dummy function that it should return a bad request but unfortunately it is returning OK here is what i wrote. any help will be appreciated
def foo(locale: String, orderId: Int) = Action { implicit request => {
val x=4+7;
if(x==11){
BadRequest(JsonHelper.convertToJson("Bad bad it is really bad "))
}
OK(JsonHelper.convertToJson("Well Done"))
}
}
the above code returning OK Well done.
To make your code return a BadRequest, add an else:
def foo(locale: String, orderId: Int) = Action { implicit request => {
val x = 4 + 7;
if (x == 11)
BadRequest(JsonHelper.convertToJson("Bad bad it is really bad "))
else // <---
OK(JsonHelper.convertToJson("Well Done"))
}}
Your problem is your if without curly braces.
refered to this link :https://docs.scala-lang.org/style/control-structures.html#curly-braces
if - Omit braces if you have an else clause. Otherwise, surround the
contents with curly braces even if the contents are only a single
line.
so you can just suuround the BadRequest with curly braces or add an else statement between your Bad and OK instruction. Be careful, don't forget the indentation !
edit 20/12/2017 >> un scala the last instruction is implicitly returned. Your last instruction is OK, so it returns OK.
Add explicit return statement in your if block or add an else statement.

Perform more than one operation in scala's foreach?

Let's say I have this ListBuffer that I am filling in a scala foreach like the following:
Tokens.foreach(t => tokens+=new Token(t._1.toString()))
i am wondering whether it is possible to perform another operation at the same time for-example adding to a string something like:
Tokens.foreach(t => tokens+=new Token(t._1.toString()), posTagString+=t._2.toString())
the 2nd example results in a "too many arguments (2) for method foreach" error. Is there a way to do this or shall I just stick too the form of:
for(x<-Tokens){
}
try this? :
Tokens.foreach{t =>
tokens+=new Token(t._1.toString())
posTagString+=t._2.toString()
}
You can achieve your requirement by using map too
Tokens.map(t => {
tokens += new Token(t._1.toString())
posTagString += t._2.toString()
})