Custom converters in Scallop library - scala

I am trying to use Scallop (https://github.com/scallop/scallop/) to parse the command-line arguments in Scala.
However, I cannot compile the example for converting arguments to a case class as shown on https://github.com/scallop/scallop/wiki/Custom-converters.
I get two errors at compile-time:
[error] found : org.rogach.scallop.ValueConverter[center.scala.sbk.Commands.Person]{val nameRgx: scala.util.matching.Regex; val phoneRgx: scala.util.matching.Regex}
[error] required: String
[error] Error occurred in an application involving default arguments.
[error] val person = opt[Person](personConverter)
[error] ^
and
[error] ...: could not find implicit value for parameter conv: org.rogach.scallop.ValueConverter[center.scala.sbk.Commands.Person]
[error] Error occurred in an application involving default arguments.
[error] val person = opt[Person](personConverter)
[error] ^
Thank you for your help!

The documentation has a typo.
Use
val person = opt[Person]()(personConverter) // note the parentheses
instead of
val person = opt[Person](personConverter)
since personConverter is passed in implicit arguments.

Related

"Expected whitespace character" when running a custom inputKey

I am creating a custom inputKey which looks like
val rating = inputKey[Option[Int]]("How will you rate this course?")
rating := {
import complete.DefaultParsers._
import complete.Parser
val r: Parser[Int] = IntBasic.examples("<rating>")
r.result
}
This sits in file projectRoot/build.sbt.
I try to run this on sbt shell using multiple times, each time it fails
sbt:Hello> rating 1
[error] Expected whitespace character
[error] Expected '/'
[error] rating 1
[error] ^
sbt:Hello>
Then,
sbt:Hello> show "rating 3"
[error] Expected whitespace character
[error] Expected 'Global'
[error] Expected '*'
[error] Expected 'Zero'
[error] Expected 'ThisBuild'
[error] Expected 'ProjectRef('
[error] Expected '{'
[error] Expected project ID
[error] Expected configuration
[error] Expected configuration ident
[error] Expected key
[error] show "rating 3"
[error] ^
sbt:Hello>
Also, as
sbt:Hello> rating "5"
[error] Expected whitespace character
[error] Expected '/'
[error] rating "5"
[error] ^
sbt:Hello>
I do not know what I am missing here. Can someone please point out my mistake here?
Since there is a space character before the integer, try using Space ~> IntBasic parser combination like so
lazy val rating = inputKey[Int]("How will you rate this course?")
rating := {
import complete.DefaultParsers._
val rating = (Space ~> IntBasic).examples("<rating>").parsed
println(s"Rating input = $rating")
rating
}
Executing rating 3 in sbt should now output Rating input = 3

no suitable method found for configured finagle in Java code

I've Java polyglot application which mainly has Java code and uses few Scala libraries as well.
The Scala below code compiles fine.
import com.twitter.finagle.Http.Client
import com.twitter.finagle.Http
import com.twitter.finagle.param.Logger
object Main extends App {
private val loggerFinagle = java.util.logging.Logger.getLogger("FinagleLogger")
val client: Client = Http.client
.configured(Logger(loggerFinagle))
}
I write the same code in java as below
import com.twitter.finagle.Http;
import com.twitter.finagle.param.Logger;
public class JavaMain {
public static void main(String[] args) {
java.util.logging.Logger loggerFinagle = java.util.logging.Logger.getLogger("FinagleLogger");
Http.client()
.configured(new Logger(loggerFinagle));
}
}
When I compile the code I get below error -
[info] Compiling 1 Scala source and 1 Java source to /Users/rajkumar.natarajan/Documents/Coding/finagle-errors/target/scala-2.12/classes ...
[error] /Users/rajkumar.natarajan/Documents/Coding/finagle-errors/src/main/java/JavaMain.java:10:1: no suitable method found for configured(com.twitter.finagle.param.Logger)
[error] method com.twitter.finagle.Stack.Parameterized.<P>configured(P,com.twitter.finagle.Stack.Param<P>) is not applicable
[error] (cannot infer type-variable(s) P
[error] (actual and formal argument lists differ in length))
[error] method com.twitter.finagle.Stack.Parameterized.<P>configured(scala.Tuple2<P,com.twitter.finagle.Stack.Param<P>>) is not applicable
[error] (cannot infer type-variable(s) P
[error] (argument mismatch; com.twitter.finagle.param.Logger cannot be converted to scala.Tuple2<P,com.twitter.finagle.Stack.Param<P>>))
[error] method com.twitter.finagle.client.StackClient.<P>configured(P,com.twitter.finagle.Stack.Param<P>) is not applicable
[error] (cannot infer type-variable(s) P
[error] (actual and formal argument lists differ in length))
[error] method com.twitter.finagle.client.StackClient.<P>configured(scala.Tuple2<P,com.twitter.finagle.Stack.Param<P>>) is not applicable
[error] (cannot infer type-variable(s) P
[error] (argument mismatch; com.twitter.finagle.param.Logger cannot be converted to scala.Tuple2<P,com.twitter.finagle.Stack.Param<P>>))
[error] method com.twitter.finagle.client.EndpointerStackClient.<P>configured(P,com.twitter.finagle.Stack.Param<P>) is not applicable
[error] (cannot infer type-variable(s) P
[error] (actual and formal argument lists differ in length))
[error] method com.twitter.finagle.client.EndpointerStackClient.<P>configured(scala.Tuple2<P,com.twitter.finagle.Stack.Param<P>>) is not applicable
[error] (cannot infer type-variable(s) P
[error] (argument mismatch; com.twitter.finagle.param.Logger cannot be converted to scala.Tuple2<P,com.twitter.finagle.Stack.Param<P>>))
[error] method com.twitter.finagle.Http.Client.<P>configured(scala.Tuple2<P,com.twitter.finagle.Stack.Param<P>>) is not applicable
[error] (cannot infer type-variable(s) P
[error] (argument mismatch; com.twitter.finagle.param.Logger cannot be converted to scala.Tuple2<P,com.twitter.finagle.Stack.Param<P>>))
[error] Http.client()
[error] .configured
Looks like I've to pass the Tuple but I don't know how.
The project in github is here.
Below are dependency details of my project -
Scala Version - 2.12.6
Java Version - 1.8.0_151
finagle version - 7.1.0
According to the docs, you need to call the mk() method on the param, so something like the following should create the proper tuple:
Http.client()
.configured(new Logger(loggerFinagle).mk());

No Json serializer as JsObject found for type play.api.libs.json.JsValue

I'm trying to migrate my project from using play2-reactivemongo version 0.10.5.0.akka23 to using version 0.11.7.play23. I've already added the following import to fix the problems addressed in this question:
import play.modules.reactivemongo.json._
With the former version, the following code worked:
val updateEntity = Json.obj("_id" -> Json.obj("$oid" -> id))
val entity = Json.parse(stringJson)
collection.update(updateEntity, entity)
however, using the new version, the third line gives a compile error:
[error] No Json serializer as JsObject found for type play.api.libs.json.JsValue. Try to implement an implicit OWrites or OFormat for this type.
[error] collection.update(updateEntity, entity)
[error] ^
I've tried introducing an implicit OWriter:
implicit val toJsObject: OWrites[JsValue] = OWrites.apply(_.as[JsObject])
but that gives an implicit declaration conflict:
[error] ambiguous implicit values:
[error] both value toJsObject of type play.api.libs.json.OWrites[play.api.libs.json.JsValue]
[error] and object JsObjectDocumentWriter in trait ImplicitBSONHandlers of type play.modules.reactivemongo.json.JsObjectDocumentWriter.type
[error] match expected type collection.pack.Writer[play.api.libs.json.JsObject]
[error] collection.update(updateEntity, entity)
[error] ^
changing the second line to
val entity = Json.parse(stringJson).as[JsObject]
fixes the problem, but I have a lot of these around my code and I was hoping for a simpler solution.
Just got bit by this too. The trick is to remove
import play.modules.reactivemongo.json._
and instead use
import reactivemongo.play.json._
The play.modules version doesn't provide the identity OWriter.

How can I use Scala macros to create an object?

I am trying to create a Scala macro that will generate an object - something like
object SomeEnum {
sealed abstract class Enum(name: String)
case object Option1 extends Enum("option1")
case object Option2 extends Enum("option2")
private val elements: Seq[Enum] = Seq(Option1, Option2)
def apply(code: String): Enum = {
...
}
}
I thought I might be able to create a macro createEnum, so I could just put
createEnum("SomeEnum", "Option1", "Option2") into my code and have it generate. Seems like it's calling out for a macro.
But I must not be understanding macros. I am using Scala 2.11.6, and just to try to get something working, I created the following:
object createEnumObj {
def createEnumImpl(c: scala.reflect.macros.whitebox.Context)(ename: c.Expr[String]): c.universe.ModuleDef = {
import c.universe._
val Literal(Constant(s_ename: String)) = ename.tree
val oname = TermName(s_ename)
val barLine = q"val bar: Int = 5"
q"object $oname { $barLine }"
}
def createEnum(ename: String): Unit = macro createEnumImpl
}
This is in a separate project - everything seems to be compiling for it OK.
If I stick a call to createEnumObj.createEnum into some source and try to compile that, I get a billion lines (give or take a few) of exception output, which seems to repeat something like this:
[error] (main/compile:compile) java.lang.AssertionError: assertion failed:
[error] object foo extends scala.AnyRef {
[error] def <init>() = {
[error] super.<init>();
[error] ()
[error] };
[error] val bar: Int = 5
[error] }
[error] while compiling: /Users/bob/ICL/ironcore-id/src/main/scala/package.scala
[error] during phase: typer
[error] library version: version 2.11.6
[error] compiler version: version 2.11.6
[error] reconstructed args: -Xfuture ...
error]
[error] last tree to typer: term foo
[error] tree position: line 8 of /Users/bob/ICL/ironcore-id/src/main/scala/package.scala
[error] symbol: <none>
[error] symbol definition: <none> (a NoSymbol)
[error] symbol package: <none>
[error] symbol owners:
[error] call site: <none> in <none>
[error]
[error] == Source file context for tree position ==
[error]
[error] 5 type DateTime = Int
[error] 6
[error] 7 createEnumObj.createEnum("foo")
[error] 8
[error] 9 }
[error] Total time: 2 s, completed Jun 18, 2015 2:46:05 PM
What I am trying to do doesn't seem too dissimilar to this question, but I'm obviously missing something. Any ideas about how to accomplish this would be gratefully accepted.
Thanks,
Bob

