Some scala tips.

Sbt

Set log level on demand

set logLevel := Level.Debug

Run single test

Source

testOnly *MySuite* // suite
test-only *MySuite* -- -z "text" // Use Only test case from suite which name contains "text"

Run App in src/test

sbt test:runMain "com.package.Main"
# or  specyfying project:
sbt project/test:runMain "com.package.Main"

Exclude transitive dependencies

val alaDependencies = Seq(
  ("org.organization" %% "common-mongo" % "1.2.3")
    .exclude("org.reactivemongo", "reactivemongo_2.13"),
  //...
)

Bloop

Runspecific tests

bloop test foo -o "*CubeCalculatorTest*" -- -z "a single test case"  # Just like in sbt

Metals

How to view JSON-RPC logs?

here

How to set ammonite/ scala version in script

Like that (source):

// scala 2.12.12
// ammonite 2.3.8

It solves bugs like ‘Error fetching Ammonite 2.3.8-4-88785969 for scala 2.12.13’.

Libraries

TODO Checkout / noteworthy

LibsDescriptionChecked
diffxCase class diffs (in tests)
pureconfigRead HOCON without boilerplate
quillTame doobie’s unsafety.

Slick - Drop tables

def dropTables(db: Database)(implicit ec: ExecutionContext) =
  Await.result(
    db.run(
      DBIO.sequence(
        schemas.map(tab =>
          sqlu"DROP TABLE IF EXISTS #${tab.baseTableRow.tableName}"
        ))), 10 seconds)

FS2

Streaming patterns with fs2

Timers

awakeEveryawake every X sec
awakeDelaysleep X sec after execution
fixedRateawakeEvery, but emit unit
fixedDelayawakeDelay, but emit unit

Misc

  • throttlemetered

Sangria

Omit / Remove / Ignore output field

It’s called ExcludeFields !

Cannot count how many times I’ve searched for it 🤦‍♂️.

Akka

  • akka-kafka streams compatibility table here

Scala - Language

Regex pattern matching

val regex = raw"hello:(.*)/(.*)".r

"hello:xe/lol" match{
    case regex(a,b) => print((a,b))
    case _ => print("nic")
}
// ("xe", "lol")

Date formatting

FormatStyleResult
“yyyy-MM-dd HH:mm”2020-12-20 15:26
FormatStyle.LONGDecember 20, 2020
FormatStyle.MEDIUMDec 20, 2020
FormatStyle.SHORT12/20/20
FormatStyle.LONGDecember 20, 2020 at 3:26:59 PM Z
FormatStyle.MEDIUMDec 20, 2020, 3:26:59 PM
FormatStyle.SHORT12/20/20, 3:26 PM
“E, MMM dd, yyyy HH:mm:ss”Sun, Dec 20, 2020 15:26:59
“E, MMM dd, yyyy”Sun, Dec 20, 2020
“HH:mm:ss”15:26:59
“HH:mm:ss VV”15:26:59 Z
“HH:mm:ss O”15:26:59 GMT
ISO_OFFSET_DATE_TIME2021-02-25T14:40:37.942581Z
formatDateFancy130th Jul 2021, 7:42 AM
import java.time.ZonedDateTime
import java.time.format.{DateTimeFormatter,FormatStyle}
// val date = ZonedDateTime.now()
val date = ZonedDateTime.ofInstant(ZonedDateTime.now.toInstant(), ZoneOffset.UTC)

def formatDateFancy1(zdt: ZonedDateTime): String = {
    def daySuffix(n: Int) = {
      require(n >= 1 && n <= 31, "illegal day of month: " + n)

      if (n >= 11 && n <= 13) {
        "th";
      } else
        (n % 10) match {
          case 1 => "st"
          case 2 => "nd"
          case 3 => "rd"
          case _ => "th"
        }
    }

    zdt.getDayOfMonth.toString + daySuffix(zdt.getDayOfMonth) + " "
    + zdt.format(DateTimeFormatter.ofPattern("MMM yyyy, K:mm a"))
  }



val formatters : List[ZonedDateTime => String] = List(
    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"),
    DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG),
    DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM),
    DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT),
    DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG),
    DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM),
    DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT),
    DateTimeFormatter.ofPattern("E, MMM dd, yyyy  HH:mm:ss"),
    DateTimeFormatter.ofPattern("E, MMM dd, yyyy"),
    DateTimeFormatter.ofPattern("HH:mm:ss"),
    DateTimeFormatter.ofPattern("HH:mm:ss VV"),
    DateTimeFormatter.ofPattern("HH:mm:ss O"),
    DateTimeFormatter.ISO_OFFSET_DATE_TIME
).map(fmt => (fmt.format _)) :+ (formatDateFancy1 _)

formatters.map(f => f(date)).reduce(_ + "\n" + _)

Other date operations

Set timezone

ZonedDateTime.now().withZoneSameInstant(ZoneOffset.ofTotalSeconds(timeZoneOffsetSeconds))

Ls files

import java.nio.file.{Files,Path,Paths}
import java.util.stream.Collectors
import scala.jdk.CollectionConverters.ListHasAsScala

val ls :List[Path] =Files
    .list(Paths.get("."))
    .collect(Collectors.toList[Path])
    .asScala.toList

ls

Trivial LRU cache

Maybe not the fastest.

import scala.jdk.CollectionConverters.MapHasAsScala
import scala.collection.mutable
import javax.annotation.concurrent.NotThreadSafe

// From https://stackoverflow.com/a/59116615
@NotThreadSafe
class LRUCache[K, V](maxEntries: Int)
  extends java.util.LinkedHashMap[K, V](100, .75f, true) {

  override def removeEldestEntry(eldest: java.util.Map.Entry[K, V]): Boolean
     = size > maxEntries

}

object LRUCache {
  def apply[K, V](maxEntries: Int): mutable.Map[K, V]
    = new LRUCache[K, V](maxEntries).asScala // thread safe??
}