Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Scala Programming Projects

You're reading from   Scala Programming Projects Build real-world projects using popular Scala frameworks such as Play, Akka, and Spark

Arrow left icon
Product type Paperback
Published in Sep 2018
Publisher Packt
ISBN-13 9781788397643
Length 398 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Mikael Valot Mikael Valot
Author Profile Icon Mikael Valot
Mikael Valot
Nicolas Jorand Nicolas Jorand
Author Profile Icon Nicolas Jorand
Nicolas Jorand
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Writing Your First Program FREE CHAPTER 2. Developing a Retirement Calculator 3. Handling Errors 4. Advanced Features 5. Type Classes 6. Online Shopping - Persistence 7. Online Shopping - REST API 8. Online Shopping - User Interface 9. Interactive Browser 10. Fetching and Persisting Bitcoin Market Data 11. Batch and Streaming Analytics 12. Other Books You May Enjoy

Creating my first project

As you now know the basics of running code in the REPL and the worksheet, it is time to create your first 'Hello World' project. In this section, we are going to filter a list of people and print their name and age into the console.

Creating the project

Repeat the same recipe that you completed in the Installing IntelliJ section to create a new project. Here is a summary of the tasks you must complete:

  1. Run IntelliJ and select Create New Project
  2. Select Scala and sbt
  3. Input the name of the project, such as Examples
  4. If the selected directory doesn't exist, IntelliJ will ask you if you want to create it – select OK

As soon as you accept that you are going to create the directory, IntelliJ is going to download all the necessary dependencies and build the project structure. Be patient, as this could take a while, especially if you do not have a good internet connection.

Once everything is downloaded, you should have your IDE in the following state:

Notice the folder structure. The source code is under src/main/scala and the test code is under src/test/scala. If you have used Maven before, this structure should sound familiar.

Creating the Main object

Here we are! Let's create our first application. First, create the entry point for the program. If you are coming from Java, it would be equivalent to defining the public static void main(String[] args).

Right-click on the src/main/scala folder and select New | Scala Class. Give Main as the class name and Object as the Kind:

We have created our first object. This object is a singleton. There can be only one instance of it in the JVM. The equivalent in Java would be a static class with static methods.

We would like to use it as the main entry point of our program. Scala provides a convenient class named App that needs to be extended. Let's extend our Main object with that class:

object Main extends App {

}

The App superclass defines a static main method that will execute all the code defined inside your Main object. That's all – we created our first version, which does nothing!

We can now run the program in IntelliJ. Click on the small green triangle in the gutter of the object definition, as follows:

The program gets compiled and executed, as shown in the following screenshot:

It is not spectacular, but let's improve it. To get the right habits, we are going to use the TDD technique to proceed further.

Writing the first unit test

TDD is a very powerful technique to write efficient, modular, and safe programs. It is very simple, and there are only three rules to play this game:

  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail, and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
See the full article from Uncle Bob here: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd.

