Pass reference to a template class in Play2 framework template engine - scala

I have a field.scala.html that should take a control as input and render it.
Right now I do like this:
#field("shop", "name", true) { (modelName, fieldName, required) =>
#textInput(modelName, fieldName, required)
}
But I would like to do it like this:
#field("shop", "name", true)(textInput)
I see 2 ways it could be done but not sure if it's possible:
Somehow via reflection call the textInput.apply with appropriate
parameters.
Make textInput implement some trait and field would
require an instance of this particular trait (more type safe)
Maybe there is a better way?

Templates are just functions. If field.scala.html takes a:
(String, String, Boolean) => Html
And textInput.Scala.html has the following parameter declaration:
#(modelName: String, fieldName: String, required: Boolean)
Then what you want to do will just work. If not try passing textInput.apply.

Related

How to find out who and from where called a method?

I am looking in some legacy code in Scala and see a method:
private def method1 (value: AnyRef, fieldName: String, qualifiedFieldName: String, fieldType: Type, schema: Schema)
(implicit mode: ParseMode): Any = {...}
How to see who called (or who can call) this method (from where)? (tracking in IDE/InteliJ is fine - just want to 'track' who is calling a method in order to understand the code routes)..
Ideal print line right after a Method name (inside method body) would be: This method is being called from this class etc...
You can use Thread.currentThread.getStackTrace() to achieve that.
You can find more info on that on the official documentation.
It returns an Array[StackTraceElement], where each StackTraceElement holds the class, method, file name and line number of the caller, ordered from top to bottom of the call stack.
You can run the following method in the Scala shell to get a sense of the result:
def stackTraceInfo(thread: Thread): Seq[String] =
thread.getStackTrace.map(ste => s"${ste.getClassName}.${ste.getMethodName}")
For example could yield something like the following:
scala> stackTraceInfo(Thread.currentThread).foreach(println)
java.lang.Thread.getStackTrace
$line7.$read$$iw$$iw$.stackTraceInfo
$line10.$read$$iw$$iw$.<init>
$line10.$read$$iw$$iw$.<clinit>
$line10.$eval$.$print$lzycompute
$line10.$eval$.$print
$line10.$eval.$print
...

Understanding Some and Option in Scala

I am reading this example from their docs:
class Email(val username: String, val domainName: String)
object Email {
def fromString(emailString: String): Option[Email] = {
emailString.split('#') match {
case Array(a, b) => Some(new Email(a, b))
case _ => None
}
}
}
println(Email.fromString("scala.center#epfl.ch"))
val scalaCenterEmail = Email.fromString("scala.center#epfl.ch")
scalaCenterEmail match {
case Some(email) => println(
s"""Registered an email
|Username: ${email.username}
|Domain name: ${email.domainName}
""")
case None => println("Error: could not parse email")
}
My questions:
What is Some and Option?
What is a factory method (just some function that creates a new object and returns it?)
What is the point of companion objects? Is it just to contain functions that are available to all instances of class? Are they like class methods in Ruby?
What is Some and Option?
Option is a data structure that represents optionality, as the name suggests. Whenever a computation may not return a value, you can return an Option. Option has two cases (represented as two subclasses): Some or None.
In the example above, the method Email.fromString can fail and not return a value. This is represented with Option. In order to know whether the computation yielded a value or not, you can use match and check whether it was a Some or a None:
Email.fromString("scala.center#epfl.ch") match {
case Some(email) => // do something if it's a Some
case None => // do something it it's a None
}
This is much better than returning null because now whoever calls the method can't possibly forget to check the return value.
For example compare this:
def willReturnNull(s: String): String = null
willReturnNull("foo").length() // NullPointerException!
with this
def willReturnNone(s: String): Option[String] = None
willReturnNone("foo").length() // doesn't compile, because 'length' is not a member of `Option`
Also, note that using match is just a way of working with Option. Further discussion would involve using map, flatMap, getOrElse or similar methods defined on Option, but I feel it would be off-topic here.
What is a factory method (just some function that creates a new object and returns it?)
This is nothing specific to Scala. A "factory method" is usually a static method that constructs the value of some type, possibly hiding the details of the type itself. In this case fromString is a factory method because it allows you create an Email without calling the Email constructor with new Email(...)
What is the point of companion objects? Is it just to contain functions that are available to all instances of class? Are they like class methods in Ruby?
As a first approximation, yes. Scala doesn't have static members of a class. Instead, you can have an object associated with that class where you define everything that is static.
E.g. in Java you would have:
public class Email {
public String username;
public String domain;
public static Optional<Email> fromString(String: s) {
// ...
}
}
Where as in Scala you would define the same class as roughly:
class Email(val username: String, val domain: String)
object Email {
def fromString(s: String): Option[Email] = {
// ...
}
}
I would like to add some examples/information to the third question.
If you use akka in companion object you can put every message that you use in case method (it should proceed and use by actor). Moreover, you can add some val for a name of actors or other constant values.
If you work with JSON you should create a format for it (sometimes custom reads and writes). This format you should put inside companion object. Methods to create instances too.
If you go deeper to Scala you can find case classes. So a possibility to create an object of this class without new is because there is a method apply in "default" companion object.
But in general, it's a place where you can put every "static" method etc.
About Option, it provides you a possibility to avoid some exception and make something when you don't have any values.
Gabriele put an example with email, so I'll add another one.
You have a method that sends email, but you take email from User class. The user can have this field empty, so if we have something like it
val maybeEmail: Option[String] = user.email you can use for example map to send an email
maybeEmail.map(email => sendEmail(email))
So if you use it, during writing methods like above you don't need to think that user specify his email or not :)

How can spray unmarshall a list in query parameters

I'm new to spray. Im playing around with building the routes, and while I manage to get parameters out of the query string using the parameters directive, I'm having trouble when I want one of the parameters to be a list.
For this example I've defined this case class:
case class Person(name: String, friends: Int)
my route currently looks like this:
path("test") {
get { parameters('name, 'friend ).as(Person) { p => complete(p) } }
}
this works fine and I can do a get: localhost:8080/test?name=jo&friends=12
and get what I expect.
I want to pass a list of friends ids, rather than just the number of friends, so I started by changing my case class like so:
case class Person(name: String, friends: Array[Int])
and my call to: localhost:8080/test?name=jo&friends=1,2
this does not compile. I get a type mismatch:
found : Person.type
required: spray.routing.HListDeserializer[shapeless.::[String,shapeless.::[String,shapeless.HNil]],?]
get { parameters('name, 'friend ).as(Person) { p =>
^ comment: this points at the P in .as(Person)
Any idea on what I'm doing wrong? I'd love an answer on how to do it. Even better would be an explanation to what is this shapeless type that it's looking for. Thanks
The first example worked since the parameter 'friend could be automatically converted from String to Int, hence satisfying the requirements of the Person case class.
The latter doesn't work because there's no String => Array[Int] conversion available, so it's impossible to materialize a Person from two strings.
You can tell that it's treating both 'friend and 'name as strings by looking at the message error
spray.routing.HListDeserializer[shapeless.::[String,shapeless.::[String,shapeless.HNil]],?]
can be simplified to something like
String :: String :: HNil
i.e. it's looking for something that can deserialize two strings into something else.
Bottom line, you will need to provide a custom deserializer in order to parse "1,2" into an Array[Int].
Here's the relevant documentation: http://spray.io/documentation/1.1-SNAPSHOT/spray-httpx/unmarshalling/#unmarshalling

Pre-process parameters of a case class constructor without repeating the argument list

I have this case class with a lot of parameters:
case class Document(id:String, title:String, ...12 more params.. , keywords: Seq[String])
For certain parameters, I need to do some string cleanup (trim, etc) before creating the object.
I know I could add a companion object with an apply function, but the LAST thing I want is to write the list of parameters TWICE in my code (case class constructor and companion object's apply).
Does Scala provide anything to help me on this?
My general recommendations would be:
Your goal (data preprocessing) is the perfect use case of a companion object -- so it is maybe the most idiomatic solution despite the boilerplate.
If the number of case class parameters is high the builder pattern definitely helps, since you do not have to remember the order of the parameters and your IDE can help you with calling the builder member functions. Using named arguments for the case class constructor allows you to use a random argument order as well but, to my knowledge, there is not IDE autocompletion for named arguments => makes a builder class slightly more convenient. However using a builder class raises the question of how to deal with enforcing the specification of certain arguments -- the simple solution may cause runtime errors; the type-safe solution is a bit more verbose. In this regard a case class with default arguments is more elegant.
There is also this solution: Introduce an additional flag preprocessed with a default argument of false. Whenever you want to use an instance val d: Document, you call d.preprocess() implemented via the case class copy method (to avoid ever typing all your arguments again):
case class Document(id: String, title: String, keywords: Seq[String], preprocessed: Boolean = false) {
def preprocess() = if (preprocessed) this else {
this.copy(title = title.trim, preprocessed = true) // or whatever you want to do
}
}
But: You cannot prevent a client to initialize preprocessed set to true.
Another option would be to make some of your parameters a private val and expose the corresponding getter for the preprocessed data:
case class Document(id: String, title: String, private val _keywords: Seq[String]) {
val keywords = _keywords.map(kw => kw.trim)
}
But: Pattern matching and the default toString implementation will not give you quite what you want...
After changing context for half an hour, I looked at this problem with fresh eyes and came up with this:
case class Document(id: String, title: String, var keywords: Seq[String]) {
keywords = keywords.map(kw => kw.trim)
}
I simply make the argument mutable adding var and cleanup data in the class body.
Ok I know, my data is not immutable anymore and Martin Odersky will probably kill a kitten after seeing this, but hey.. I managed to do what I want adding 3 characters. I call this a win :)

How to pass around string values type-safely?

E.g.:
def updateAsinRecords(asins:Seq[String], recordType:String)
Above method takes a Seq of ASINs and a record type. Both have type of String. There are also other values that are passed around with type String in the application. Needless to say, this being Scala, I'd like to use the type system to my advantage. How to pass around string values in a type safe manner (like below)?
def updateAsinRecords(asins:Seq[ASIN], recordType:RecordType)
^ ^
I can imagine, having something like this:
trait ASIN { val value:String }
but I'm wondering if there's a better approach...
There is an excellent bit of new Scala functionality know as Value Classes and Universal Traits. They impose no runtime overhead but you can use them to work in a type safe manner:
class AnsiString(val inner: String) extends AnyVal
class Record(val inner: String) extends AnyVal
def updateAnsiRecords(ansi: Seq[AnsiString], record: Record)
They were created specifically for this purpose.
You could add thin wrappers with case classes:
case class ASIN(asin: String)
case class RecordType(recordType: String)
def updateAsinRecords(asins: Seq[ASIN], recordType: RecordType) = ???
updateAsinRecords(Vector(ASIN("a"), ASIN("b")), RecordType("c"))
This will not only make your code safer, but it will also make it much easier to read! The other big advantage of this approach is that refactoring later will be much easier. For example, if you decide later that an ASIN should have two fields instead of just one, then you just update the ASIN class definition instead of every place it's used. Likewise, you can do things like add methods to these types whenever you decide you need them.
In addition to the suggestions about using a Value Class / extends AnyVal, you should probably control the construction to allow only valid instances, since presumably not any old string is a valid ASIN. (And... is that an Amazon thing? It rings a bell somehow.)
The best way to do this is to make the constructor private and put a validating factory method in a companion object. The reason for this is that throwing exceptions in constructors (when an attempt is made to instantiate with an invalid argument) can lead to puzzling failure modes (I often see it manifest as a NoClassDefFoundError error when trying to load a different class).
So, in addition to:
case class ASIN private (asin: String) extends AnyVal { /* other stuff */ }
You should include something like this:
object A {
import scala.util.{Try, Success, Failure}
def fromString(str: String): Try[ASIN] =
if (validASIN(str))
Success(new ASIN(str))
else
Failure(new InvalidArgumentException(s"Invalid ASIN string: $str")
}
How about a type alias?
type ASIN = String
def update(asins: Seq[ASIN])