Bundle imports in Scala - scala

In my Scala project, almost all my files have these imports:
import eu.timepit.refined._
import eu.timepit.refined.api.Refined
import eu.timepit.refined.auto._
import eu.timepit.refined.numeric._
import spire.math._
import spire.implicits._
import com.wix.accord._
import com.wix.accord.dsl._
import codes.reactive.scalatime._
import better.files._
import java.time._
import scala.collection.mutable
...
...
What is the best way to DRY this in Scala? Can I specify all of them for my project (using some kind of sbt plugin?) or at the package level?

I've seen a few approaches that kinda solve what you're looking for. Check out
Imports defined
https://github.com/mongodb/casbah/blob/master/casbah-core/src/main/scala/Implicits.scala
Small example of this approach:
object Imports extends Imports with commons.Imports with query.Imports with query.dsl.FluidQueryBarewordOps
object BaseImports extends BaseImports with commons.BaseImports with query.BaseImports
object TypeImports extends TypeImports with commons.TypeImports with query.TypeImports
trait Imports extends BaseImports with TypeImports with Implicits
#SuppressWarnings(Array("deprecation"))
trait BaseImports {
// ...
val WriteConcern = com.mongodb.casbah.WriteConcern
// More here ...
}
trait TypeImports {
// ...
type WriteConcern = com.mongodb.WriteConcern
// ...
}
Imports used
https://github.com/mongodb/casbah/blob/master/casbah-core/src/main/scala/MongoClient.scala
When they use this import object, it unlocks all your type aliases for you. For example, WriteConcern
import com.mongodb.casbah.Imports._
// ...
def setWriteConcern(concern: WriteConcern): Unit = underlying.setWriteConcern(concern)
Essentially they wrap up all the imports into a common Import object, then just use import com.mycompany.Imports._
Doobie does something similar where most of the end-users just import doobie.imports._
https://github.com/tpolecat/doobie/blob/series/0.3.x/yax/core/src/main/scala/doobie/imports.scala
Again, a sample from this pattern:
object imports extends ToDoobieCatchSqlOps with ToDoobieCatchableOps {
/**
* Alias for `doobie.free.connection`.
* #group Free Module Aliases
*/
val FC = doobie.free.connection
/**
* Alias for `doobie.free.statement`.
* #group Free Module Aliases
*/
val FS = doobie.free.statement
// More here ...
}
The main difference in this approach between the package object style is you get more control over what/when to import. I've used both patterns, usually a package object for common utility methods I'll need across an internal package. And for libraries, specifically the users of my code, I can attach certain implicit definitions to an import object like in doobie mentioned above that will unlock a DSL syntax for the user using a single import.

I would probably go with the scala.Predef approach: basically, alias the types and expose the objects I want to make available. So e.g.
package com.my
package object project {
type LocalDate = java.time.LocalDate
type LocalDateTime = java.time.LocalDateTime
type LocalTime = java.time.LocalTime
import scala.collection.mutable
type MutMap[A, B] = mutable.Map[A, B]
val MutMap = mutable.Map
// And so on....
}
Now, wherever you start a file with package com.my.project, all of the above will be automatically available. Btw, kudos also to #som-snytt for pointing this out.

Related

Initialising variables in a mock class scala

I am writing unit tests for an akka actor model implementation. The system contains classes and traits that need to be initialised. My issue lies with the testing of the methods. When I mock required parameters for a class, it removes the intelij compiler error, however all of the variables are set to null.
I have attempted to use
when(mock.answer).thenReturn(42)
and directly assigning the variables
val mock.answer = 42
The above two through compilation errors. "When" is not recognised and directly assigning values cases a runtime error.
Any insight would be much appreciated.
I am not sure if I understood your issue correctly, but try the self contained code snippet below and let me know if it is not clear enough:
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{FunSuite, Matchers}
import org.mockito.Mockito.when
#RunWith(classOf[JUnitRunner])
class MyTest extends FunSuite with Matchers with MockitoSugar {
trait MyMock {
def answer: Int
}
test("my mock") {
val myMock = mock[MyMock]
when(myMock.answer).thenReturn(42)
myMock.answer should be(42)
}
}

Importing object without class

I'm trying to import an object from another .scala file that doesn't exist inside a class. I've found you can import a class like in here Scala, importing class. Is there a way to import an object without having a class around it?
Thanks
Importing a class and importing an object work the same in scala.
If you have a class
package com.package1
class MyClass{}
and an object
package com.package2
object MyObject{}
You import both the exact same way
package com.package3
import com.package1.MyClass
import com.package2.MyObject
import syntax is the same no matter what you are importing, whether it's an object, a class, a trait, a method, or a field
Yes, Scala can do exactly what you ask, and this is used frequently. Here is an example:
object Blah {
val x = 1
val y = "hello"
}
object Main extends App {
import Blah._
println(s"x=$x; y=$y")
}
Output is:
x=1; y=hello
You can also import members of a class instance, which blew my mind the first time I saw it.
If you are talking about companion objects, they are not defined inside a class, but after the class definition:
class AClass {
def sayHello() = {
println(AClass.Hello)
}
}
object AClass {
private val Hello = "hello"
}
You should have no problem importing it.

