Play QueryStringBindable with Gradle - scala

I am trying to implement a custom QueryStringBindable and use it in a Play project built with Gradle, but cannot figure out what is the SBT equivalent of routesImport.
There is this discussion:
gradle :compilePlayBinaryPlayRoutes is not generating all imports
but it appears to no longer work with Play 2.8. I tried
play {
platform {
playVersion = 2.8.17
scalaVersion = 2.12.17
}
// additionalImports += ...
// and
.. routesImport += ...
}
but end up with Could not get unknown property 'routesImport' for extension 'play' of type org.gradle.playframework.extensions.PlayExtension.
Did something change in Play 2.8 or am I missing something?

Related

How to include a Scala compiler plugin from a local path?

I'm developing a Scala compiler plugin, and right now I have to go to the plugin project, run sbt publishLocal, come back to my project, and run sbt clean compile.
This is because I'm using addCompilerPlugin(...) in my build.sbt
I wonder if there's a way to refer the compiler plugin's local path, so that I can simply run sbt compile.
Thank you.
Here's how we can achieve it:
scalacOptions in Compile ++= {
val jar = (Keys.`package` in (plugin, Compile)).value
System.setProperty("sbt.paths.plugin.jar", jar.getAbsolutePath)
val addPlugin = "-Xplugin:" + jar.getAbsolutePath
// Thanks Jason for this cool idea (taken from https://github.com/retronym/boxer)
// add plugin timestamp to compiler options to trigger recompile of
// main after editing the plugin. (Otherwise a 'clean' is needed in the current project)
val dummy = "-Jdummy=" + jar.lastModified
Seq(addPlugin, dummy)
}
Here's an example: https://github.com/GIVESocialMovement/scala-named-argument-compiler-plugin/blob/master/test-project/build.sbt#L26
This above runs package on the plugin project, gets its jar, and adds the plugin through scalacOptions on the current project.
Thanks this redditor for answering my question: https://www.reddit.com/r/scala/comments/aq2bt6/just_made_a_compiler_plugin_to_enforce_named/

ScalaTest v3: why require to implement convertToLegacyEqualizer

