scalajs js.native object throws "is not a constructor" - scala.js

I have the following class
#js.native
class Foo extends js.Object {
var bar: String = js.native
}
And in my JSApp I have
object TutorialApp extends JSApp {
#JSExport
val bar = new Foo()
}
When I run I get $g.Foo is not a constructor. Following the scalajs doc I can not get what I am doing wrong here.

Related

Scala generics function call

I have the following trait in scala:
trait BaseDao {
type T <: BaseModel
def saveModel(model: T)
}
I created a class which extends BaseDao:
class Sample (dynamoDBMapper: DynamoDBMapper) extends BaseDao with LazyLogging {
checkNotNull(dynamoDBMapper)
protected def classType: Class[T] = implicitly[ClassTag[T]].runtimeClass.asInstanceOf[Class[T]]
override def saveModel(model: T): Unit ={
model.validate()
dynamoDBMapper.save(model)
}
Now, when I create the instance of above class and try to call save method:
val testModel = new TestModel();
testModel.setHashKey("a")
testModel.setSortKey("b")
testModel.setCreatedOn(new Date())
testModel.setModifiedOn(new Date())
sample.saveModel(testModel)
It gives the following error:
Type mismatch expected: Sample#T, actual: TestModel model class extends BaseModel class
I am new in scala and I am not able to figure out what is wrong here?
You haven't defined type T in Sample.
Rewrite your Sample class to look somewhat like this:
class Sample (dynamoDBMapper: DynamoDBMapper) extends BaseDao with LazyLogging {
checkNotNull(dynamoDBMapper)
type T = TestModel
override def saveModel(model: T): Unit ={
model.validate()
dynamoDBMapper.save(model)
}
}

how to define global scope method with `.` in name

I am trying to define facade for : https://facebook.github.io/jest/docs/en/api.html#testonlyname-fn
#JSGlobalScope
#js.native
object JestGlobal extends js.Object {
def test(str: String, function: js.Function0[_]): Unit = js.native
#JSName("test.only")
def testOnly(str: String, function: js.Function0[_]): Unit = js.native
def expect[T](in:T) : Matcher[T] = js.native
}
#js.native
trait Matcher[T] extends js.Object {
def toBe(in:T):Unit = js.native
}
Calling a method of the global scope whose name is not a valid
JavaScript identifier is not allowed. [error] See
https://www.scala-js.org/doc/interoperability/global-scope.html for
further information.
Edit:(Answer)
def test : JestTestObject = js.native
#js.native
trait JestTestObject extends js.Object {
def only(str: String, function: js.Function0[_]): Unit = js.native
}
For all practical purposes, there is no such thing as a JS function whose name is test.only. It is much more likely that there is a top-level object whose name is test, and it has a method named only. You can model that as:
#js.native
#JSGlobal("test")
object JestTest extends js.Object {
def only(str: String, function: js.Function0[_]): Unit = js.native
}
You can also use the same object to represent the top-level function whose name is test (because apparently the library is presented so), by adding an apply method:
#js.native
#JSGlobal("test")
object JestTest extends js.Object {
// This is the test(...) function
def apply(str: String, function: js.Function0[_]): Unit = js.native
// This is the test.only(...) function
def only(str: String, function: js.Function0[_]): Unit = js.native
}
Your variant as a self-answer is also valid, but it can be made more idiomatic as follows:
#js.native
#JSGlobalScope
object JestGlobal extends js.Object {
#js.native
object test extends js.Object {
// This is the test(...) function
def apply(str: String, function: js.Function0[_]): Unit = js.native
// This is the test.only(...) function
def only(str: String, function: js.Function0[_]): Unit = js.native
}
def expect[T](in: T): Matcher[T] = js.native
}

How to inject a trait with macwire

I have a Scala trait
trait UserRepository {
def findByEmail(email: String): User
}
I would like to inject this into a service with MacWire
class AccountService(){
val userRepo = wire[UserRepository]
}
And then use it in a test or class
class AccountServiceSpec {
val userRepo = new UserRepositoryImpl()
val accountSvc = new AccountService() //<--not manually injecting repo in service constructor
}
but I'm getting a compile error in the service class
Cannot find a public constructor nor a companion object for
accounts.repository.UserRepository
You may try to transform userRepo to class parameter, that allows macwire automatically provide its value for service:
import com.softwaremill.macwire._
case class User(email: String)
trait UserRepository {
def findByEmail(email: String): User
}
class AccountService(val userRepo: UserRepository)
class UserRepositoryImpl extends UserRepository{
def findByEmail(email: String): User = new User(email)
}
class AccountServiceSpec {
val userRepo = new UserRepositoryImpl()
val accountSvc = wire[AccountService] //<--not manually injecting repo in service constructor
}

Using trait method in the class constructor

I have a trait and a class that extends the trait. I can use the methods from the trait as follows:
trait A {
def a = ""
}
class B(s: String) extends A {
def b = a
}
However, when I use the trait's method in the constructor like this:
trait A {
def a = ""
}
class B(s: String) extends A {
def this() = this(a)
}
then the following error appears:
error: not found: value a
Is there some way to define default parameters for the construction of classes in the trait?
EDIT: To clarify the purpose: There is the akka-testkit:
class TestKit(_system: ActorSystem) extends { implicit val system = _system }
And each test looks like this:
class B(_system: ActorSystem) extends TestKit(_system) with A with ... {
def this() = this(actorSystem)
...
}
because I want to create common creation of the ActorSystem in A:
trait A {
val conf = ...
def actorSystem = ActorSystem("MySpec", conf)
...
}
It's a little bit tricky because of Scala initialization order. The simplest solution I found is to define a companion object for your class B with apply as factory method:
trait A {
def a = "aaaa"
}
class B(s: String) {
println(s)
}
object B extends A {
def apply() = new B(a)
def apply(s: String) = new B(s)
}

Is it possible to split object definion in several files in scala?

I'm writing a facade to use CreateJS lib in scala, like this
object CreateJS
{
sealed trait EventListener extends js.Object
type EventHandler = js.Function
class DisplayObject extends js.Object
{
}
class Container extends DisplayObject
{
def addChild(item:DisplayObject):Unit = ???
def update():Unit = ???
}
#JSName("createjs.Stage")
class Stage(canvasId:String) extends Container with EventListener
// TODO: Is enum done this way ???
object MovieClip
{
#JSName("createjs.MovieClip")
var INDEPENDENT:String = _
#JSName("createjs.SINGLE_FRAME")
var SINGLE_FRAME:String = _
#JSName("createjs.SYNCHED")
var SYNCHED:String = _
}
#JSName("createjs.MovieClip")
class MovieClip(mode:js.String=MovieClip.INDEPENDENT,startPosition:js.Number=0, loop:js.Boolean=true, labels:js.Object = null) extends DisplayObject
{
def addEventListener(eventName:String, target:EventHandler):Unit = ???
var timeline:TimeLine = _
def gotoAndPlay(where:String):Unit = ???
}
class TimeLine extends js.Object
{
def addTween(tween:Tween):Unit = ???
}
#JSName("createjs.Shape")
class Shape(graphics:Graphics = null) extends DisplayObject
#JSName("createjs.Graphics")
class Graphics extends js.Object
{
def beginFill(color:String):Graphics = ???
def drawCircle(x:js.Number, y:js.Number, r:js.Number):Graphics = ???
}
#JSName("createjs.Ticker")
object Ticker extends js.Object
{
def addEventListener(eventName:String, handler:EventHandler):Unit = ???
def addEventListener(eventName:String, stage:Stage):Unit = ???
}
class Tween extends js.Object
{
def get(item:DisplayObject):Tween = ???
def to(state:js.Dynamic, time:js.Number = 0):Tween = ???
}
#JSName("createjs.Tween")
object Tween extends Tween
/* Load queue */
class Plugin extends js.Object
#JSName("createjs.Sound")
object Sound extends Plugin {
def play(soundId:String):Unit = ???
}
#JSName("createjs.LoadQueue")
class LoadQueue(useXHR:Boolean = true, basePath:String="", crossOrigin:String="") extends js.Object
{
def installPlugin(plugin:Plugin):Unit = ???
def on(event:String, handler:EventHandler):Unit = ???
def addEventListener(event:String, handler:EventHandler):Unit = ???
def loadFile(params:js.Dynamic):Unit = ???
def loadManifest(paramList:js.Array[js.Dynamic]):Unit = ???
}
}
This file becomes just a large pile.
In real createJS these are split in 4 files - easel, tween, sound and preload, each extending base createjs object. Is it possible I do this file separation in scala while keeping everything in CreateJS namespace?
(Maybe such port already exist?)
You can split code in different trait, each one responsible for a coherent aspect (and gathering related functions), each trait in a separate file, then have the public singleton facade object exposing all.
For example with trait A implementing function foo and bar in file A.scala, and trait B with functions oof and rab in file B.scala, then facade object can be declared like object Facade extends A with B.
In this way, I would suggest to declare trait as package private, as they are there only to organise code: private[mypackage] trait A { ... }.