I try to google it and search give me just java examples...
Thread.currentThread().getStackTrace()(2).getLineNumber
but in worksheet always returned 5, and in working project scala/playframework 2.5 - always 35
I try to play with level, but it does not work.
I understood, for example create services/Log.scala
package services
object Log {
def info(text: String) = {
val systemStr = makeSystemStr
Console.out.println(Console.BLUE + "[INFO] " + systemStr + Console.RESET + text)
}
def makeSystemStr() = {
val fileName = Thread.currentThread().getStackTrace()(3).getFileName
val lineNumber = Thread.currentThread().getStackTrace()(3).getLineNumber
val cnArr = Thread.currentThread().getStackTrace()(3).getClassName.split("[$]")
val pkgName = cnArr(0).split("[.]")(0)
val name = cnArr(0).split("[.]")(1)
val defName = cnArr(3)
s"$pkgName : $fileName : $name : $defName : line $lineNumber - "
}
}
Then in controller
package controllers
import play.api.mvc._
import services.Log
class SomeCtrl extends Controller {
def Index = Action { request =>
Log.info("some text")
Ok("ok")
}
}
use macro , you can easy to get lineNumber and fileName
//edit
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object SrcFile {
def currentLine: Int = macro SrcFileImpl.currentLine
def currentFileName: String = macro SrcFileImpl.currentFileName
def currentPackage: String = macro SrcFileImpl.currentPackage
def currentClassName: String = macro SrcFileImpl.currentClassName
def currentFuncName :String = macro SrcFileImpl.currentFuncName
}
class SrcFileImpl(val c: blackbox.Context) {
import c.universe._
def getPackage(symbol: Symbol): String =
if(symbol.isPackage) symbol.fullName else getPackage(symbol.owner)
def getClass(symbol: Symbol): String =
if(symbol.isClass) symbol.name.toTypeName.toString else getClass(symbol.owner)
def currentPackage: c.Expr[String] = c.Expr(q"${getPackage(c.internal.enclosingOwner)}")
def currentFileName: c.Expr[String] = c.Expr(q"${c.enclosingPosition.source.file.name}")
def currentLine: c.Expr[Int] = c.Expr(q"${c.enclosingPosition.line}")
def currentClassName: c.Expr[String] = c.Expr(q"${getClass(c.internal.enclosingOwner)}")
def currentFuncName: c.Expr[String] = c.Expr(q"${c.internal.enclosingOwner.name.toTermName.toString}")
}
// test
package so
object SrcFileTest extends App {
def f() = {
println(SrcFile.currentFileName)
println(SrcFile.currentLine)
println(SrcFile.currentPackage)
println(SrcFile.currentClassName)
println(SrcFile.currentFuncName)
}
f()
}
Related
trait Show[T] {
def show(t: T): String
}
Give such Show typeclass, I want to generate show for case class like
def caseClassShow[A](using Type[A], Quotes): Expr[Show[A]] = {
import quotes.reflect._
def shows(caseClassExpr: Expr[A]): Expr[String] = {
val caseClassTerm = caseClassExpr.asTerm
val parts = TypeRepr.of[A].typeSymbol.caseFields.collect {
case cf if cf.isValDef =>
val valDefTree = cf.tree.asInstanceOf[ValDef]
val valType = valDefTree.tpt
val showCtor = TypeTree.of[Show[_]]
val valShowType = Applied(showCtor, List(valType))
val showInstance = Expr.summon[valShowType] // compile error, how to summon the instance here
val valuePart = Apply(Select.unique(showInstance, "show"), List(Select(caseClassTerm, cf)))
'{s"${Expr(cf.name)}:${valuePart}"}
}
val strParts = Expr.ofList(parts)
'{$strParts.mkString(",")}
}
'{
new Show[A] {
def show(a: A) = {
${shows('{a})}
}
}
}
}
But the showInstance part won't compile, so how to summon an implicit Show[X] here ?
Implicits.search
can be used to summon implicit instance if there is no type arg avaiable for Expr.summon
val valDefTree = cf.tree.asInstanceOf[ValDef]
val valType = valDefTree.tpt
val showCtor = TypeRepr.typeConstructorOf(classOf[Show[_]])
val valShowType = showCtor.appliedTo(valType.tpe)
Implicits.search(valShowType) match {
case si: ImplicitSearchSuccess =>
val siExpr: Expr[Show[Any]] = si.tree.asExpr.asInstanceOf[Expr[Show[Any]]]
val valueExpr = Select(caseClassTerm, cf).asExpr
'{$siExpr.show($valueExpr)}
}
I am trying to execute this code on databricks in scala. Everything is in an object, then I have a case class and def main and other def functions.
Trying to work with "package cells" but I got Warning: classes defined within packages cannot be redefined without a cluster restart.
Compilation successful.
removing the object didn't work either
package x.y.z
import java.util.Date
import java.io.File
import java.io.PrintWriter
import org.apache.hadoop.fs.{FileSystem, Path}
object Meter {
val dateFormat = new SimpleDateFormat("yyyyMMdd")
case class Forc (cust: String, Num: String, date: String, results: Double)
def main(args: Array[String]): Unit = {
val inputFile = "sv" //
val outputFile = "ssv" //
val fileSystem = getFileSystem(inputFile)
val inputData = readLines(fileSystem, inputFile, skipHeader = true).toSeq
val filtinp = inputData.filter(x => x.nonEmpty)
.map(x => Results(x(6), x(5), x(0), x(8).toDouble))
def getTimestamp(date: String): Long = dateFormat.parse(date).getTime
def getDate(timeStampInMills: Long): String = {
val time = new Date(timeStampInMills)
dateFormat.format(time)
}
def getFileSystem(path: String): FileSystem = {
val hconf = new Configuration()
new Path(path).getFileSystem(hconf)
}
override def next(): String = {
val result = line
line = inputData.readLine()
if (line == null) {
inputData.close()
}
result
}
}
}
}
I have a macro that I use to generate some code to call methods dynamically. The macro is more complex than this, but for simplicity let's say it works something like this
def myMacro[T]: Seq[MethodName]
so than when called on
class Hello {
def one(a: Int, b: UserId): String = a.toString + b.id
def two(c: Option[Int]): String = ""
def three(d: Seq[Int], f: Set[Int]): String = ""
}
println(myMacro[Hello]) // Seq("one", "two", "three")
I need this macro to generate code for an internal framework we use at Candu, but I need to be able to call it from the parent's class. So what I want to achieve is:
trait Superclass {
def aFakeMethod: String = ""
val methods = myMacro[Self] // FIXME! self is not defined here...
}
class Hello extends Superclass {
def one(a: Int, b: UserId): String = a.toString + b.id
def two(c: Option[Int]): String = ""
def three(d: Seq[Int], f: Set[Int]): String = ""
}
val hi = new Hello
println(hi.methods) // Seq("one", "two", "three")
Because the high number of classes in the framework, modifying the api between Hello and Superclass is very expansive. So I would need a way to do this without changing code in Hello
Any suggestions on how this could be achieved?
If myMacro worked outside Hello it should work inside Superclass as well
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def myMacro[T]: Seq[String] = macro impl[T]
def impl[T: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
import c.universe._
val methodNames = weakTypeOf[T].decls
.filter(symb => symb.isMethod && !symb.isConstructor)
.map(_.name.toString).toList
val methodNamesTree = methodNames.foldRight[Tree](q"Nil")((name, names) => q"$name :: $names")
q"..$methodNamesTree"
}
Usage:
sealed trait Superclass {
def aFakeMethod: String = ""
val methods = myMacro[Hello]
}
val hi = new Hello
println(hi.methods) // List("one", "two", "three")
If for some reason you can't use the name of Hello you can try to make Superclass sealed and use knownDirectSubclasses
def myMacro1(): Seq[String] = macro impl1
def impl1(c: blackbox.Context)(): c.Tree = {
import c.universe._
val child = c.enclosingClass.symbol.asClass.knownDirectSubclasses.head
q"myMacro[$child]"
}
Usage:
sealed trait Superclass {
def aFakeMethod: String = ""
val methods = myMacro1()
}
val hi = new Hello
println(hi.methods) // List("one", "two", "three")
Or you can replace deprecated c.enclosingClass.symbol.asClass with c.internal.enclosingOwner.owner.asClass (now enclosingOwner is val methods, enclosingOwner.owner is trait Superclass).
If you can't make Superclass sealed try to traverse all classes and look for those extending Superclass
def myMacro2(): Seq[Seq[String]] = macro impl2
def impl2(c: blackbox.Context)(): c.Tree = {
import c.universe._
def treeSymbol(tree: Tree): Symbol = c.typecheck(tree, mode = c.TYPEmode).symbol
val enclosingClassSymbol = c.internal.enclosingOwner.owner
def isEnclosingClass(tree: Tree): Boolean = treeSymbol(tree) == enclosingClassSymbol
var methodss = Seq[Seq[String]]()
val traverser = new Traverser {
override def traverse(tree: Tree): Unit = {
tree match {
case q"$_ class $_[..$_] $_(...$_) extends { ..$_ } with ..$parents { $_ => ..$stats }"
if parents.exists(isEnclosingClass(_)) =>
val methods = stats.collect {
case q"$_ def $tname[..$_](...$_): $_ = $_" => tname.toString
}
methodss :+= methods
case _ => ()
}
super.traverse(tree)
}
}
c.enclosingRun.units.foreach(unit => traverser.traverse(unit.body))
def namesToTree[A: Liftable](names: Seq[A]): Tree =
names.foldRight[Tree](q"Seq()")((name, names) => q"$name +: $names")
namesToTree[Tree](methodss.map(namesToTree[String](_)))
}
Usage:
trait Superclass {
def aFakeMethod: String = ""
val methods = myMacro2()
}
class Hello1 extends Superclass {
def four = ???
def five = ???
}
class Hello extends Superclass {
def one(a: Int, b: UserId): String = a.toString + b.id
def two(c: Option[Int]): String = ""
def three(d: Seq[Int], f: Set[Int]): String = ""
}
val hi = new Hello
println(hi.methods) // List(List("four", "five"), List("one", "two", "three"))
Going from the following macro implementation, which is working as expected, i would like to remove the hard coded Account and replace it with a variable beeing passed as type parameter T:c.WeakTypeTag to the macro by the caller.
how should the macro be modified so that i can pass any type T?
`
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
import com.xy.iws.model.Model._
import com.xy.iws.repo.dao.DAO._
import com.xy.iws.service.run
import com.xy.iws.service.Api
import com.xy.iws.service.Request._
object makeService {
def make[T]:Api[Account] = macro makeImpl[T]
def makeImpl[T:c.WeakTypeTag](c: Context): c.Expr[Api[Account]] = c.universe.reify {
//val source = c.weakTypeOf[T]
import com.xy.iws.service.Request._
implicit val api = new Api[Account] {
def create():Int = {run.runG[Int](Create[Account])}
def all(): List[Account] = run.runG[List[Account]](new FindAll[Account])
def insert(model: List[Account]) = run.runG[Int](new Insert[Account](model))
def findSome(id: String): List[Account] = run.runG[List[Account]](new FindSome[Account](id))
def find(id: String): List[Account] = run.runG[List[Account]](new Find[Account](id))
def update(item: Account): List[Account] = {
val i = run.runG[List[Account]](new Find[Account](item.id))
if (i.size > 0) {
val updateAccount = run.runG[Int](new Update[Account](item.id, item.name))
}else {
insert(List(item))
}
run.runG[List[Account]](new FindAll[Account])
}
def delete(id: String): List[Account] = {
run.runG[Int](new Delete[Account](id))
run.runG[List[Account]](new FindAll[Account])
}
}
api
}
}
`
maybe you can use quasiquotes
abstract class Api[T] {
def a: Int
def b: Int
def t: List[T]
}
object Reify {
def apply[T](initValue: T): Api[T] = macro impl[T]
def impl[T: c.WeakTypeTag](c: Context)(initValue: c.Expr[T]): c.Tree = {
import c.universe._
val t = c.weakTypeOf[T].typeSymbol.name.toTypeName
q"""
val api = new Api[$t] {
def a = 1
def b = 2
override def t= List(${initValue})
}
api
"""
}
}
---use like this
object ReifyUsing extends App {
import macross.Reify
import macross.Api
println(Reify.apply[String]("String").t)
}
Thank you that was the hint i was looking for as answer to my question:
How to pass pass parameter in particular type parameter to the implementation of a macro?
Short answer: Use quasiquote
See the implementation below that did the job
`
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
import com.xy.iws.model.Model._
import com.xy.iws.repo.dao.DAO._
object makeService {
import com.xy.iws.service.Api
import com.xy.iws.service.Request
def make[T]:Api[T] = macro makeImpl[T]
def makeImpl[T:c.WeakTypeTag](c: Context): c.Tree = {
import c.universe._
val t = c.weakTypeOf[T].typeSymbol.name.toTypeName
q"""
implicit val api = new Api[$t] {
override def create():Int = {run.runG[Int](Create[$t])}
override def all(): List[$t] = run.runG[List[$t]](new FindAll[$t])
override def insert(model: List[$t]) = run.runG[Int](new Insert[$t](model))
override def findSome(id: String): List[$t] = run.runG[List[$t]](new FindSome[$t](id))
override def find(id: String): List[$t] = run.runG[List[$t]](new Find[$t](id))
override def update(item: $t): List[$t] = {
val i = run.runG[List[$t]](new Find[$t](item.id))
if (i.size > 0) {
run.runG[Int](new Update[$t](item.id, item.name))
}else {
insert(List(item))
}
run.runG[List[$t]](new FindAll[$t])
}
override def delete(id: String): List[$t] = {
run.runG[Int](new Delete[$t](id))
run.runG[List[$t]](new FindAll[$t])
}
}
api
"""
}
}
`
and i use the macro like this:
object Main {
def main(args: Array[String])
{
import com.xy.iws.service.Api
println(makeService.make[Account].all +" account objects")
println(makeService.make[Article].all +" article objects")
println(makeService.make[Supplier].all +" supplier objects")
}
}
What is wrong with this ActiveSlick query?
import io.strongtyped.active.slick.ActiveSlick
import io.strongtyped.active.slick.models.Identifiable
import scala.slick.driver._
import scala.slick.driver.JdbcProfile._
trait MappingActiveSlickIdentifiable {
this: ActiveSlick =>
import jdbcDriver.simple._
case class Foo(name: String, id: Option[Int] = None) extends Identifiable[Foo] {
override type Id = Int
override def withId(id: Id): Foo = copy(id = Some(id))
}
class FooTable(tag: Tag) extends EntityTable[Foo](tag, "FOOS") {
def name = column[String]("NAME")
def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
def * = (name, id.?) <> (Foo.tupled, Foo.unapply)
}
val Foos = new EntityTableQuery[Foo, FooTable](tag => new FooTable(tag))
}
object MappingActiveSlickIdentifiable {
class Components(override val jdbcDriver: JdbcDriver)
extends ActiveSlick
with MappingActiveSlickIdentifiable {
import jdbcDriver.simple._
val db = Database.forURL("jdbc:h2:mem:active-slick", driver = "org.h2.Driver")
def createSchema(implicit s:Session): Unit = {
Foos.ddl.create
}
}
object Components {
val instance = new Components(H2Driver)
}
import Components.instance._
def main(args:Array[String]) : Unit = {
db.withTransaction { implicit s =>
createSchema
(1 to 3) foreach { i =>
val foo = Foo(s"foo $i")
val fooWithId : Foo = Foos.save(foo)
Foos.update(fooWithId.copy(name = "?"))
println(s"Foo: $foo, foo with id: $fooWithId")
assert(fooWithId.id.isDefined, "Foo's ID should be defined")
}
val q = for {
f <- Foos if f.name === "?"
} yield f.name
}
}
}
The error:
[error] /Volumes/Home/s/hello/slick-active/hw.scala:57: value === is not a member of scala.slick.lifted.Column[String]
[error] f <- Foos if f.name === "?"
You should NOT import there
import scala.slick.driver._
import scala.slick.driver.JdbcProfile._
import from a particular driver instead, e.g.
import scala.slick.driver.H2Driver._