Using ScalaTest 3.0.0
Environment: Scala 2.11.8, sbt 0.13.5, IntelliJ 14.1.4
build.sbt has only
// NOTE: not using org.scalactic
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.0" % "test"
The test below passed. However, IntelliJ marks a squiggly red line below MyMiniTest with the warning message:
Class 'MyMiniTest ' must either be declared abstract or implement
abstract member 'convertToLegacyEqualizer[T](left: T):
TripleEqualsSupport.this.LegacyEqualizer[T]' in
'org.scalactic.TripleEqualsSupport'
import org.scalatest.FeatureSpec
class MyMiniTest extends FeatureSpec {
scenario("A simple test") {
val a = 12
assert(a * 3 == 36)
}
}
What is the reason of this warning and what is the recommended solution to fix it?
I had the same problem on IntelliJ just follow this steps to invalidate cache/restart. This will solve the problem.
In my case it was a transitive dependency (don't know how a test library could appear as such) of a different version clashing with the dependency defined in my project. SBT knows how to deal with most of these cases, IntelliJ doesn't seem to know. Note that invalidating the cache and restarting IntelliJ wouldn't help in this case.
To be sure it's your case, check the following: File -> Project Structure -> [Project Settings - Libraries]. Look for org.scalatest:* and you will probably find two libraries, like this:
Then remove the unnecessary one by selecting it and pressing - at the top of the panel. That's it, IntelliJ will be happy now.
A cleaner solution would be to exclude the unnecessary library from your dependencies, e.g.:
ExclusionRule("org.scalatest", "scalatest_2.11-2.2.4")
IntelliJ will show the library among the project's dependencies, but will know that it should be ingored.
Please check all you dependencies and check if any of those dependencies is downloading org.scalatest.* . If the version of org.scalatest.* you have defined is different from the one getting downloaded due to other defined dependencies, this issue occurs.
I was using org.mockito%mockito-scala whose pom defined that scalatest 3.0.8 was provided. But the scalatest I had defined was 2.2.5. By changing the version of scalatest to 3.0.8, I was able to resolve this issue.
Hope this helps.

Add scala-async to library dependency but still get "not found: value async" error

I have a simple function using "async":
def delay(t: Duration): Future[Unit] = async {
blocking {
Thread.sleep(t.toMillis)
}
}
I've added the following jar to my project through Project Settings / Libraries (from Maven) :
SBT: org.scala-lang.modules:scala-async_2.11:0.9.2:jar
and also found this dependency already in the "build.sbt":
projectDetailsMap := {
val depsNode = Seq(
.......
"org.scala-lang.modules" %% "scala-async" % "0.9.2"
)}
But when I rebuilt the project, even restarted Intellij and rebuilt again, I still got this error:
Error:(65, 44) not found: value async
def delay(t: Duration): Future[Unit] = async {
^
Can someone tell me what might be wrong? Thanks a lot!
I'm using scala "2.11.5" on Mac
Well, I reinstalled my Intellij IDEA, changed the default JDK 1.6 in "idea.properties" to my current JDK 1.8, and also imported my project again as an SBT project. Problem solved. It might be caused by some conflicts in my environment.

Importing in Scala - How to add a jar to the classpath permanently

So I'm having trouble importing a package in scala. I downloaded the package, breeze, from github, because I wanted to sample from probability distributions.
I'm used to Python, where I can just download a package, include it in the path, and then import it in the code. So I'm very new to the idea of using a separate "build tool" to use 3rd party packages.
So I downloaded the "breeze" source code from github, installed sbt, and then within the source code for breeze, I ran sbt, and then I used the "assembly" command to get a .jar for breeze.
If I want to use the scala interpreter, I can import the package just fine with
scala -cp breeze-master/target/scala-2.11/breeze-parent-assembly-0.8.jar
The problem is that I want to use this package in a separate piece of code that I'm writing in a file called Chromosome.scala. And when I try to import the package (as seen below), I get an error:
error: not found: object breeze
Here's my code:
// Chromosome.scala
import breeze.stats.distributions._
class Chromosome(s:Int, bitstring:Array[Boolean]) {
val size:Int = s;
val dna:Array[Boolean] = bitstring;
var fitness:Int = 0;
def mutate(prob:Float):Unit = {
// This method will randomly "mutate" the dna sequence by flipping a bit.
// Any individual bit may be flipped with probability 'pm', usually small.
val pm:Float = prob;
// The variable bern is an instance of a Bernoulli random variable,
// whose probability parameter is equal to 'pm'.
var bern = new Bernoulli(pm);
//Loop through the 'dna' array and flip each bit with probability pm.
for (i <- 0 to (size - 1)) {
var flip = bern.draw();
if (flip) {
dna(i) = !(dna(i));
}
}
}
“A script?” What is this and what is its connection to your SBT project? Scala scripts include their own launch command for the Scala interpreter / compiler ( / REPL…). If you want to access things beyond the standard library, you'll have to inclulde them there. Alternately, you can use the SBT Start Script plug-in to produce a launcher script that will include the project dependencies. It will only work locally, though you can write some text processing and other shell scripting to produce a portable launch bundle.
It looks like there's some understandable confusion about what sbt is supposed to do for you.
First off, you generally don't need to download a package from github and build it from source. In the rare cases that you do (such as when you require features that have not made it into a release of the library), sbt can handle the grunt work.
Instead, you tell sbt a little about the project you're building (including what its dependencies are), and sbt will download them, compile your code, and set up the runtime classpath for the scala interpreter (amongst myriad other build-related tasks).
Just follow the directions on the breeze wiki. Specifically, create a build.sbt file in your project's root folder and copy this into it:
libraryDependencies ++= Seq(
// other dependencies here
"org.scalanlp" % "breeze_2.10" % "0.7",
// native libraries are not included by default. add this if you want them (as of 0.7)
// native libraries greatly improve performance, but increase jar sizes.
"org.scalanlp" % "breeze-natives_2.10" % "0.7",
)
resolvers ++= Seq(
// other resolvers here
// if you want to use snapshot builds (currently 0.8-SNAPSHOT), use this.
"Sonatype Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/",
"Sonatype Releases" at "https://oss.sonatype.org/content/repositories/releases/"
)
// Scala 2.9.2 is still supported for 0.2.1, but is dropped afterwards.
// Don't use an earlier version of 2.10, you will probably get weird compiler crashes.
scalaVersion := "2.10.3"
Put your source into the appropriate folder (by default, src/main/scala) and run sbt console. This command will download the dependencies, compile your code, and launch the Scala interpreter. At this point you should be able to interact with your class.

SBT: Plugin dependencies and project classpath

How does one add a external dependency to a SBT plugin and make it available on both the project and plugin classpath ?:
Specifically I have a simple plugin that should run our TestNG test suites and do some post processing. Here is a simplified version:
import sbt._
import java.util.ArrayList
import Keys._
import org.testng._
object RunTestSuitesPlugin extends Plugin {
lazy val runTestSuites = TaskKey[Unit]("run-test-suites", "runs TestNG test suites")
lazy val testSuites = SettingKey[Seq[String]]("test-suites", "list of test suites to run")
class JavaListWrapper[T](val seq: Seq[T]) {
def toJavaList = seq.foldLeft(new java.util.ArrayList[T](seq.size)) { (al, e) => al.add(e); al }
}
implicit def listToJavaList[T](l: Seq[T]) = new JavaListWrapper(l)
def runTestSuitesTask = runTestSuites <<= (target, streams, testSuites) map {
(targetDirectory, taskStream, suites) =>
import taskStream.log
log.info("running test suites: " + suites)
runSuites(suites)
}
private def runSuites(testSuites: Seq[String]) = {
var tester = new TestNG
tester.setTestSuites(testSuites.toJavaList)
tester.run()
}
def testSuiteSettings = {
inConfig(Compile)(Seq(
runTestSuitesTask,
testSuites := Seq("testsuites/mysuite.xml"),
libraryDependencies += "org.testng" % "testng" % "5.14"))
}
}
The problem is that when I add this plugin to a project and run it with run-test-suites then it fails with java.lang.NoClassDefFoundError: org/testng/TestNG even though show full-classpath shows that testng.jar is on the classpath.
So somehow the classpath used when executing the plugin differs from the one in my project, so how do I make a plugin dependency appear in both places ?
I'll try an answer, but I'm not very familiar with the inner details of sbt.
Normally, the path for the build system (as opposed to your program) is under project, as explained here. That would typically be in a project/plugins.sbt. Sounds right, as there is no reason that the application you develop should be concerned by what libraries your build system uses, nor the other way round.
When your plugin run the application code, that may not be so simple and there could well be classpath/classloader issues. I'm not sure that it will work. Normally, your plugin should implement a testing Framework rather than define its own task. Documentation of testing for sbt is limited.
A testing framework should implement org.scalatools.testing.Framework, in test-interface. Your build will take it into account after you add
testFrameworks += new TestFramework("full.class.name")
When you run the normal test command, it let every framework recognize the test classes it deals with (two criteria available: extending some base class or having some annotation) and run them. The framework run in the build, it is given a class loader to access the application code.
You may have a look at the framework implementation for junit (shipped with sbt). Also there is a TestNG implementation. I don't know it, according to its doc, it is a little bit unorthodox, hopefully it will work for you.
The error was fixed by adding TestNG directly to unmanagedJars in Compile in the project that uses the plugin.
I have not found any resources explaining the structure of the SBT class path during plugin execution so any attempt at explaining why this step is necessary will be greatly appreciated.