There are multiple testing frameworks in Scala, but we chose ScalaTest (http://www.scalatest.org/) for its simplicity.

In order to add the ScalaTest library in the project, follow these steps:

  1. Edit the build.sbt file.
  2. Add a new repository resolver to search for Scala libraries.
  3. Add the ScalaTest library:
name := "Examples"
version := "0.1"
scalaVersion := "2.12.4"
resolvers += "Artima Maven Repository" at "http://repo.artima.com/releases"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.4" % "test"
Notice the information bar on the top of the screen. It tells you that your file has changed and asks for multiple choices. As this is a small project, you can select enable autoimport.
  1. Create the test class by right-clicking on the test/scala folder and clicking on create a new class. Name it MainSpec.

ScalaTest offers multiple ways to define your test – the full list can be found on the official website (http://www.scalatest.org/at_a_glance/WordSpec). We are going to use the WordSpec style since it is quite prescriptive, offers a hierarchical structure, and is commonly used on large Scala projects.

Your MainSpec should extend the WordSpec class and the Matchers class, like so:

class MainSpec extends WordSpec with Matchers {

}
The class Matchers is providing the word should as a keyword to perform the comparison on a test.

WordSpec and Matchers are underlined in red, which means that the class is not resolved. To make it resolved, go with the cursor on the class and press Alt + Enter of your keyboard. If you are positioned on the WordSpec word, a popup should appear. This is normal, as there are several classes named WordSpec in different packages:

Select the first option and IntelliJ will automatically add the import on the top of your code. On the Matchers class, as soon as you type Alt + Enter, the import will be added directly.

The final code should be as follows:

import org.scalatest.{WordSpec, Matchers}

class MainSpec extends WordSpec with Matchers {

}

Our class skeleton is now ready for our first test. We would like to create the Person class and test its constructor.

Let's explain what we would like to test using simple sentences. Complete the test class with the following code:

class MainSpec extends WordSpec with Matchers {
"A Person" should {
"be instantiated with a age and name" in {
val john = Person(firstName = "John", lastName = "Smith", 42)
john.firstName should be("John")
john.lastName should be("Smith")
john.age should be(42)
}
}
}

IntelliJ is complaining that it cannot resolve the symbols Person, name, surname, and age. This is expected since the Person class does not exist. Let's create it in the folder src/main/scala. Right-click on the folder and create a new class named Person.

Transform it in the case of the class by adding the case keyword and defining the constructor with the name, surname, and age:

case class Person(firstName: String, lastName: String, age: Int)

If you go back to the MainSpec.scala file, you'll notice that the class is now compiled without any error and warning. The green tick () on the top-right of the code window confirms this.

Run the test by right-clicking on the MainSpec.scala file and selecting Run 'MainSpec', or use the keyboard shortcut Ctrl + Shift + F10 or Ctrl + Shift + R:

The test contained in MainSpec runs and the results appear in the Run window:

Implementing another feature

Now, we would like to have a nice representation of the person by stating his/her name and age. The test should look like the following:

"Get a human readable representation of the person" in {
val paul = Person(firstName = "Paul", lastName = "Smith", age = 24)
paul.description should be("Paul Smith is 24 years old")
}

Run the test again. We will get a compilation error:

This is expected as the function doesn't exist on the Person class. To implement it, add the expected implementation by setting the cursor on the description() error in the MainSpec.scala class, hitting Alt + Enter, and selecting the create method description.
IntelliJ generates the method for you and sets the implementation to ???. Replace ??? with the expected code:

def description = s"$firstName $lastName is $age ${if (age <= 1) "year"                    else "years"} old"

By doing so, we defined a method that does not take any parameter and return a string representing Person. In order to simplify the code, we are using a string interpolation to build the string. To use string interpolation, you just have to prepend an s before the first quote. Inside the quote, you can use the wildcard $ so that we can use an external variable and use the bracket after the dollar sign to enter more code than just a variable name.

Execute the test and the result should be green:

The next step is to write a utility function that, given a list of people, returns only the adults.

For the tests, two cases are defined:

"The Person companion object" should {
val (akira, peter, nick) = (
Person(firstName = "Akira", lastName = "Sakura", age = 12),
Person(firstName = "Peter", lastName = "Müller", age = 34),
Person(firstName = "Nick", lastName = "Tagart", age = 52)
)
"return a list of adult person" in {
val ref = List(akira, peter, nick)
Person.filterAdult(ref) should be(List(peter, nick))
}
"return an empty list if no adult in the list" in {
val ref = List(akira)
Person.filterAdult(ref) should be(List.empty[Person])
}
}

Here, we used a tuple to define three variables. This is a convenient way to define multiple variables. The scope of the variables is bounded by the enclosing curly brackets.
Use IntelliJ to create the filterAdult function by using the Alt+ Enter shortcut. The IDE understands that the function should be in the Person companion object and generates it for you.

If you didn't use the named parameters and would like to use them, IntelliJ can help you: hit Alt + Enter when the cursor is after the parenthesis and select "used named arguments ...".

We implement this method using the for comprehension Scala feature:

object Person {
def filterAdult(persons: List[Person]) : List[Person] = {
for {
person <- persons
if (person.age >= 18)
} yield (person)
}
}

It is a good practice to define the return type of the method, especially when this method is exposed as a public API.

The for comprehension has been used only for demonstration purposes. We can simplify it using the filter method on List. filter is part of the Scala Collections API and is available for many kinds of collections:

def filterAdult(persons: List[Person]) : List[Person] = {
persons.filter(_.age >= 18)
}

Implementing the Main method

Now that all our tests are green, we can implement the main method. The implementation becomes trivial as all the code is already in the test:

object Main extends App {
val persons = List(
Person(firstName = "Akira", lastName = "Sakura", age = 12),
Person(firstName = "Peter", lastName = "Müller", age = 34),
Person(firstName = "Nick", lastName = "Tagart", age = 52))

val adults = Person.filterAdult(persons)
val descriptions = adults.map(p => p.description).mkString("\n\t")
println(s"The adults are \n\t$descriptions")
}

The first thing is to define a list of Person, so that Person.filterAdult() is used to remove all the persons, not the adults. The adults variable is a list of Person, but I would like to transform this list of Person into a list of the description of the Person. To perform this operation, the map function of the collection is used. The map function transforms each element of the list by applying the function in the parameter.

The notation inside the map() function defines an anonymous function that takes p as the parameter. The body of the function is p.description. This notation is commonly used whenever a function takes another function as an argument.

Once we have a list of descriptions, we create a string with the mkString() function. It concatenates all the elements of the list using the special character \n\t, which are respectively the carriage return and the tab character.

Finally, we perform the side effect, which is the print on the console. To print in the console, the println alias is used. It is a syntactic sugar for System.out.println.

You have been reading a chapter from
Scala Programming Projects
Published in: Sep 2018
Publisher: Packt
ISBN-13: 9781788397643
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime