How to get the package of methods or objects in Scala?
For example
import scala.math._
round().getClass // errors
Is there a way to get the desired output: "scala.math.round"? So that I can be sure of round() method doesn't come from any other package I've imported.
PS. Without using Intellij IDE. The IDE shows you this info, hence there has to be a function that IDE calls to get this info.
EDIT:
For example, running these commands in scala shell
With Scala reflection (libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value in build.sbt) you can do
import scala.math._
import scala.reflect.runtime.universe._
object App {
def main(args: Array[String]): Unit = {
println(
showRaw(reify {
round(???)
})
)
}
}
Output at runtime will be
Expr(Apply(Select(Ident(scala.math.package), TermName("round")), List(Select(Ident(scala.Predef), TermName("$qmark$qmark$qmark")))))
Or you can add scalacOptions in Compile ++= Seq("-Xprint-types", "-Xprint:typer") to build.sbt.
Then compilation of
package pckg
import scala.math._
object App {
round(???)
}
will produce (at compile time)
Warning:scalac: package pckg{pckg.type} {
import scala.math._;
object App extends scala.AnyRef {
def <init>(): pckg.App.type = {
App.super{pckg.App.type}.<init>{()Object}(){Object};
(){Unit}
}{Unit};
scala.math.`package`.round{(x: Long)Long}(scala.Predef.???{Nothing}){Long}
}
}
Related
I am unable to use macros in scala 2.13.1.
I keep getting the following error:
object blackbox is not a member of package scala.reflect.macros
This obviously isn't true, because scala 2.13.1 actually has these blackbox.
What am I not doing right?
Hello.scala
package example.core
import example.macros.MacroLibrary
object Hello extends App {
MacroLibrary.hello()
}
MacroLibrary.scala
package example.macros
// This line throws errors
import scala.reflect.macros.blackbox.Context
import scala.reflect.macros.blackbox
object MacroLibrary {
def hello_impl(c: blackbox.Context)(): c.Expr[Unit] = {
import c.universe._
c.Expr(q"""println("Hello World")""")
}
def hello(): Unit = macro hello_impl
}
build.sbt
scalaVersion := "2.13.1"
Error
object blackbox is not a member of package scala.reflect.macros
They are not in the standard library, but in separate scala-reflect, which needs to be added as a dependency in build.sbt:
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value
You can see that from Context documentation having "Scala Reflection Library" in the top left.
Play 2.4 app, using dependency injection for service classes.
I found that Specs2 chokes when a service class being tested has more than one injected dependency. It fails with "Can't find a constructor for class ..."
$ test-only services.ReportServiceSpec
[error] Can't find a constructor for class services.ReportService
[error] Error: Total 1, Failed 0, Errors 1, Passed 0
[error] Error during tests:
[error] services.ReportServiceSpec
[error] (test:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 2 s, completed Dec 8, 2015 5:24:34 PM
Production code, stripped to bare minimum to reproduce this problem:
package services
import javax.inject.Inject
class ReportService #Inject()(userService: UserService, supportService: SupportService) {
// ...
}
class UserService {
// ...
}
class SupportService {
// ...
}
Test code:
package services
import javax.inject.Inject
import org.specs2.mutable.Specification
class ReportServiceSpec #Inject()(service: ReportService) extends Specification {
"ReportService" should {
"Work" in {
1 mustEqual 1
}
}
}
If I remove either UserService or SupportService dependency from ReportService, the test works. But obviously the dependencies are in the production code for a reason. Question is, how do I make this test work?
Edit: When trying to run the test inside IntelliJ IDEA, the same thing fails, but with different messages: "Test framework quit unexpectedly", "This looks like a specs2 exception..."; see full output with stacktrace. I opened a Specs2 issue as instructed in the output, though I have no idea if the problem is in Play or Specs2 or somewhere else.
My library dependencies below. (I tried specifying Specs2 version explicitly, but that didn't help. Looks like I need specs2 % Test as is, for Play's test classes like WithApplication to work.)
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
libraryDependencies ++= Seq(
specs2 % Test,
jdbc,
evolutions,
filters,
"com.typesafe.play" %% "anorm" % "2.4.0",
"org.postgresql" % "postgresql" % "9.4-1205-jdbc42"
)
There is limited support for dependency injection in specs2, mostly for execution environments or command-line arguments.
There is nothing preventing you from just using a lazy val and your favourite injection framework:
class MySpec extends Specification with Inject {
lazy val reportService = inject[ReportService]
...
}
With Play and Guice, you could have a test helper such as this:
import play.api.inject.guice.GuiceApplicationBuilder
import scala.reflect.ClassTag
trait Inject {
lazy val injector = (new GuiceApplicationBuilder).injector()
def inject[T : ClassTag]: T = injector.instanceOf[T]
}
If you really need runtime dependency injection, then it's better to use Guice loading, I guess:
package services
import org.specs2.mutable.Specification
import scala.reflect.ClassTag
import com.google.inject.Guice
// Something you'd like to share between your tests
// or maybe not
object Inject {
lazy val injector = Guice.createInjector()
def apply[T <: AnyRef](implicit m: ClassTag[T]): T =
injector.getInstance(m.runtimeClass).asInstanceOf[T]
}
class ReportServiceSpec extends Specification {
lazy val reportService: ReportService = Inject[ReportService]
"ReportService" should {
"Work" in {
reportService.foo mustEqual 2
}
}
}
Alternatively you can implement Inject object as
import scala.reflect.ClassTag
import play.api.inject.guice.GuiceApplicationBuilder
object Inject {
lazy val injector = (new GuiceApplicationBuilder).injector()
def apply[T : ClassTag]: T = injector.instanceOf[T]
}
It depends whether you want to use Guice directly, or thru play wrappers.
Looks like you are out of luck ATM: The comment says
Try to create an instance of a given class by using whatever constructor is available and trying to instantiate the first parameter recursively if there is a parameter for that constructor.
val constructors = klass.getDeclaredConstructors.toList.filter(_.getParameterTypes.size <= 1).sortBy(_.getParameterTypes.size)
i.e. Specs2 doesn't provide own DI out-of-the box,
Or you can reimplement the functionality yourself, if Guice isn't working for you.
App code:
package services
import javax.inject.Inject
class ReportService #Inject()(userService: UserService, supportService: SupportService) {
val foo: Int = userService.foo + supportService.foo
}
class UserService {
val foo: Int = 1
}
class SupportService {
val foo: Int = 41
}
Test code
package services
import org.specs2.mutable.Specification
import scala.reflect.ClassTag
import java.lang.reflect.Constructor
class Trick {
val m: ClassTag[ReportService] = implicitly
val classLoader: ClassLoader = m.runtimeClass.getClassLoader
val trick: ReportService = Trick.createInstance[ReportService](m.runtimeClass, classLoader)
}
object Trick {
def createInstance[T <: AnyRef](klass: Class[_], loader: ClassLoader)(implicit m: ClassTag[T]): T = {
val constructors = klass.getDeclaredConstructors.toList.sortBy(_.getParameterTypes.size)
val constructor = constructors.head
createInstanceForConstructor(klass, constructor, loader)
}
private def createInstanceForConstructor[T <: AnyRef : ClassTag]
(c: Class[_], constructor: Constructor[_], loader: ClassLoader): T = {
constructor.setAccessible(true)
// This can be implemented generically, but I don't remember how to deal with variadic functions
// generically. IIRC even more reflection.
if (constructor.getParameterTypes.isEmpty)
constructor.newInstance().asInstanceOf[T]
else if (constructor.getParameterTypes.size == 1) {
// not implemented
null.asInstanceOf[T]
} else if (constructor.getParameterTypes.size == 2) {
val types = constructor.getParameterTypes.toSeq
val param1 = createInstance(types(0), loader)
val param2 = createInstance(types(1), loader)
constructor.newInstance(param1, param2).asInstanceOf[T]
} else {
// not implemented
null.asInstanceOf[T]
}
}
}
// NB: no need to #Inject here. The specs2 framework does it for us.
// It sees spec with parameter, and loads it for us.
class ReportServiceSpec (trick: Trick) extends Specification {
"ReportService" should {
"Work" in {
trick.trick.foo mustEqual 2
}
}
}
And that expectedly fails with
[info] ReportService should
[error] x Work
[error] '42' is not equal to '2' (FooSpec.scala:46)
If you don't need runtime dependency injection, then it's better to use cake pattern, and forget reflection all-together.
My colleague suggested a "low-tech" workaround. In the test, instantiate service classes with new:
class ReportServiceSpec extends Specification {
val service = new ReportService(new UserService, new SupportService)
// ...
}
This also works:
class ReportServiceSpec #Inject()(userService: UserService) extends Specification {
val service = new ReportService(userService, new SupportService)
// ...
}
Feel free to post more elegant solutions. I've yet to see a simple DI solution that works (with Guice, Play's default).
Does anyone else find it curious that Play's default test framework does not play well with Play's default DI mechanism?
Edit: In the end I went with an "Injector" test helper, almost the same as what Eric suggested:
Injector:
package testhelpers
import play.api.inject.guice.GuiceApplicationBuilder
import scala.reflect.ClassTag
/**
* Provides dependency injection for test classes.
*/
object Injector {
lazy val injector = (new GuiceApplicationBuilder).injector()
def inject[T: ClassTag]: T = injector.instanceOf[T]
}
Test:
class ReportServiceSpec extends Specification {
val service = Injector.inject[ReportService]
// ...
}
I'm new to Scala, and trying to write a little REST API. I am using Scala 11.2, Spray 1.3.1 and akka 2.3.6.
I am basically trying to compile an example from spray.
The error I get for each of the routes is:
type mismatch; found : String("pong!!!!!!!!") required: spray.httpx.marshalling.ToResponseMarshallable
I am unsure if it is a versions incompatibility issue or I am missing a reference.
Here is my route definition taken from the spray example :
package com.Shenandoah.SBIR.httpInterface
import spray.routing.HttpService
trait HttpInterface extends HttpService {
def pingRoute = path("ping") {
get { complete("pong!!!!!!!!") }
}
def pongRoute = path("pong") {
get { complete("pong!?") }
}
def pipRoute = path("pip") {
get { complete("moonshine") }
}
def rootRoute = pingRoute ~ pongRoute ~ pipRoute
}
Here is the actor:
package com.Shenandoah.SBIR.httpInterface
import akka.actor._
class HttpInterfaceActor extends HttpInterface with Actor {
// the HttpService trait defines
// only one abstract member, which connects the services environment
// to the enclosing actor or test.
def actorRefFactory = context
def receive = runRoute(rootRoute)
}
You are probably using the dependency "io.spray" % "spray-routing" % "2.3.6" which is for Scala 2.10. There is a Spray version published without the Scala version designation, which is compiled against Scala 2.10. This is unfortunate.
Use "io.spray" %% "spray-routing" % "2.3.6" (note the double %) to pull in the dependency matching your Scala version. This will work with both Scala 2.10 and 2.11.
Looks like you are missing the default marshallers. Try adding to your imports:
import spray.httpx.marshalling.Marshaller
I am trying to learn scala (and also the concept of unit testing).
I have an object
object Foo{
def parse(s:String): Array[String] = {
return s.split(",")
}
}
A very simple code block.. but now I want to write unit test?
My code structure is:
src/main/scala/foo.scala
src/test/scala/(empty)
I am using sbt to compile and run?
Thanks
put this in src/test/scala/FooSpec.scala
import org.specs2.mutable.Specification
class FooSpec extends Specification {
"Foo" should {
"parse a String" in {
Foo.parse("a,b") == Array("a","b")
}
}
}
then in the sbt prompt you can run test
for this to work you will need to add a dependency on specs 2 in your build.sbt as explained in the documentation
libraryDependencies ++= Seq(
"org.specs2" %% "specs2" % "2.3.11" % "test"
)
It's a very big topic.
I'm a proponent of Specs2 along with its Mockito and ScalaCheck support. All of these have good documentation, so I recommend you start by looking them up on the Web.
I'm just following akka sample but could not run the program.
I've installed akka, sbt(0.13), scala(2.10.3) using homebrew(OSX Mountail Lion)
make empty directory named akka_test
create build.sbt and Hello.scala file
run sbt in akka_test directory and compile command worked well
sbt's run command complains No main class detected
What should I do to run the program?
here's my code
build.sbt
name := "My Project"
version := "1.0"
scalaVersion := "2.10.2"
resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
libraryDependencies +=
"com.typesafe.akka" %% "akka-actor" % "2.2.1"
Hello.scala
import akka.actor.Actor
import akka.actor.Props
class HelloWorld extends Actor {
override def preStart(): Unit = {
// create the greeter actor
val greeter = context.actorOf(Props[Greeter], "greeter")
// tell it to perform the greeting
greeter ! Greeter.Greet
}
def receive = {
// when the greeter is done, stop this actor and with it the application
case Greeter.Done ⇒ context.stop(self)
}
}
object Greeter {
case object Greet
case object Done
}
class Greeter extends Actor {
def receive = {
case Greeter.Greet ⇒
println("Hello World!")
sender ! Greeter.Done
}
}
sbt has run-main command which accepts main class from command line,
so full command is
sbt "run-main akka.Main HelloWorld"
sbt run looks for a "main" class, i.e., a class with def main(args: Array[String]) or extends the trait App. Since that can't be an actor, you'll need to initiate a system and use that to initiate HelloWorld, so something like:
class HelloWorldMain {
def main(args: Array[String]) {
import akka.actor.ActorSystem
val system = ActorSystem("HelloWorld")
val helloWorldActor = system.actorOf(Props[HelloWorld] ...)
// ... Do stuff
}
}
Since systems just run until you shut them down, if you want your main class to stop you'll either have to use futures via akka.pattern.ask and have the system terminate after you collect them or set up a separate reaper actor to kill the system for you. This post has more info on how to do that, and this pull request is a good example of how it looks in practice (and has some other useful stuff in there as well)
in case you have package you need to add the path.
For example if you have package com.foo.bar
(your HelloWorld is in ./youProject/src/main/scala/com/foo/bar)
then the command will be:
sbt "run-main akka.Main com.foo.bar.HelloWorld"