Slick 3.0.3 warning: method dynamicSession in trait DatabaseFactoryDef is deprecated

I am using Slick 3.0.3 and I'm happy with the Plain SQL approach mapping result sets to case classes. However, the following code produces the warning method dynamicSession in trait DatabaseFactoryDef is deprecated: Use the new Action-based API instead. After researching the Slick documentation and migration jungles I still have to find what they mean with the "new Action-based API". What's the clean, warning-free version of this?
import play.api.db.DB
import slick.driver.PostgresDriver.backend.Database._
import slick.jdbc.{StaticQuery => Q}
import play.api.Play.current
import models.Tables._
class InstrumentDao {
def countAllInstruments(): Int = DB.withConnection() { implicit conn =>
Q.queryNA[Int](s"""select count(*) from "${Instrument.baseTableRow.tableName}"""").first
}
}
The new API is imported via the {driver}.api._ package. Slick 3 is fully asynchronous and it returns Future instances for any action that is run using this API, so you need to change the return type of your function accordingly. Just use the run function on the Database instance and pass it a DBIOAction instance created using the method result on a statement; an example using the string interpolator to create the actual statement could be:
import play.api.db.DB
import scala.concurrent.Future
import slick.driver.PostgresDriver.api._
import play.api.Play.current
import models.Tables._
class InstrumentDao {
def countAllInstruments(): Future[Int] = db.run(sql"""select count(*) from "${Instrument.baseTableRow.tableName}"""".result.head)
}

How to instantiate lexical.Scanner in a JavaTokenParsers class?

I am writing a parser which inherits from JavaTokenParsers in that I have a function as follow:
import scala.util.parsing.combinator.lexical._
import scala.util.parsing._
import scala.util.parsing.combinator.RegexParsers;
import scala.util.parsing.combinator.syntactical.StdTokenParsers
import scala.util.parsing.combinator.token.StdTokens
import scala.util.parsing.combinator.lexical.StdLexical
import scala.util.parsing.combinator.lexical.Scanners
import scala.util.parsing.combinator.lexical.Lexical
import scala.util.parsing.input._
import scala.util.parsing.combinator.syntactical._
import scala.util.parsing.combinator.token
import scala.util.parsing.combinator._
class ParseExp extends JavaTokenParsers{
//some code for parsing
def parse(s:String) = {
val tokens = new lexical.Scanner(s)
phrase(expr)(tokens)
}
}
I am getting the following error :
type Scanner is not a member of package scala.util.parsing.combinator.lexical
[error] val tokens = new lexical.Scanner(s)
[error] ^
Why I have this error while I have imported all packages?
The JavaTokenParsers does not implement the Scanners trait. So you would need to extends also from this trait (or a trait that extends it) in order to have access to this class.
Unless your expr parser accepts the Reader as a parameter (not from its apply method), you'd need to override the type of elements and the input type if I'm not mistaken to make this working.
Also is there any reason you need to have a Reader[Token]?.
If you don't need a Reader[Token]and since you give your input in a plain string,
phrase(expr)(new CharSequenceReader(s))
should work.

Imports and wildcard imports of Symbols in Scala

I have a list of Symbols representing packages, objects and classes and want to import them in a macro context.
For packages and objects, this would mean a wildcard import and for classes it would mean a “standard” import.
Given a List[Symbol] consisting of some.package, some.Class and some.Object, how would I properly import those and how can I decide whether a “standard” or a wildcard import needs to be used?
My current approach is this:
def importPackageOrModuleOrClass(sym: Symbol): Import =
if (sym.isPackage || sym.isModule) // e. g. import scala._, scala.Predef
gen.mkWildcardImport(sym)
else // e. g. import java.lang.String
gen.mkImport(sym.enclosingPackage, sym.name, sym.name) // <--- ?????
The package/module import works, but the class import doesn't although it looks correct.
You need to get the "TermName" like this...
def importPackageOrModuleOrClass(sym: Symbol): Import =
if (sym.isPackage || sym.isModule)
gen.mkWildcardImport(sym)
else
gen.mkImport(sym.enclosingPackage, sym.name.toTermName, sym.name.toTermName)
You can grab more hints regarding importing, reflecting, etc. via the sourcecode at http://xuwei-k.github.io/scala-compiler-sxr/scala-compiler-2.10.0/scala/reflect/internal/Importers.scala.html