Published 2013-12-01.
Last modified 2019-08-12.
Time to read: 7 minutes.
The Scala REPL and SBT console have strong competition – the Ammonite REPL. Ammonite is used by other projects, notably the Jupyter Almond kernel for Scala, which we discuss in the Almond - a Scala kernel for Jupyter lecture.
The Ammonite REPL features syntax highlighting, multi-line editing, the ability to load Maven artifacts directly in the REPL, and many other features missing in the default Scala REPL and SBT console.
Ammonite-REPL features pretty printing, many SBT bug fixes, undo, special built-in functions and more. Ammonite bundles a copy of the Scala compiler (v2.12.6) within itself, so it has no external dependency on a particular version of Scala.
Installation
Ammonite REPL works under all OSes, including Windows Subsystem for Linux (WSL). As usual, it is not recommended for native Windows.
Mac users can install Ammonite using brew:
$ brew install ammonite-repl
Because the Ammonite REPL installation instructions change frequently for other OSes, I refer you to the official documentation for that information.
Usage Tracking Is On By Default
--no-remote-logging
command-line flag or
the remoteLogging=false
argument to Main.
Launching Ammonite From bash
You can run the Ammonite REPL by typing amm
at the command prompt.
The Ammonite prompt is the @
sign.
$ amm Compiling (synthetic)/ammonite/predef/interpBridge.sc Compiling (synthetic)/ammonite/predef/replBridge.sc Compiling (synthetic)/ammonite/predef/DefaultPredef.sc Compiling /home/mslinn/.ammonite/predef.sc Welcome to the Ammonite Repl 1.1.2 (Scala 2.12.6 Java 1.8.0_201) If you like Ammonite, please support our development at www.patreon.com/lihaoyi
Type Ctrl-D to exit Ammonite REPL.
Adding Dependencies
Unlike SBT, which requires several files to define a project before the SBT console is ready, the Ammonite REPL allows you to specify all your settings and dependencies in the interactive session.
The Ammonite REPL uses a different syntax than SBT to specify dependencies.
In fact, Ammonite REPL has several ways to specify dependencies.
We will look at the import $ivy
syntax in a moment.
sbt-ammonite-classpath
sbt-ammonite-classpath
can export an SBT project’s classpath for use with Ammonite and Almond.To use it, add the following to project/plugins.sbt
:
addSbtPlugin("com.thoughtworks.deeplearning" % "sbt-ammonite-classpath" % "1.0.5")
Now you can invoke sbt from the command line; here sbt is invoked for the courseNotes
project:
$ sbt Compile/fullClasspath/exportToAmmoniteScript
This creates a file called target/scala-2.13/fullClasspath-Compile.sc
(note that the Scala compiler version is encoded into the file name).
The file looks like this:
{ { if (!_root_.ammonite.ops.exists(_root_.ammonite.ops.Path("/mnt/c/work/course_scala_intro_code/courseNotes/target/scala-2.13/classes"))) { _root_.ammonite.ops.mkdir(_root_.ammonite.ops.Path("/mnt/c/work/course_scala_intro_code/courseNotes/target/scala-2.13/classes")) } if (!_root_.ammonite.ops.exists(_root_.ammonite.ops.Path("/home/mslinn/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.1/scala-library-2.13.1.jar"))) { _root_.ammonite.ops.mkdir(_root_.ammonite.ops.Path("/home/mslinn/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.1/scala-library-2.13.1.jar")) } } interp.load.cp(Seq(_root_.ammonite.ops.Path("/mnt/c/work/course_scala_intro_code/courseNotes/target/scala-2.13/classes"), _root_.ammonite.ops.Path("/home/mslinn/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.1/scala-library-2.13.1.jar")))
Now you can launch Ammonite and point it to that file:
$ amm --predef target/scala-2.13/fullClasspath-Compile.sc Loading... Compiling /mnt/c/work/course_scala_intro_code/courseNotes/target/scala-2.13/fullClasspath-Compile.sc Welcome to the Ammonite Repl 1.6.9 (Scala 2.13.0 Java 1.8.0_232-ea) If you like Ammonite, please support our development at www.patreon.com/lihaoyi @
You can also use an import
statement instead of a command-line parameter to achieve the same result:
$ amm< Loading... Welcome to the Ammonite Repl 1.6.9 (Scala 2.13.0 Java 1.8.0_232-ea) If you like Ammonite, please support our development at www.patreon.com/lihaoyi @ import $file.target.`scala-2.13`.`fullClasspath-Compile` Compiling /mnt/c/work/course_scala_intro_code/courseNotes/target/scala-2.13/fullClasspath-Compile.sc import $file.$
Example: Jsoup
Here is an example of adding the Jsoup dependency to an Ammonite REPL session, then the dependency is used to extract information from a web page.
Ammonite uses backticks to surround the dependency specification, and single or double colons instead of percent signs.
We learned in the SBT Global Setup lecture
that SBT uses %%
to denote a Scala dependency whose name must be mangled to reference the version which
matches the version of the Scala compiler used in the project. Ammonite uses ::
for the same purpose.
Jsoup was written in Java, not Scala, so referencing this dependency does not require name mangling,
which is why only one colon was used to separate the Maven group
("org.jsoup
") from the Maven name ("jsoup
").
Another difference is that Ammonite does not require quoted strings like SBT does.
Both Ammonite and SBT console allow code that uses the dependency to be typed in interactively.
We started amm
a moment ago, so let’s continue typing:
@ import $ivy.`org.jsoup:jsoup:1.11.3` :: loading settings :: url = jar:file:/usr/local/bin/amm!/org/apache/ivy/core/settings/ivysettings.xml :: resolving dependencies ... voluminous output not shown ...
Now we are ready to read the web page into a variable called html
.
I used
scala.io.Source.fromURL
to read the contents of a URL, then converted the collection of characters into a string with
mkString
.
The Collections Overview
lecture of the Intermediate Scala course discusses mkString
in detail.
@ import scala.io.Source._ import scala.io.Source._
@ val html: String = fromURL("https://www.scalacourses.com").mkString html: String = """<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Scala Training Online</title>
<meta property="og:locale" content="en_US" /> <meta property="og:type" content="article" /> <meta property="og:title" content="Scala Training Online" /> <meta property="og:site_name" content="ScalaCourses.com" /> <meta property="og:url" content="https://ScalaCourses.com/" /> <link rel="canonical" href="https://ScalaCourses.com/" /> <script src=’https://cdn.jsdelivr.net/webjars/jquery/1.11.1/jquery.min.js’></script> <script src=’https://cdn.jsdelivr.net/webjars/jquery-cookie/1.4.1/jquery.cookie.js’></script> <script src=’https://cdn.jsdelivr.net/webjars/jquery-ui/1.11.1/jquery-ui.min.js’></script> <script src=’https://cdn.jsdelivr.net/webjars/bootstrap/2.3.2/js/bootstrap.min.js’></script> <script src=’https://cdn.jsdelivr.net/webjars/bootstrap-datepicker/1.0.1/js/bootstrap-datepicker.js’></script> <script src=’https://cdn.jsdelivr.net/webjars/jwerty/0.3.2/jwerty.js’></script> <link href=’https://cdn.jsdelivr.net/webjars/jquery-ui-themes/1.10.3/redmond/jquery-ui.min.css’ rel="stylesheet" /> <link href=’https://cdn.jsdelivr.net/webjars/jquery-ui-themes/1.10.3/redmond/jquery.ui.theme.css’ rel="stylesheet" /> <link href=’https://cdn.jsdelivr.net/webjars/bootstrap/2.3.2/css/bootstrap.min.css’ rel="stylesheet" /> <link href=’https://cdn.jsdelivr.net/webjars/bootstrap/2.3.2/css/bootstrap-responsive.min.css’ rel="stylesheet" /> <link href=’https://cdn.jsdelivr.net/webjars/bootstrap-datepicker/1.0.1/css/datepicker.css’ rel="stylesheet" /> ... """
Now that we have captured all of the HTML from the web page,
let’s make a Jsoup Document
from the HTML so we can extract information from it:
@ val doc = org.jsoup.Jsoup.parse(html) doc: org.jsoup.nodes.Document = <!doctype html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Scala Training Online</title> <meta property="og:locale" content="en_US"> <meta property="og:type" content="article"> <meta property="og:title" content="Scala Training Online"> <meta property="og:site_name" content="ScalaCourses.com"> <meta property="og:url" content="https://ScalaCourses.com/"> <link rel="canonical" href="https://ScalaCourses.com/"> <script src="https://cdn.jsdelivr.net/webjars/jquery/1.11.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/webjars/jquery-cookie/1.4.1/jquery.cookie.js"></script> <script src="https://cdn.jsdelivr.net/webjars/jquery-ui/1.11.1/jquery-ui.min.js"></script> <script src="https://cdn.jsdelivr.net/webjars/bootstrap/2.3.2/js/bootstrap.min.js"></script> <script src="https://cdn.jsdelivr.net/webjars/bootstrap-datepicker/1.0.1/js/bootstrap-datepicker.js"></script> <script src="https://cdn.jsdelivr.net/webjars/jwerty/0.3.2/jwerty.js"></script> <link href="https://cdn.jsdelivr.net/webjars/jquery-ui-themes/1.10.3/redmond/jquery-ui.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/webjars/jquery-ui-themes/1.10.3/redmond/jquery.ui.theme.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/webjars/bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/webjars/bootstrap/2.3.2/css/bootstrap-responsive.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/webjars/bootstrap-datepicker/1.0.1/css/datepicker.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/webjars/dropzone/4.2.0/min/dropzone.min.css" rel="stylesheet"> <script src="/javascriptRoutes"></script> <link href="https://siteassets.scalacourses.com/stylesheets/docs.css" rel="stylesheet"> ...
Extracting the title is easy:
@ val title = doc.select("title").text title: String = "Scala Training Online"
We can do more! Let’s extract all the headings (H1 to H6). To do this I’m again jumping ahead to material that is covered in detail in the Mutable Collections lecture of the Intermediate Scala course. All I’m doing is converting a Java array to a Scala array, and then turning it into a formatted string:
@ val headings = doc.select("h1, h2, h3, h4, h5, h6, h7").eachText().asScala headings: scala.collection.mutable.Buffer[String] = Buffer(Scala Training Online, Get Scala - Click and Find Out How!, Unique Partnership with Lightbend, Accolades, 20% Off Your 2nd and 3rdEnrollments!, Get Scala - Click and Find Out How!, Accolades, Core Scala Courses, Introduction to Scala $495usd, Intermediate Scala $495usd, Play Framework Courses, Introduction to Play Framework for Scala $495usd) @ headings.mkString(" ", "\n ", "") res0: collection.mutable.Buffer[String] = ArrayBuffer( "Scala Training Online", "Get Scala - Click and Find Out How!", "Unique Partnership with Lightbend", "Accolades", "20% Off Your 2nd and 3rd Enrollments!", "Get Scala - Click and Find Out How!", "Accolades", "Core Scala Courses", "Introduction to Scala $495usd", "Intermediate Scala $495usd", "Play Framework Courses", "Introduction to Play Framework for Scala $495usd" )
Exit the Ammonite REPL by typing Ctrl-D.
@ Ctrl-D Bye!
Ammonite Script
This same code can be saved to a file and executed using Ammonite.
I’ve provided this as a file called jsoup.sc
in the git repository:
/** Extract title and headings from a URL. */
// See https://jsoup.org/ import $ivy.`org.jsoup:jsoup:1.11.3`
import scala.io.Source._ val html: String = fromURL("https://www.scalacourses.com").mkString val doc = org.jsoup.Jsoup.parse(html) val title = doc.select("title").text println(s"""title="$title"""")
import scala.collection.JavaConverters._ val headings = doc.select("h1, h2, h3, h4, h5, h6, h7").eachText().asScala println("headings:\n" + headings.mkString(" ", "\n ", ""))
Run the script like this:
$ amm path/to/course_scala_intro_code/jsoup.sc Compiling (synthetic)/ammonite/predef/interpBridge.sc Compiling (synthetic)/ammonite/predef/DefaultPredef.sc Compiling /mnt/c/work/cadenzaHome/cadenzaCode/student/group_scalaCore/course_scala_intro_code/jsoup.sc title="Scala Training Online" headings: Scala Training Online Get Scala - Click and Find Out How! Unique Partnership with Lightbend Accolades 20% Off Your 2nd and 3rd Enrollments! Get Scala - Click and Find Out How! Accolades Core Scala Courses Introduction to Scala $495usd Intermediate Scala $495usd Play Framework Courses Introduction to Play Framework for Scala $495usd
Ammonite Script with main
The jsoup.sc script works fine for the one web site that it is hard-coded to work with,
but if you would like to pass it a URL to fetch we’ll need to modify it so that it implements a main
method.
Here is jsoupMain.sc
, with the main
method highlighted in yellow.
I also added a test (shown in orange) to ensure that a URL was in fact provided by the user.
/** Extract title and headings from a given URL. * Call like this: * amm jsoup.sc https://www.scalacourses.com */
// See https://jsoup.org/ import $ivy.`org.jsoup:jsoup:1.11.3`
def help(msg: String = ""): Nothing = { Console.err.println(msg) sys.exit(1) }
@main def main(args: String*): Unit = { if (args.isEmpty) help("Error: No URL was provided.\n")
import scala.io.Source._ val html: String = fromURL(args(0)).mkString
val doc = org.jsoup.Jsoup.parse(html) val title = doc.select("title").text println(s"""title="$title"""")
import scala.collection.JavaConverters._ val headings = doc.select("h1, h2, h3, h4, h5, h6, h7").eachText().asScala println("headings:\n" + headings.mkString(" ", "\n ", "")) }
Let’s run it:
$ amm jsoupMain.sc https://www.getscala.com title="Get Scala / Play Training at ScalaCourses.com" headings: About ScalaCourses.com Unique Partnership with Lightbend More Course Authors and Trainers Needed! Accolades Learning Scala & Play Framework Compare Learning Options Enroll 20% Off Your 2nd and 3rd Enrollments Individuals – Self-Study Extending Your Enrollments Individuals – Instructor-Led Teams – Self-Study and Instructor-Led Training Online Instructor-Led Training Preparing For Office Hours How Time Slots Are Allocated to Office Hours Work With Us! Independent Sales Representatives About You Responsibilities
Jsoup sbt Console Equivalent
Now lets do the same thing using a typical SBT project.
First we need to create a project using the sbtTemplate
script,
discussed in the SBT Project Setup lecture.
I created my new project called blah
in ~/work
:
$ cd ~/work
$ sbtTemplate soupsOn remote: Enumerating objects: 30, done. remote: Counting objects: 100% (30/30), done. remote: Compressing objects: 100% (21/21), done. remote: Total 401 (delta 9), reused 23 (delta 6), pack-reused 371 Receiving objects: 100% (401/401), 61.96 KiB | 1.44 MiB/s, done. Resolving deltas: 100% (198/198), done. Initialized empty Git repository in /mnt/c/work/soupsOn/.git/ Remember to edit README.md and build.sbt ASAP
$ cd soupsOn
Now add a Jsoup dependency to the libraryDependencies
section of build.sbt
.
Be sure to follow the line with a comma, in order to make a properly formatted list of dependencies:
"org.jsoup" %% "jsoup" % "1.11.3",
When you are done, that portion of build.sbt
should look like this:
libraryDependencies ++= Seq( "org.jsoup" %% "jsoup" % "1.11.3", "org.scalatest" %% "scalatest" % "3.1.0-SNAP9" % Test withSources(), "junit" % "junit" % "4.12" % Test )
Now that the SBT project is ready, we can perform the same computation as we did with Ammonite REPL using SBT console:
$ sbt console [info] Loading settings for project global-plugins from idea.sbt ... [info] Loading global plugins from /home/mslinn/.sbt/1.0/plugins [info] Loading settings for project soupson-build from build.sbt,plugins.sbt ... [info] Loading project definition from /mnt/c/work/soupsOn/project [info] Loading settings for project soupson from build.sbt,eclipse.sbt ... [info] Set current project to sbt-template (in build file:/mnt/c/work/soupsOn/) https://repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.2.0/scala-xml_2.12-1.2.0.jar 100.0% [##########] 543.5 KiB (252.2 KiB / s) https://repo1.maven.org/maven2/org/scalactic/scalactic_2.12/3.1.0-SNAP9/scalactic_2.12-3.1.0-SNAP9.jar 100.0% [##########] 1.5 MiB (325.9 KiB / s) https://repo1.maven.org/maven2/org/scalatest/scalatest_2.12/3.1.0-SNAP9/scalatest_2.12-3.1.0-SNAP9-sources.jar 100.0% [##########] 1.6 MiB (321.1 KiB / s) Welcome to Scala 2.12.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_201). Type in expressions for evaluation. Or try :help.
Now we are ready to read the web page into a variable called html
just as before with Ammonite.
scala> import scala.io.Source._ scala.io.Source._
scala> val html: String = fromURL("https://www.scalacourses.com").mkString html: String = "<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Scala Training Online</title>
<meta property="og:locale" content="en_US" /> <meta property="og:type" content="article" /> <meta property="og:title" content="Scala Training Online" /> <meta property="og:site_name" content="ScalaCourses.com" /> <meta property="og:url" content="https://ScalaCourses.com/" /> <link rel="canonical" href="https://ScalaCourses.com/" /> <script src=’https://cdn.jsdelivr.net/webjars/jquery/1.11.1/jquery.min.js’></script> <script src=’https://cdn.jsdelivr.net/webjars/jquery-cookie/1.4.1/jquery.cookie.js’></script> <script src=’https://cdn.jsdelivr.net/webjars/jquery-ui/1.11.1/jquery-...
Now that we have captured all of the HTML from the web page,
let’s make a Jsoup Document
from the HTML so we can extract information from it:
scala> val doc = org.jsoup.Jsoup.parse(html) doc: org.jsoup.nodes.Document = <!doctype html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Scala Training Online</title> <meta property="og:locale" content="en_US"> <meta property="og:type" content="article"> <meta property="og:title" content="Scala Training Online"> <meta property="og:site_name" content="ScalaCourses.com"> <meta property="og:url" content="https://ScalaCourses.com/"> <link rel="canonical" href="https://ScalaCourses.com/"> <script src="https://cdn.jsdelivr.net/webjars/jquery/1.11.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/webjars/jquery-cookie/1.4.1/jquery.cookie.js"></script> <script src="https://cdn.jsdelivr.net/webjars/jquery-ui/1.11.1/jquery-..."
Again, extracting the title is easy:
scala> val title = doc.select("title").text title: String = Scala Training Online
Now let’s extract all the headings as before:
scala> import scala.collection.JavaConverters._ import scala.collection.JavaConverters._
scala> val headings = doc.select("h1, h2, h3, h4, h5, h6, h7").eachText().asScala headings: scala.collection.mutable.Buffer[String] = Buffer(Scala Training Online, Get Scala - Click and Find Out How!, Unique Partnership with Lightbend, Accolades, 20% Off Your 2nd and 3rdEnrollments!, Get Scala - Click and Find Out How!, Accolades, Core Scala Courses, Introduction to Scala $495usd, Intermediate Scala $495usd, Play Framework Courses, Introduction to Play Framework for Scala $495usd)
scala> headings.mkString(" ", "\n ", "") res1: String = " Scala Training Online Get Scala - Click and Find Out How! Unique Partnership with Lightbend Accolades 20% Off Your 2nd and 3rd Enrollments! Get Scala - Click and Find Out How! Accolades Core Scala Courses Introduction to Scala $495usd Intermediate Scala $495usd Play Framework Courses Introduction to Play Framework for Scala $495usd"
Exit the SBT console by typing Ctrl-D.
It is easy to see that Ammonite is a lot more convenient to experiment with than SBT.
SBT console also has no mechanism to support a main
method.
Example: Apache Commons IO
Here is another example that specifies the Apache Commons IO project as a dependency.
This dependency was written in Java, not Scala, so referencing this dependency does not require name mangling,
which is why only one colon was used to separate the Maven group ("commons-io
")
from the Maven name (also called "commons-io
").
I then use the FileUtils
class from Commons IO to read a file into a string.
If you want to type along, first change to the courseNotes/
directory.
$ amm Loading... Welcome to the Ammonite Repl 1.1.2 (Scala 2.12.6 Java 1.8.0_201) If you like Ammonite, please support our development at www.patreon.com/lihaoyi
@ import $ivy.`commons-io:commons-io:2.5` import $ivy.$
@ import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
@ import java.io.File import java.io.File
@ val str = FileUtils.readFileToString(new File("build.sbt"), "UTF-8") str: String = """ organization := "com.micronautics" name := "IntroScalaCourse" description := "Core Scala - Introduction to Scala Course Notes" scalaVersion := "2.12.8" version := scalaVersion.value autoCompilerPlugins := true scalacOptions in (Compile, doc) ++= baseDirectory.map { (bd: File) => Seq[String]( "-deprecation", "-encoding", "UTF-8", "-feature", "-target:jvm-1.8", "-unchecked", "-Ywarn-adapted-args", "-Ywarn-dead-code", "-Ywarn-numeric-widen", "-Ywarn-unused", "-Ywarn-value-discard", "-Xfuture", "-Xlint" ) }.value ... """
Exit the SBT console
by typing Ctrl-D.
Now lets do the same thing using a typical SBT project.
Again, you could use the sbtTemplate
script to create the initial SBT project.
I created my new project called blah2
in /var/work
:
$ sbtTemplate blah2 Cloning into ’blah2’... remote: Counting objects: 181, done. remote: Compressing objects: 100% (6/6), done. remote: Total 181 (delta 2), reused 0 (delta 0), pack-reused 175 Receiving objects: 100% (181/181), 21.39 KiB | 0 bytes/s, done. Resolving deltas: 100% (80/80), done. Checking connectivity... done. Initialized empty Git repository in /var/work/blah2/.git/ Remember to edit README.md and build.sbt ASAP
$ cd blah2
Now add the following to the libraryDependencies
section.
Be sure to follow the line with a comma, in order to make a properly formatted list of dependencies:
"commons-io" % "commons-io" % "2.5",
The SBT console could then be launched:
$ sbt console [info] Loading global plugins from /home/mslinn/.sbt/0.13/plugins [info] Loading project definition from /var/work/blah2/project [info] Updating {file:/var/work/blah2/}coursenotes-build... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. [info] Set current project to IntroScalaCourse (in build file:/var/work/blah2/) [info] Updating {file:/var/work/blah2/}coursenotes... [info] Resolving org.apache#apache;16 ... [info] Done updating. [info] Starting scala interpreter... [info] Welcome to Scala 2.12.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_74). Type in expressions for evaluation. Or try :help.
scala> import org.apache.commons.io.FileUtils
scala> import java.io.File import java.io.File
scala> val str = FileUtils.readFileToString(new File("build.sbt"), "UTF-8") str: String = "organization := "com.micronautics"
name := "change-me"
version := "0.1.6"
scalaVersion := "2.12.8"
scalacOptions ++= Seq( "-deprecation", "-encoding", "UTF-8", "-feature", "-target:jvm-1.8", "-unchecked", "-Ywarn-adapted-args", "-Ywarn-dead-code", "-Ywarn-numeric-widen", "-Ywarn-unused", "-Ywarn-value-discard", "-Xfuture", "-Xlint" )
scalacOptions in (Compile, doc) ++= baseDirectory.map { (bd: File) => Seq[String]( "-sourcepath", bd.getAbsolutePath, "-doc-source-url", "https://github.com/mslinn/changeMe/tree/master├ó¬{FILE_PATH}.scala" ) }.value
javacOptions ++= Seq( "-Xlint:deprecation", "-Xlint:unchecked", "-source", "1.8", "-target", "1.8", "-g:vars" )
resolvers ++= Seq( )
libraryDependencies ++= Seq( "commons-io"...)
Exit the SBT console
by typing Ctrl-D.
Example: Google Guava
I will write this up soon, it is a bit advanced for where we are right now...
$ amm Loading... Welcome to the Ammonite Repl 1.1.2 (Scala 2.12.6 Java 1.8.0_201) If you like Ammonite, please support our development at www.patreon.com/lihaoyi
@ import $ivy.`com.google.guava:guava:27.1-jre` ... lots of output ...
@ import com.google.common.base.{ CharMatcher, Splitter } import com.google.common.base.{ CharMatcher, Splitter }
@ import scala.collection.JavaConverters._ import scala.collection.JavaConverters._
@ val line = """.TH man 1 "03 May 2019" "1.0" "cad-lecture man page"""" line: String = ".TH man 1 \"03 May 2019\" \"1.0\" \"cad-lecture man page\""
@ val tokens: List[String] = Splitter.on(","). trimResults(CharMatcher.is(’"’)). split(line). asScala. toList tokens: List[String] = List(".TH", "man", "1", "03", "May", "2019", "1.0", "cad-lecture", "man", "page")
@ tokens. zipWithIndex. foreach { case (x, i) => println(s"$i: $x") } 0: .TH 1: man 2: 1 3: 03 4: May 5: 2019 6: 1.0 7: cad-lecture 8: man 9: page
@ case class Th(section: String, dateStr: String, version: String, command: String) defined class Th
@ Th(tokens(2), s"${ tokens(3) } ${ tokens(4) } ${ tokens(5) }", tokens(6), tokens(7)) res0: Th = Th("1", "03 May 2019", "1.0", "cad-lecture")
Trailing Dots
Here is a similar Ammonite script, provided as guava.sc
.
The last expression has a dot, or period, at the end of every line.
The dot acts as a continuation character so Ammonite interprets the next line as part of the current line.
import $ivy.`com.google.guava:guava:27.1-jre` import scala.collection.JavaConverters._ import com.google.common.base.Splitter import java.util.regex.Pattern val tokenizerPattern: Pattern = Pattern.compile("[ \r\n]") val lineB: String = """.B Something Else blah """.stripMargin val split=Splitter. on(tokenizerPattern). split(lineB). asScala. toList
Most people would write the last expression the way shown below, with leading dots, in a .scala
file.
I do too, but for Ammonite I adjust as shown above:
val split=Splitter .on(tokenizerPattern) .split(lineB) .asScala .toList
Clipboard Support
Ammonite can read your clipboard text, process it and write the results back to the clipboard. This example shows how Circe is used to add a field to a JSON copied from Wikipedia.
Excluding Dependencies With Ammonium (Supplemental)
The SBT Tasks and Settings
lecture described two ways of excluding transitive dependencies.
Ammonium,
a fork of Ammonite used by the Almond Scala kernel for Jupyter,
has an equivalent to SBT’s exclude()
syntax: import $exclude
.
At the time of writing this lecture,
Ammonium’s enhancements were under consideration to be folded back into a future version of Ammonite.
To refresh your memory, here is how to exclude the joda-time dependency that NScala-Time transitively includes using SBT:
"com.github.nscala-time" %% "nscala-time" % "2.4.0" exclude("joda-time", "joda-time")
Here is how to accomplish the same thing using Ammonium REPL:
import $exclude.`joda-time:joda-time`
If you want Ammonium to exclude multiple transitive dependencies, separate them with commas, like this:
import $exclude.`maven-group1:maven-id1`, $ivy.`maven-group2:maven-id2:optionalVersion`, $ivy.`maven-group3:maven-id3`
Notice that the first transitive dependency was prefaced with $exclude
,
while the remainder were prefaced with $ivy
.
The second transitive dependency specified an optional version for that dependency.
Replacing the SBT Test Console with Ammonite
You can also use the Ammonite REPL as a replacement for the standard SBT console,
but I recommend that you limit its use to test:console
instead.
Because Ammonite is revised frequently, I suggest you do not hard-code a specific version in libraryDependencies
;
instead, use latest.integration
, which is one of
Ivy’s dynamic version specifiers.
To enable Ammonite-REPL:
-
For all of your SBT projects, add the following to
~/.sbt/0.13/ammonite.sbt
– as you know, the exact name does not matter, so long as the file type issbt
:build.sbt fragmentlibraryDependencies += "com.lihaoyi" % "ammonite" % "latest.integration" % "test" cross CrossVersion.full
initialCommands in (Test, console) := "ammonite.Main().run()"test:console
now uses Ammonite-REPL, while the regular console continues to use the default SBT REPL. This is done so Ammonite-REPL is not declared to be a runtime dependency of every one of your projects.
Here is how you can use Ammonite-REPL withtest:console
. Wait a few seconds until you see the “Welcome to the Ammonite Repl” message before typing, or your input will be lost.Shell$ sbt test:console
... lots of output ...
[info] Starting scala interpreter... [info] Loading... Welcome to the Ammonite Repl 0.8.1 (Scala 2.11.8 Java 1.8.0_111) @ -
If you don’t want to make Ammonite available to every SBT project,
put a copy of
ammonite.sbt
in the SBT project directories that you wish to provide Ammonite to, instead of placing one copy in~/.sbt/0.13/
. -
If you don’t mind adding Ammonite as a runtime dependency, don’t specify
% test
, modifyinitialCommands
so it applies to the non-test console and instead of typingtest:console
to launch Ammonite, just typesbt console
.build.sbtlibraryDependencies += "com.lihaoyi" % "ammonite-repl" % "latest.integration" cross CrossVersion.full
initialCommands in console := "ammonite.Main().run()"
Exit test:console
by typing Ctrl-D.
If you installed the Ctrl-C trap discussed in the
SBT Tasks and Settings lecture,
there would be no other way to exit.
© Copyright 1994-2024 Michael Slinn. All rights reserved.
If you would like to request to use this copyright-protected work in any manner,
please send an email.
This website was made using Jekyll and Mike Slinn’s Jekyll Plugins.