Is it possible to mock Scala methods with view bounds with Mockito and Specs2?

I've come across a problem when mocking methods that have view bounds on the type of their parameters using Mockito and Specs2. Simply put, since a view bound translates to an extra implicit argument to the method, Mockito cannot reconcile the call described by an expectation to the actual arguments the mock recieves:
For example:
//Receiver.scala
class Receiver {
def methodWithViewBound[T <% WrappedString](w : T) : Unit = {
//noop!
}
}
//WrappedString.scala
class WrappedString(val wrapped : String) {
}
//TestMockedMethodWithViewBound.scala
import org.specs2.mutable._
import org.specs2.specification._
import org.specs2.mock._
import org.mockito.Matchers
class TestMockedMethodWithViewBound extends Specification with Mockito {
implicit def wrapString(s : String) : WrappedString = new WrappedString(s);
implicit def unwrapString(w : WrappedString) : String = w.wrapped;
"Mockito" should {
"Allow mocking of methods whose argument types include a view bound, using a matcher" in {
val receiver = mock[Receiver]
receiver.methodWithViewBound("Testing")
there was one(receiver).methodWithViewBound(Matchers.eq("Testing"))
}
"Allow mocking of methods whose argument types include a view bound, using an argument literal" in {
val receiver = mock[Receiver]
receiver.methodWithViewBound("Testing")
there was one(receiver).methodWithViewBound("Testing")
}
}
}
The output of this gives:
[15:18:46] [tim#ahtanum ../tim/Projects/MockitoTest] $ sbt test
[info] Set current project to Mockito View Bounds Test (in build file:/home/tim/Projects/MockitoTest/)
[info] Compiling 1 Scala source to /home/tim/Projects/MockitoTest/target/scala-2.9.1/test-classes...
[info] Mockito should
[error] x Allow mocking of methods whose argument types include a view bound
[error] The mock was not called as expected:
[error] Invalid use of argument matchers!
[error] 2 matchers expected, 1 recorded.
[error] This exception may occur if matchers are combined with raw values:
[error] //incorrect:
[error] someMethod(anyObject(), "raw String");
[error] When using matchers, all arguments have to be provided by matchers.
[error] For example:
[error] //correct:
[error] someMethod(anyObject(), eq("String by matcher"));
[error]
[error] For more info see javadoc for Matchers class. (TestMockedMethodWithViewBound.scala:12)
[info]
[info]
[info] Total for specification TestMockedMethodWithViewBound
[info] Finished in 175 ms
[info] 1 example, 1 failure, 0 error
[error] Failed: : Total 1, Failed 1, Errors 0, Passed 0, Skipped 0
[error] Failed tests:
[error] TestMockedMethodWithViewBound
[error] {file:/home/tim/Projects/MockitoTest/}default-3adcf2/test:test: Tests unsuccessful
[error] Total time: 7 s, completed 07-Mar-2012 15:19:47
[15:19:47] [tim#ahtanum ../tim/Projects/MockitoTest] $ sbt test
[info] Set current project to Mockito View Bounds Test (in build file:/home/tim/Projects/MockitoTest/)
[info] Compiling 1 Scala source to /home/tim/Projects/MockitoTest/target/scala-2.9.1/test-classes...
[info] Mockito should
[error] x Allow mocking of methods whose argument types include a view bound, using a matcher
[error] The mock was not called as expected:
[error] Invalid use of argument matchers!
[error] 2 matchers expected, 1 recorded.
[error] This exception may occur if matchers are combined with raw values:
[error] //incorrect:
[error] someMethod(anyObject(), "raw String");
[error] When using matchers, all arguments have to be provided by matchers.
[error] For example:
[error] //correct:
[error] someMethod(anyObject(), eq("String by matcher"));
[error]
[error] For more info see javadoc for Matchers class. (TestMockedMethodWithViewBound.scala:12)
[error] x Allow mocking of methods whose argument types include a view bound, using an argument literal
[error] The mock was not called as expected:
[error] Argument(s) are different! Wanted:
[error] receiver.methodWithViewBound(
[error] "Testing",
[error] ($anonfun$apply$mcV$sp$2) <function1>
[error] );
[error] -> at TestMockedMethodWithViewBound$$anonfun$1$$anonfun$apply$6$$anonfun$apply$2.apply$mcV$sp(TestMockedMethodWithViewBound.scala:22)
[error] Actual invocation has different arguments:
[error] receiver.methodWithViewBound(
[error] "Testing",
[error] ($anonfun$apply$7) <function1>
[error] );
[error] -> at TestMockedMethodWithViewBound$$anonfun$1$$anonfun$apply$6.apply(TestMockedMethodWithViewBound.scala:21)
[error] (TestMockedMethodWithViewBound.scala:19)
[info]
[info]
[info] Total for specification TestMockedMethodWithViewBound
[info] Finished in 325 ms
[info] 2 examples (+1), 2 expectations (+1), 2 failures (+1), 0 error
[error] Failed: : Total 2, Failed 2, Errors 0, Passed 0, Skipped 0
[error] Failed tests:
[error] TestMockedMethodWithViewBound
[error] {file:/home/tim/Projects/MockitoTest/}default-3adcf2/test:test: Tests unsuccessful
[error] Total time: 7 s, completed 07-Mar-2012 15:23:05
...has anyone come across this problem before, or come across any way of mocking methods with view bounds or implicit parameters using specs2?
Thanks,
Tim
Tim, I've added the possibility to verify converted parameters to the latest specs2 1.9-SNAPSHOT.
This is still experimental as I don't what kind of undesired effect could come out of that.
One thing, for example, is that any Function1 parameter will now be verified as ok by default because Mockito can not know which functions are implicit conversions and which are "regular" parameters.