How can I get the value of a SettingKey like baseDirectory in a function? - sbt

I've got the following settingKey:
val filterValues = SettingKey[Map[String, String]]("filter-values")
And so when defining the setting:
filterValues := Map(
"someKey" -> sys.props.get("some.path").getOrElse(localPath("example"))
…
)
...
private def localFile(path: String): String = ((baseDirectory) { _ / path })(_.getAbsolutePath)
But what I'm getting is the following type mismatch:
Build.scala:8: type mismatch;
[error] found : sbt.Def.Initialize[String]
[error] required: String
[error] private def localFile(path: String): String = ((baseDirectory) { _ / path })(_.getAbsolutePath)
What's the right way to do this? (for sbt 0.13, btw)

You should extract the value of the settings within the setting intializer, and pass it to the function:
filterValues := Map(
"someKey" -> sys.props.get("some.path").getOrElse(localPath(baseDirectory.value, "example"))
…
)
...
private def localFile(base: File, path: String): String = (base / path).getAbsolutePath

Related

Scala.js ReferenceError in sbt shell but not in browser

I'm new to ScalaJS, so I'm a little perplexed with this issue.
I'm trying to write a very simple facade for the peer.js library. I have this:
#js.native
#JSGlobal
class Peer() extends js.Object {
def this(id: String = ???, options: js.Object = ???) = this()
def connect(id: String, options: js.Object = ???): DataConnection = js.native
def on(event: String, callback: js.Function): Unit = js.native
def disconnect(): Unit = js.native
def reconnect(): Unit = js.native
def destroy(): Unit = js.native
def id: String = js.native
def connections: js.Object = js.native
def disconnected: Boolean = js.native
def destroyed: Boolean = js.native
}
And here is the simple code I'm trying to run:
object index {
def main(args: Array[String]): Unit = {
val peer = new Peer()
peer.on("open", (id: String) => println(id))
}
}
This small piece of code works perfectly fine in the browser, however when I try to run it in the sbt shell, I get this error:
ReferenceError: Peer is not defined
ReferenceError: Peer is not defined
at $c_Lcom_nicolaswinsten_peerscalajs_index$.main__AT__V (file:///C:/Users/mjwin/IdeaProjects/peer-scalajs/target/scala-2.13/peer-scalajs-fastopt/main.js:840:14)
at $s_Lcom_nicolaswinsten_peerscalajs_index__main__AT__V (file:///C:/Users/mjwin/IdeaProjects/peer-scalajs/target/scala-2.13/peer-scalajs-fastopt/main.js:826:47)
at file:///C:/Users/mjwin/IdeaProjects/peer-scalajs/target/scala-2.13/peer-scalajs-fastopt/main.js:2078:1
at file:///C:/Users/mjwin/IdeaProjects/peer-scalajs/target/scala-2.13/peer-scalajs-fastopt/main.js:2079:4
at Script.runInContext (vm.js:143:18)
at Object.runInContext (vm.js:294:6)
at processJavaScript (C:\Users\mjwin\IdeaProjects\peer-scalajs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:241:10)
at HTMLScriptElementImpl._innerEval (C:\Users\mjwin\IdeaProjects\peer-scalajs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:176:5)
at onLoadExternalScript (C:\Users\mjwin\IdeaProjects\peer-scalajs\node_modules\jsdom\lib\jsdom\living\nodes\HTMLScriptElement-impl.js:98:12)
at onLoadWrapped (C:\Users\mjwin\IdeaProjects\peer-scalajs\node_modules\jsdom\lib\jsdom\browser\resources\per-document-resource-loader.js:53:33)
[error] org.scalajs.jsenv.ExternalJSRun$NonZeroExitException: exited with code 1
[error] at org.scalajs.jsenv.ExternalJSRun$$anon$1.run(ExternalJSRun.scala:186)
[error] stack trace is suppressed; run 'last Compile / run' for the full output
[error] (Compile / run) org.scalajs.jsenv.ExternalJSRun$NonZeroExitException: exited with code 1
I'm sure it's something really simple, but I'm stumped. Any guesses?
Thank you

My URL in Kotlin has an extra & at the end of it

private val BASE_URL = "https://itunes.apple.com/search?"
private var iTunesMap = mutableMapOf("term" to "parameter1",
"media" to "parameter2")
fun URL.addParameters(map:Map<String,String>) : String {
var newURL = BASE_URL
for(parameter in iTunesMap.iterator())
{
newURL += parameter.key + "=" + parameter.value + "&"
}
return newURL
}
I am ending up with a & at the end of the URL.
How do I prevent this from happening?
You can simply do it in a functional way:
val parameters = map.map { (key, value) -> // 1
"$key=$value" // 2
}.joinToString("&") // 3
return BASE_URL + parameters // 4
Explenation:
We use map function with destructuring declaration of parameters (key, value) which correspond to key and value in each map entry
For each map entry we create string key=value ($ is indicator, that we want to use value of some variable - in that case we use value of parameter key and parameter value
After .map function we have collection of strings: term=parameter1 and media=parameter2, we are joining them with & separator
Lastly we need to concatenate parameters to base url
If I can suggest - I would make this function more general by putting baseUrl as parameter - then you can use the same function for different urls.
EDIT
As Михаил Нафталь suggested in his answer, you can add prefix to joinToString function so you don't have to concatenate parameters with base url. So after that improvement your code will look like this:
return map.map { (key, value) ->
"$key=$value"
}.joinToString("&", prefix = BASE_URL )
Or you can do all of this using just joinToString function with giving transform function. (look for Михаил Нафталь answer)
Here is a one-liner:
map.entries.joinToString(separator = "&", prefix = BASE_URL) { (key, value) -> "$key=$value" }
Strings are immutable and += involves copying the entire string into a new string. Do not use += on a var: String in a loop, as that is O(N²); use a StringBuilder instead.
val urlBuilder = StringBuilder(BASE_URL)
iTunesMap.entries.joinTo(urlBuilder, separator = "&") { (key, value) ->
"$key=$value"
}
return urlBuilder.toString()

Typing object of functions with flowtype

I understand that this is the type of an object, which keys are the two strings 'foo' and 'bar', and the values two functions (although I find the syntax strange):
type Func0 = {
foo(number) : number,
bar(string) : string
};
for example:
const f: Func0 = {
foo: x => 2*x,
bar: x => `hello ${x}`
};
But what is this type? The type of an object with two functions as values? If so, what are the keys?
type Func1 = {
(number) : number,
(string) : string
}
Yes, this is the callable object with two possible strict outcomes. Repro example here - try flow.
In brief,
type fn = {
(number): number,
(string): string
}
in pseudo-code is:
type fn =
(number) => number
OR
(string) => string
so:
fn(number): number
fn(string): string
While with default function declaration you cannot keep the relation between parameter type and return type:
type fn = (number | string) => number | string
in pseudo-code is:
type fn = (number OR string) => number OR string
so:
fn(number): number | string
fn(string): number | string

How do I call a Scala Object method using reflection?

say, I have the following:
trait SomeTrait {
def someMethod: String;
}
object SomeObject extends SomeTrait {
def someMethod = "something";
}
I would like to call "someMethod" using reflection as I have the object name as a String.
Something like:
val objectName = "SomeObject"
val someTrait:SomeTrait = ???.asInstanceOf[SomeTrait]
someTrait.someMethod
or something similar.
Thanks
def companion[T](name : String)(implicit man: Manifest[T]) : T =
Class.forName(name + "$").getField("MODULE$").get(man.erasure).asInstanceOf[T]
val result = companion[SomeTrait]("SomeObject").someMethod
Since scala 2.10, we can use the reflection of Module:
import scala.reflect.runtime.universe
val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)
val module = runtimeMirror.staticModule("SomeObject")
val obj = runtimeMirror.reflectModule(module)
val someTrait:SomeTrait = obj.instance.asInstanceOf[SomeTrait]
someTrait.someMethod
For classes, this can be done pretty easily using the standard java reflection classOf method. For Scala objects, it is a bit more work, but it still can be done:
trait SomeTrait { def someMethod: String}
object SomeObject extends SomeTrait { def someMethod = "something"}
class SomeClass extends SomeTrait { def someMethod = "something"}
object Main {
def main(args:Array[String]) = {
val someClassTrait:SomeTrait = Class.forName("SomeClass").newInstance().asInstanceOf[SomeTrait]
println("calling someClassTrait: " + someClassTrait.someMethod)
val objectName = "SomeObject$"
val cons = Class.forName(objectName).getDeclaredConstructors();
cons(0).setAccessible(true);
val someObjectTrait:SomeTrait = cons(0).newInstance().asInstanceOf[SomeTrait]
println("calling someObjectTrait: " + someObjectTrait.someMethod)
}
}
//prints:
calling someClassTrait: something
calling someObjectTrait: something

Scala: How do I dynamically instantiate an object and invoke a method using reflection?

In Scala, what's the best way to dynamically instantiate an object and invoke a method using reflection?
I would like to do Scala-equivalent of the following Java code:
Class class = Class.forName("Foo");
Object foo = class.newInstance();
Method method = class.getMethod("hello", null);
method.invoke(foo, null);
In the above code, both the class name and the method name are passed in dynamically. The above Java mechanism could probably be used for Foo and hello(), but the Scala types don't match one-to-one with that of Java. For example, a class may be declared implicitly for a singleton object. Also Scala method allows all sorts of symbols to be its name. Both are resolved by name mangling. See Interop Between Java and Scala.
Another issue seems to be the matching of parameters by resolving overloads and autoboxing, described in Reflection from Scala - Heaven and Hell.
There is an easier way to invoke method reflectively without resorting to calling Java reflection methods: use Structural Typing.
Just cast the object reference to a Structural Type which has the necessary method signature then call the method: no reflection necessary (of course, Scala is doing reflection underneath but we don't need to do it).
class Foo {
def hello(name: String): String = "Hello there, %s".format(name)
}
object FooMain {
def main(args: Array[String]) {
val foo = Class.forName("Foo").newInstance.asInstanceOf[{ def hello(name: String): String }]
println(foo.hello("Walter")) // prints "Hello there, Walter"
}
}
The answers by VonC and Walter Chang are quite good, so I'll just complement with one Scala 2.8 Experimental feature. In fact, I won't even bother to dress it up, I'll just copy the scaladoc.
object Invocation
extends AnyRef
A more convenient syntax for reflective
invocation. Example usage:
class Obj { private def foo(x: Int, y: String): Long = x + y.length }
You can call it reflectively one of
two ways:
import scala.reflect.Invocation._
(new Obj) o 'foo(5, "abc") // the 'o' method returns Any
val x: Long = (new Obj) oo 'foo(5, "abc") // the 'oo' method casts to expected type.
If you call the oo
method and do not give the type
inferencer enough help, it will most
likely infer Nothing, which will
result in a ClassCastException.
Author Paul Phillips
The instanciation part could use the Manifest: see this SO answer
experimental feature in Scala called manifests which are a way to get around a Java constraint regarding type erasure
class Test[T](implicit m : Manifest[T]) {
val testVal = m.erasure.newInstance().asInstanceOf[T]
}
With this version you still write
class Foo
val t = new Test[Foo]
However, if there's no no-arg constructor available you get a runtime exception instead of a static type error
scala> new Test[Set[String]]
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)
So the true type safe solution would be using a Factory.
Note: as stated in this thread, Manifest is here to stay, but is for now "only use is to give access to the erasure of the type as a Class instance."
The only thing manifests give you now is the erasure of the static type of a parameter at the call site (contrary to getClass which give you the erasure of the dynamic type).
You can then get a method through reflection:
classOf[ClassName].getMethod("main", classOf[Array[String]])
and invoke it
scala> class A {
| def foo_=(foo: Boolean) = "bar"
| }
defined class A
scala>val a = new A
a: A = A#1f854bd
scala>a.getClass.getMethod(decode("foo_="),
classOf[Boolean]).invoke(a, java.lang.Boolean.TRUE)
res15: java.lang.Object = bar
In case you need to invoke a method of a Scala 2.10 object (not class) and you have the names of the method and object as Strings, you can do it like this:
package com.example.mytest
import scala.reflect.runtime.universe
class MyTest
object MyTest {
def target(i: Int) = println(i)
def invoker(objectName: String, methodName: String, arg: Any) = {
val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)
val moduleSymbol = runtimeMirror.moduleSymbol(
Class.forName(objectName))
val targetMethod = moduleSymbol.typeSignature
.members
.filter(x => x.isMethod && x.name.toString == methodName)
.head
.asMethod
runtimeMirror.reflect(runtimeMirror.reflectModule(moduleSymbol).instance)
.reflectMethod(targetMethod)(arg)
}
def main(args: Array[String]): Unit = {
invoker("com.example.mytest.MyTest$", "target", 5)
}
}
This prints 5 to standard output.
Further details in Scala Documentation.
Working up from #nedim's answer, here is a basis for a full answer,
main difference being here below we instantiate naive classes. This code does not handle the case of multiple constructors, and is by no means a full answer.
import scala.reflect.runtime.universe
case class Case(foo: Int) {
println("Case Case Instantiated")
}
class Class {
println("Class Instantiated")
}
object Inst {
def apply(className: String, arg: Any) = {
val runtimeMirror: universe.Mirror = universe.runtimeMirror(getClass.getClassLoader)
val classSymbol: universe.ClassSymbol = runtimeMirror.classSymbol(Class.forName(className))
val classMirror: universe.ClassMirror = runtimeMirror.reflectClass(classSymbol)
if (classSymbol.companion.toString() == "<none>") // TODO: use nicer method "hiding" in the api?
{
println(s"Info: $className has no companion object")
val constructors = classSymbol.typeSignature.members.filter(_.isConstructor).toList
if (constructors.length > 1) {
println(s"Info: $className has several constructors")
}
else {
val constructorMirror = classMirror.reflectConstructor(constructors.head.asMethod) // we can reuse it
constructorMirror()
}
}
else
{
val companionSymbol = classSymbol.companion
println(s"Info: $className has companion object $companionSymbol")
// TBD
}
}
}
object app extends App {
val c = Inst("Class", "")
val cc = Inst("Case", "")
}
Here is a build.sbt that would compile it:
lazy val reflection = (project in file("."))
.settings(
scalaVersion := "2.11.7",
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
"org.scala-lang" % "scala-library" % scalaVersion.value % "provided"
)
)

Resources