This blog is continuation of – ‘An Invitation From Scala String Interpolation‘. Here we will explore how to define a custom string interpolator.
In this blog the custom interpolator being designed works exactly like the ‘s interpolator’ with an extra ability to write the “post interpolation content” into a file and finally returning the status message whether the file write was successful or not.
STEPS TO SUCCESS
Step 1 “Starting Up” ->
Create new sbt project in intellij.
Step 2 “Including required dependencies and plugins” ->
a). libraryDependencies += “org.scalatest” %% “scalatest” % “2.2.4” % “test”
It includes the scalatest jar to project which facilitates code testing(add in build.sbt).
Also following plugins were used in the project (add in plugins.sbt)
a). addSbtPlugin(“org.scoverage” % “sbt-scoverage” % “1.3.5”)
Used to see the code coverage by unit tests
b). addSbtPlugin(“org.scalastyle” %% “scalastyle-sbt-plugin” % “0.8.0”)
this plugin checks if any scalastyle warning is present or not.
Step 3 “Creating Desired Directory Structure” ->
The following image shows the directory structure of the project :
In ‘main’, the ‘scala’ sub-folder contains the implementation for our custom string interpolator and the ‘test’ sub-folder contains the test cases to test our implementation, the ‘resources’ folder contains the file ‘output’ in which the output is written.
Step 4 “Defining custom string interpolator” ->
Since all the String Interpolation methods are present in ‘StringContext’ class, our goal is to write code to add a new method to ‘StringContext’ (in this new method, we define what our custom interpolator does). We will achieve it using an implicit value class. Using an implicit class provides a more convenient syntax for defining extension methods(since we need not explicitly declare the class objects), while value classes do the job of adding new functionality to a class along with removing the run time overhead. A good example is the RichInt class in the standard library.
At compile time, the string literal of the form :
id”something1 $something2 something3″
is transformed into following call using compile time reflection :-
new StringContext(“something1 “,” something3″).id(something2)
‘something1 ‘ and ‘ something3’ are refered as ‘parts'(i.e. the number of parts a string breaks in while making a call to a string interpolator) and ‘something2’ is refered as ‘args'(argument to the string interpolation method) in the example below.
Now to make our own interpolator we create a class that adds a new method to ‘StringContext’ class
In above code the ‘WriteScore’ class is a value class since it extends from Anyval and it is declared as implicit so we do not need to explicitly instantiate the class to use its methods. ‘write’ method is our custom interpolator, it is similar to the ‘s interpolator’ i.e. it first process the string using ‘treatEscapes’ method of ‘StringContext’ object, then embed the variable expressions to it(by appending the string buffer) and finally write the post interpolation content to a file using ‘writeToFile’ method which returns the status whether write was successful or not.
Whenever we need this custom interpolator, we make following import :
After the import, just use the interpolator kind of syntax to use the ‘write interpolator’. It is demonstrated in the test cases.
Step 5 “Testing” (The Climax) ->
Test cases implementing the ‘write interpolator’ are as follows :-
We firstly import the implicit ‘WriteScore’ class and then use the ‘write interpolator’ just like the other interpolators provided by ‘StringContext’ class. One thing to note is that since we are processing the string here, ‘/t’ will be treated as a tab.’File written successfully’ is the status message returned when write to the file is successful. The content is written in file :
src -> test -> scala -> resources -> output
Full code is available on git :- https://github.com/knoldus/string-interpolation-example
Comments are welcomed.