While creating Object, setting values to methods or variable without using def or val keyword - scala

I come from a Java background and as expected, am having problem understanding some patterns used in Scala (see below). Every time I feel that I have a good understanding of Scala patterns or programming methodology, something pops up that is beyond my programming understanding and puts me back in learning mode. I guess that's a beauty of scala that always inspires me to keep learning :)
Anyway I trying to do some sample programming in scala swing.............
val frame = new MainFrame {
title = "Electronic Classroom"
contents = new BorderPanel {
layout += new GridPanel(1, 2) {
contents += new ScrollPane(semesterList)
contents += new ScrollPane(courseList)
} -> West
}
menuBar = new MenuBar {
contents += new Menu("File") {
contents += new MenuItem("Login") {
action = Action("Login"){
login
user match{
case Some(inst:Instructor) => instructorMenu.enabled = true
enabled = false
case Some(_) => instructorMenu.enabled = false
enabled = false
case _ =>
}
}
}
contents += new Separator
contents += new MenuItem(Action("Exit")(sys.exit(0)))
}
}
contents += instructorMenu
}
size = new Dimension(1000, 600)
centerOnScreen
}
Here we are setting values to def and val without using def or val keyword while defining them (like title, size, contents etc) and it's now looking more like a body script which is different that the way we do in java where all the assignments etc takes place in a method body.. I guess I am missing a big design pattern here
Can someone help, abd explain to me the Scala design pattern??

This is actually not very different from Java—instead of creating an instance and then customising it, you are creating anonymous sub classes. E.g.
val frame = new MainFrame {
title = "Electronic Classroom"
}
instead of
val frame = new MainFrame
frame.title = "Electronic Classroom"
The difference to Java is that since Scala doesn't have dedicated constructor methods but treats all expressions within the body of a class part of the constructor, your anonymous sub class kind of "overrides" the constructor.
To compare directly with Java, lets say it wasn't anonymous:
class MyMainFrame extends MainFrame {
title = "Electronic Classroom"
}
In Java, this would be roughly equivalent to:
public class MyMainFrame extends JFrame {
public MyMainFrame() {
super();
setTitle("Electronic Classroom");
}
}
(I hope this is valid Java syntax, I'm a bit rusty)
This is the same case for MenuBar, Menu, MenuItem. Only Action { ... } is not subclassing but calling method apply on the Action companion object, making the syntax a bit more succinct (this way you won't have "constructor" statements, e.g. you couldn't write accelerator = None and so forth).

I subscribe to 0__'s explanation, just wanting to add that if I recall correctly you can do the same in java with
JFrame frame = new JFrame {{
title = "Electronic Classroom";
}};
This should create an anonymous subclass with the additional code appended to the constructor

Related

Are static methods more composable?

I have a case class called Cell and it has parameter-less methods for moving cells up, down, left, right...
case class Cell(topLeft: Coordinate, botRight: Coordinate) {
def up: Cell = {
Cell(
Coordinate(topLeft.x + 0, topLeft.y - 1)
, Coordinate(botRight.x + 0, botRight.y - 1))
}
}
It feels right that this up operation should be an instance method and be called like so:
val cell = Cell(x,y)
cell.up
However, if I make these operations static functions belonging to a companion object, like so,
object Cell{
def up(cell: Cell): Cell = {
Cell(
Coordinate(cell.topLeft.x + 0, cell.topLeft.y - 1)
, Coordinate(cell.botRight.x + 0, cell.botRight.y - 1))
}
...
}
then they seem more composable. Now I can pass around up, down, left,or right as a parameter of type Cell => Cell. As a parameter-less instance method it is equivalent to a value and so can't be passed as a function.
See both commented lines below.
private def move(move: Cell => Cell, team: Team, nucleus: Coordinate): Team = {
val (mover, others) = team.cells.partition(_.nucleus == Some(nucleus))
val newCell = move(mover.head) // Works using STATIC move
val newCell = mover.head.move // Doesn't Work (needs .up, .down etc...)
if(mover.nonEmpty){
if(isValidCellState(newCell)) {
Team(newCell :: others)
}else{
throw new BadMoveException("Invalid move from this position")
}
}else{
throw new BadMoveException("You didn't select a cell to move")
}
}
If I want both features:
Ability to call functions like instance methods
Use the functions as parameters for other functions
It seems that I would need to define the methods statically in the companion object, but then define them in the class by referencing the static implementation
def up = Cell.up(this)
Is this bad practice, it seems a bit stinky.
Scala makes it really easy to create lambdas for cases like this:
move(_.up, team, nucleus)
You'll notice that this is even shorter than Cell.up. For this reason, it seems unnecessary to also define them in the companion.

Play Framework Search Bar

I'm trying to make a search bar with only one variable - the search input. I'm sure there's a fairly simple way to do this, but everything that I've found about getting input from the DOM (the views file) has been about using a Form and getting multiple variables. Is there a simpler way to do this if it's just a single variable?
I have a function in my Applications
def singleElement = Action { implicit request =>
val databaseSupport = new InteractWithDatabase(comm, db)
val put = Future {
while (true) {
val data = databaseSupport.getFromDatabase()
if (data.nonEmpty) {
comm.communicator ! data.head
}
}
}
Ok(views.html.singleElement)
}
I want to take some input from the user on the page singleElement and pass it into getFromDatabase which calls a MySQL query. How do I do this?
You can use restful and do something like this
routs file
GET /content/search/:search controllers.ContentController.search(search:String)
and in controller:
public Result search(String saerch) {}

ScalaFX How do I create a method to react to changes in a var (ObjectProperty)?

I am making a multiplayer game client with ScalaFX GUI and Akka remoting for networking. When my client receives game data it stores it inside Model.gameData. I need my GUI to respond to this variable change.
I used gameData to create data:ObjectProperty in my Model object:
object Model {
var gameData:Option[GameData] = None
val data = new ObjectProperty(this,"data",Model.gameData)
...
}
drawGrid and drawPlayer are methods I use to update the GUI, located in CleintGUI object. I tired using addListener and onChange, they compile but the methods I placed inside of them are never invoked.
object ClientGUI extends JFXApp{
...
Model.data.addListener{ (o: javafx.beans.value.ObservableValue[_ <:Option[GameData]], oldVal: Option[GameData], newVal: Option[GameData]) =>
drawGrid
drawPlayer
}
Model.data onChange {
drawGrid
drawPlayer
}
}
What am I missing? Am I declaring data:ObectProperty or methods inside my ClientGUI incorrectly?
drawGrid and drawPlayer both work when I call them manually by creating an event through submitting a string in a TextField. When I receive GameData I also tried to directly call drawGrid and drawPlayer form inside of my actor class, but I got an error "Not an FX thread".
Edit: I got the GUI to update by mutating control attributes. However, ideally I would want to define the control attributes by using conditional expressions:
val data = new BooleanProperty(this,"data",Model.gameData.isDefined)
val msgLabel = new Label{
text <== when(data) choose " " otherwise "No GameData"
}
But this doesn't work as I can't figure out a way to define BooleanProperty such that when(data) changes value depending on boolean Model.gameData.isDefined
I was adding new elements to the GUI when I received gameData, by using GridPane.add method.
Instead of doing that I added all the controls(gui nodes/elements) during object creation and then changed their relevant attributes when I receive gameData.
e.g. I set Label.text from "No Game Data" to an empty string when I receive gameData:
def update {
ClientGUI.msgLabel = " "
}
I don't think this is the best approach as now I have publicly available vars in a multi threaded application, but since I only change them from one place when I receive new data it should be fine.
Ideally I would want to define the control attributes by using conditional expressions:
val data = new BooleanProperty(this,"data",Model.gameData.isDefined)
val msgLabel = new Label{
text <== when(data) choose " " otherwise "No GameData"
}
But this doesn't work as I can't figure out a way to define BooleanProperty such that when(data) changes value depending on boolean Model.gameData.isDefined

Creating custom DOM events with scalajs

I can't find a way to create custom events with scala-js. For instance, with js you can create a custom event like the following (taken from here):
var event = new CustomEvent('build', { 'detail': elem.dataset.time });
However, there is no constructor for CustomerEvent or Event in scala-js that accept arguments. Also, subclassing either such as:
class DrawEvent extends Event {
override def `type` = "draw"
}
leads to
Uncaught TypeError: undefined is not a function
when trying to construct via new DrawEvent()
Any ideas?
To instantiate javascript classes in ScalaJs you have to use js.Dynamic.newInstance:
This should work for your use case:
val event = js.Dynamic.newInstance(js.Dynamic.global.CustomEvent)("build", js.Dynamic.literal(detail = elem.dataset.time)).asInstanceOf[js.dom.CustomEvent]
There is more info available at the remarks portion (all the way at the bottom) of:
http://www.scala-js.org/doc/calling-javascript.html
Here is the same solution using some imports to make it shorter
import js.Dynamic.{ global => g, newInstance => jsnew, literal => lit }
val event = jsnew(g.CustomEvent)("build", lit(detail = elem.dataset.time)).asInstanceOf[js.dom.CustomEvent]
If you want to stay in the typed DOM (assuming you are talking about the scala-js-dom library), you can do:
new CustomEvent().initCustomEvent('build', false, false, elem.dataset.time)
The constructor you are using is actually only specified in DOM 4 (see MDN).

How to execute tests on the argument that a controller passes to the view in Play Framework

In our play application every controller function fetches data from the database (or some other way) and passes these values to the result
def index = Action { implicit request =>
val newsItems: List[String] = fetchNewsFromDB()
Ok(views.html.home.index(newsItems))
}
def fetchNewsFromDB() = List("Headline1", "Headline2")
I am writing tests using specifiactions (based on the documentation http://www.playframework.com/documentation/2.2.x/ScalaTest)
According to this documentation by controller as follows. In the next test I want to make sure that the index page contains a headline. I do this by checking if there exists a div with the class "headline"
"Example Page#index" should {
"should contain a headline" in {
val controller = new TestController()
val result: Future[SimpleResult] = controller.index().apply(FakeRequest())
val bodyText: String = contentAsString(result)
bodyText.toLowerCase must contain("<div class=\"headline\"")
}
}
However I would rather check whether the list newsItems which the controller passes to the view is nonempty.
What is the best way to do this?
Is it possible to this in a generic way for which little modification of the controllers is required?
I too was frustrated that I couldn't intercept the parameters on their way to the template - and in fact it can become extremely difficult to even get the template to render at all in tests if you have a lot of "state" in your pages (for example, implicits that provide the user object, navigation helpers etc).
What I ended up doing was putting in an extra "seam" for testability in my controllers; in my tests, I extend the controller under test, replacing the HTML rendering function with a mocked one, which I can then use to verify the parameters.
Here's a simple example based on your "news" Action; first, the controller, which is no longer an object so we can extend it:
object Application extends ApplicationController
trait ApplicationController extends Controller {
def newsAction = Action {
Ok(renderNews("this is the news"))
}
def renderNews(s:List[String]):Html = html.sandbox(s)
}
The renderNews method gives us the all-important "test seam". I think it also actually improves the readability of controller methods too, which is nice :-)
Now, the unit test:
class ApplicationSpec extends Specification with Mockito {
val mockedNewsRenderer = mock[List[String] => Html]
val controller = new ApplicationController {
override def renderNews(s:List[String]) = mockedNewsRenderer(s)
}
"Application News Controller" should {
"Pass a non-empty list of news items to the template" in {
val result = controller.newsAction(FakeRequest())
status(result) must beEqualTo(200)
val captor = ArgumentCaptor.forClass(classOf[List[String]])
there was one(mockedNewsRenderer).apply(captor.capture())
val theArgument = captor.getValue
theArgument.isEmpty must beFalse
}
}
}
We create a mock to stand-in for the renderNews function, extend the controller so that we can substitute it in (note that we don't change anything else about it of course), and then call the action as normal. Note that we still get a standard Play Result so we can still check status codes etc, but then, we can use the Mockito verify functionality that's built into Specs2, together with Mockito's ArgumentCaptor facility to assert that our template was indeed called, and that it was supplied with a non-empty list of strings.
This approach has worked well for me - it makes it possible to get really good code coverage of your controllers with fast-running and easy-to-write unit tests.
You have a very good question and a very valid point on testing controllers, but I'm afraid it can't be done easily. The problem is that the views compile to Scala functions meaning when you call views.html.home.index(newsItems) it will return an object of Html, which already has the Html put together and compiled. If you would like to test what get's passed in you need to intercept it before the view is called.
To solve this you would have to rewrite your controllers, by moving all your business logic out of the controller and only have the necessary request handling code there. That would almost be easier to test.