From 18f165eb4894033681739658f7cafcef4ed77dc7 Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Fri, 4 Aug 2023 15:19:30 +0200 Subject: [PATCH] refactor: update sbt-by-example I love this guide. I always recommend it to new people getting starting with sbt. The last couple times I did however they always came back to me ab out certain things not working anymore, mainly the console examples. I decided to just go through the whole thing myself and update all of the examples using a more modern sbt version and updating the output to match. There is also a couple other choices that I made while updating things like: - Changing the weather site we use as an example since it no longer is active - Changing the libraries being used from gigahorse to sttp and Play JSON to uJson. I didn't do this _just because_ but rather to more align with the libraries that are being used by the scala toolkit. Hopefully people will be a bit more familiar with these as I don't assume a newcomer to Scala will be using gigahorse or really Play JSON _unless_ they are using Play!. If this isn't ok, let me know and I can try to recreate it using the old libraries, but I think these examples are clearer. --- .../00-Getting-Started/02-sbt-by-example.md | 246 ++++++++-------- .../00-Getting-Started/02-sbt-by-example.md | 259 +++++++++-------- .../00-Getting-Started/02-sbt-by-example.md | 273 +++++++++--------- src/sbt-test/ref/example-library/build.sbt | 11 +- src/sbt-test/ref/example-scalatest/build.sbt | 5 +- .../test/scala/{ => example}/HelloSpec.scala | 0 src/sbt-test/ref/example-scalatest/test | 2 +- src/sbt-test/ref/example-sub1/build.sbt | 15 +- src/sbt-test/ref/example-sub2/build.sbt | 17 +- src/sbt-test/ref/example-sub3/build.sbt | 17 +- src/sbt-test/ref/example-sub4/build.sbt | 17 +- src/sbt-test/ref/example-weather/build.sbt | 21 +- .../ref/example-weather/changes/build.sbt | 21 +- .../ref/example-weather/changes/build3.sbt | 23 +- .../ref/example-weather/changes/plugins.sbt | 2 +- .../src/main/scala/example/core/Weather.scala | 31 +- .../src/main/scala/example/Hello.scala | 8 +- .../ref/example-weather/{pending => test} | 0 18 files changed, 497 insertions(+), 471 deletions(-) rename src/sbt-test/ref/example-scalatest/src/test/scala/{ => example}/HelloSpec.scala (100%) rename src/sbt-test/ref/example-weather/{pending => test} (100%) diff --git a/src/reference/00-Getting-Started/02-sbt-by-example.md b/src/reference/00-Getting-Started/02-sbt-by-example.md index 018823783..4df3ebad9 100644 --- a/src/reference/00-Getting-Started/02-sbt-by-example.md +++ b/src/reference/00-Getting-Started/02-sbt-by-example.md @@ -26,11 +26,13 @@ Let's start with examples rather than explaining how sbt works or why. ``` \$ sbt -[info] Updated file /tmp/foo-build/project/build.properties: set sbt.version to 1.1.4 +[info] Updated file /tmp/foo-build/project/build.properties: set sbt.version to 1.9.3 +[info] welcome to sbt 1.9.3 (Eclipse Adoptium Java 17.0.8) [info] Loading project definition from /tmp/foo-build/project -[info] Loading settings from build.sbt ... +[info] loading settings for project foo-build from build.sbt ... [info] Set current project to foo-build (in build file:/tmp/foo-build/) [info] sbt server started at local:///Users/eed3si9n/.sbt/1.0/server/abc4fb6c89985a00fd95/sock +[info] started sbt server sbt:foo-build> ``` @@ -58,8 +60,9 @@ re-executed whenever one of the source files within the project is modified. For ``` sbt:foo-build> ~compile -[success] Total time: 0 s, completed May 6, 2018 3:52:08 PM -1. Waiting for source changes... (press enter to interrupt) +[success] Total time: 0 s, completed 28 Jul 2023, 13:32:35 +[info] 1. Monitoring source files for foo-build/compile... +[info] Press to interrupt or '?' for more options. ``` ### Create a source file @@ -81,10 +84,11 @@ object Hello { This new file should be picked up by the running command: ``` -[info] Compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/classes ... -[info] Done compiling. -[success] Total time: 2 s, completed May 6, 2018 3:53:42 PM -2. Waiting for source changes... (press enter to interrupt) +[info] Build triggered by /tmp/foo-build/src/main/scala/example/Hello.scala. Running 'compile'. +[info] compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/classes ... +[success] Total time: 0 s, completed 28 Jul 2023, 13:38:55 +[info] 2. Monitoring source files for foo-build/compile... +[info] Press to interrupt or '?' for more options. ``` Press `Enter` to exit `~compile`. @@ -105,13 +109,14 @@ Use the `help` command to get basic help about the available commands. ``` sbt:foo-build> help - about Displays basic information about sbt and the build. - tasks Lists the tasks defined for the current project. - settings Lists the settings defined for the current project. - reload (Re)loads the current project or changes to plugins project or returns from it. - new Creates a new sbt build. - projects Lists the names of available projects or temporarily adds/removes extra builds to the session. - project Displays the current project or changes to the provided `project`. + (; )* Runs the provided semicolon-separated commands. + about Displays basic information about sbt and the build. + tasks Lists the tasks defined for the current project. + settings Lists the settings defined for the current project. + reload (Re)loads the current project or changes to plugins project or returns from it. + new Creates a new sbt build. + new Creates a new sbt build. + projects Lists the names of available projects or temporarily adds/removes extra builds to the session. .... ``` @@ -127,11 +132,9 @@ Runs a main class, passing along arguments provided on the command line. ``` sbt:foo-build> run -[info] Packaging /tmp/foo-build/target/scala-2.12/foo-build_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Running example.Hello +[info] running example.Hello Hello -[success] Total time: 1 s, completed May 6, 2018 4:10:44 PM +[success] Total time: 0 s, completed 28 Jul 2023, 13:40:31 ``` ### Set ThisBuild / scalaVersion from sbt shell @@ -139,6 +142,10 @@ Hello ``` sbt:foo-build> set ThisBuild / scalaVersion := "$example_scala213$" [info] Defining ThisBuild / scalaVersion +[info] The new value will be used by Compile / bspBuildTarget, Compile / dependencyTreeCrossProjectId and 50 others. +[info] Run `last` for details. +[info] Reapplying settings... +[info] set current project to foo-build (in build file:/tmp/foo-build/) ``` Check the `scalaVersion` setting: @@ -155,6 +162,13 @@ We can save the ad-hoc settings using `session save`. ``` sbt:foo-build> session save [info] Reapplying settings... +[info] set current project to foo-build (in build file:/tmp/foo-build/) +[warn] build source files have changed +[warn] modified files: +[warn] /tmp/foo-build/build.sbt +[warn] Apply these changes by running `reload`. +[warn] Automatically reload the build when source changes are detected by setting `Global / onChangedBuildSource := ReloadOnSourceChanges`. +[warn] Disable this warning by setting `Global / onChangedBuildSource := IgnoreSourceChanges`. ``` `build.sbt` file should now contain: @@ -177,9 +191,10 @@ Use the `reload` command to reload the build. The command causes the ``` sbt:foo-build> reload -[info] Loading project definition from /tmp/foo-build/project -[info] Loading settings from build.sbt ... -[info] Set current project to Hello (in build file:/tmp/foo-build/) +[info] welcome to sbt 1.9.3 (Eclipse Adoptium Java 17.0.8) +[info] loading project definition from /tmp/foo-build/project +[info] loading settings for project hello from build.sbt ... +[info] set current project to Hello (in build file:/tmp/foo-build/) sbt:Hello> ``` @@ -211,35 +226,34 @@ sbt:Hello> ~testQuick ### Write a test -Leaving the previous command running, create a file named `src/test/scala/HelloSpec.scala` +Leaving the previous command running, create a file named `src/test/scala/example/HelloSpec.scala` using an editor: -@@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/src/test/scala/HelloSpec.scala) {} +@@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/src/test/scala/example/HelloSpec.scala) {} `~testQuick` should pick up the change: ``` -2. Waiting for source changes... (press enter to interrupt) -[info] Compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/test-classes ... -[info] Done compiling. +[info] 2. Monitoring source files for hello/testQuick... +[info] Press to interrupt or '?' for more options. +[info] Build triggered by /private/tmp/foo-build/src/test/scala/HelloSpec.scala. Running 'testQuick'. +[info] compiling 1 Scala source to /private/tmp/foo-build/target/scala-2.13/test-classes ... [info] HelloSpec: [info] - Hello should start with H *** FAILED *** -[info] assert("hello".startsWith("H")) -[info] | | | -[info] "hello" false "H" (HelloSpec.scala:5) -[info] Run completed in 135 milliseconds. +[info] "hello" did not start with "H" (HelloSpec.scala:5) +[info] Run completed in 44 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0 [info] *** 1 TEST FAILED *** [error] Failed tests: -[error] HelloSpec -[error] (Test / testQuick) sbt.TestsFailedException: Tests unsuccessful +[error] HelloSpec +[error] (Test / testQuick) sbt.TestsFailedException: Tests unsuccessfull ``` ### Make the test pass -Using an editor, change `src/test/scala/HelloSpec.scala` to: +Using an editor, change `src/test/scala/example/HelloSpec.scala` to: @@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/changes/HelloSpec.scala) {} @@ -260,60 +274,51 @@ We can find out the current weather in New York. ```scala sbt:Hello> console [info] Starting scala interpreter... -Welcome to Scala 2.12.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_171). +Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java 17). Type in expressions for evaluation. Or try :help. scala> :paste // Entering paste mode (ctrl-D to finish) -import scala.concurrent._, duration._ -import gigahorse._, support.okhttp.Gigahorse -import play.api.libs.json._ - -Gigahorse.withHttp(Gigahorse.config) { http => - val baseUrl = "https://www.metaweather.com/api/location" - val rLoc = Gigahorse.url(baseUrl + "/search/").get. - addQueryString("query" -> "New York") - val fLoc = http.run(rLoc, Gigahorse.asString) - val loc = Await.result(fLoc, 10.seconds) - val woeid = (Json.parse(loc) \\ 0 \\ "woeid").get - val rWeather = Gigahorse.url(baseUrl + s"/\$woeid/").get - val fWeather = http.run(rWeather, Gigahorse.asString) - val weather = Await.result(fWeather, 10.seconds) - ({Json.parse(_: String)} andThen Json.prettyPrint)(weather) -} +import sttp.client4.quick._ +import sttp.client4.Response + +val newYorkLatitude: Double = 40.7143 +val newYorkLongitude: Double = -74.006 +val response: Response[String] = quickRequest + .get( + uri"https://api.open-meteo.com/v1/forecast?latitude=\$newYorkLatitude&longitude=\$newYorkLongitude¤t_weather=true" + ) + .send() + +println(ujson.read(response.body).render(indent = 2)) // press Ctrl+D // Exiting paste mode, now interpreting. -import scala.concurrent._ -import duration._ -import gigahorse._ -import support.okhttp.Gigahorse -import play.api.libs.json._ -res0: String = { - "consolidated_weather" : [ { - "id" : 6446939314847744, - "weather_state_name" : "Light Rain", - "weather_state_abbr" : "lr", - "wind_direction_compass" : "WNW", - "created" : "2019-02-21T04:39:47.747805Z", - "applicable_date" : "2019-02-21", - "min_temp" : 0.48000000000000004, - "max_temp" : 7.84, - "the_temp" : 2.1700000000000004, - "wind_speed" : 5.996333145703094, - "wind_direction" : 293.12257757287307, - "air_pressure" : 1033.115, - "humidity" : 77, - "visibility" : 14.890539250775472, - "predictability" : 75 - }, { - "id" : 5806299509948416, - "weather_state_name" : "Heavy Cloud", -... + "latitude": 40.710335, + "longitude": -73.99307, + "generationtime_ms": 0.36704540252685547, + "utc_offset_seconds": 0, + "timezone": "GMT", + "timezone_abbreviation": "GMT", + "elevation": 51, + "current_weather": { + "temperature": 21.3, + "windspeed": 16.7, + "winddirection": 205, + "weathercode": 3, + "is_day": 1, + "time": "2023-08-04T10:00" + } +} +import sttp.client4.quick._ +import sttp.client4.Response +val newYorkLatitude: Double = 40.7143 +val newYorkLongitude: Double = -74.006 +val response: sttp.client4.Response[String] = Response({"latitude":40.710335,"longitude":-73.99307,"generationtime_ms":0.36704540252685547,"utc_offset_seconds":0,"timezone":"GMT","timezone_abbreviation":"GMT","elevation":51.0,"current_weather":{"temperature":21.3,"windspeed":16.7,"winddirection":205.0,"weathercode":3,"is_day":1,"time":"2023-08-04T10:00"}},200,,List(:status: 200, content-encoding: deflate, content-type: application/json; charset=utf-8, date: Fri, 04 Aug 2023 10:09:11 GMT),List(),RequestMetadata(GET,https://api.open-meteo.com/v1/forecast?latitude=40.7143&longitude... scala> :q // to quit ``` @@ -367,9 +372,9 @@ Use `.dependsOn(...)` to add a dependency on other subprojects. Also let's move @@snip [example-sub4]($root$/src/sbt-test/ref/example-sub4/build.sbt) {} -### Parse JSON using Play JSON +### Parse JSON using uJson -Let's add Play JSON to `helloCore`. +Let's add uJson to `helloCore`. @@snip [example-weather-build]($root$/src/sbt-test/ref/example-weather/build.sbt) {} @@ -378,29 +383,22 @@ After `reload`, add `core/src/main/scala/example/core/Weather.scala`: ```scala package example.core -import gigahorse._, support.okhttp.Gigahorse -import scala.concurrent._, duration._ -import play.api.libs.json._ +import sttp.client4.quick._ +import sttp.client4.Response object Weather { - lazy val http = Gigahorse.http(Gigahorse.config) - - def weather: Future[String] = { - val baseUrl = "https://www.metaweather.com/api/location" - val locUrl = baseUrl + "/search/" - val weatherUrl = baseUrl + "/%s/" - val rLoc = Gigahorse.url(locUrl).get. - addQueryString("query" -> "New York") - import ExecutionContext.Implicits.global - for { - loc <- http.run(rLoc, parse) - woeid = (loc \\ 0 \\ "woeid").get - rWeather = Gigahorse.url(weatherUrl format woeid).get - weather <- http.run(rWeather, parse) - } yield (weather \\\\ "weather_state_name")(0).as[String].toLowerCase + def weather() = { + val response: Response[String] = quickRequest + .get( + uri"https://api.open-meteo.com/v1/forecast?latitude=\$newYorkLatitude&longitude=\$newYorkLongitude¤t_weather=true" + ) + .send() + val json = ujson.read(response.body) + json.obj("current_weather")("temperature").num } - private def parse = Gigahorse.asString andThen Json.parse + private val newYorkLatitude: Double = 40.7143 + private val newYorkLongitude: Double = -74.006 } ``` @@ -409,14 +407,12 @@ Next, change `src/main/scala/example/Hello.scala` as follows: ```scala package example -import scala.concurrent._, duration._ -import core.Weather +import example.core.Weather object Hello { def main(args: Array[String]): Unit = { - val w = Await.result(Weather.weather, 10.seconds) - println(s"Hello! The weather in New York is \$w.") - Weather.http.close() + val temp = Weather.weather() + println(s"Hello! The current temperature in New York is \$temp C.") } } ``` @@ -425,16 +421,10 @@ Let's run the app to see if it worked: ``` sbt:Hello> run -[info] Compiling 1 Scala source to /tmp/foo-build/core/target/scala-2.12/classes ... -[info] Done compiling. -[info] Compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/classes ... -[info] Packaging /tmp/foo-build/core/target/scala-2.12/hello-core_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Done compiling. -[info] Packaging /tmp/foo-build/target/scala-2.12/hello_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Running example.Hello -Hello! The weather in New York is mostly cloudy. +[info] compiling 1 Scala source to /tmp/foo-build/core/target/scala-2.13/classes ... +[info] compiling 1 Scala source to /tmp/foo-build/target/scala-2.13/classes ... +[info] running example.Hello +Hello! The current temperature in New York is 22.7 C. ``` ### Add sbt-native-packager plugin @@ -453,8 +443,16 @@ Next change `build.sbt` as follows to add `JavaAppPackaging`: sbt:Hello> reload ... sbt:Hello> dist -[info] Wrote /tmp/foo-build/target/scala-2.12/hello_2.12-0.1.0-SNAPSHOT.pom -[info] Wrote /tmp/foo-build/core/target/scala-2.12/hello-core_2.12-0.1.0-SNAPSHOT.pom +[info] Wrote /private/tmp/foo-build/target/scala-2.13/hello_2.13-0.1.0-SNAPSHOT.pom +[info] Main Scala API documentation to /tmp/foo-build/target/scala-2.13/api... +[info] Main Scala API documentation successful. +[info] Main Scala API documentation to /tmp/foo-build/core/target/scala-2.13/api... +[info] Wrote /tmp/foo-build/core/target/scala-2.13/hello-core_2.13-0.1.0-SNAPSHOT.pom +[info] Main Scala API documentation successful. +[warn] [1] The maintainer is empty +[warn] Add this to your build.sbt +[warn] maintainer := "your.name@company.org" +[success] All package validations passed [info] Your package is ready in /tmp/foo-build/target/universal/hello-0.1.0-SNAPSHOT.zip ``` @@ -465,24 +463,24 @@ Here's how you can run the packaged app: \$ cd /tmp/someother \$ unzip -o -d /tmp/someother /tmp/foo-build/target/universal/hello-0.1.0-SNAPSHOT.zip \$ ./hello-0.1.0-SNAPSHOT/bin/hello -Hello! The weather in New York is mostly cloudy. +Hello! The current temperature in New York is 22.7 C. ``` ### Dockerize your app +_Note that a Docker daemon will need to be running in order for this to work._ + ``` sbt:Hello> Docker/publishLocal .... -[info] Successfully built b6ce1b6ab2c0 -[info] Successfully tagged hello:0.1.0-SNAPSHOT -[info] Built image hello:0.1.0-SNAPSHOT +[info] Built image hello with tags [0.1.0-SNAPSHOT] ``` Here's how to run the Dockerized app: ``` \$ docker run hello:0.1.0-SNAPSHOT -Hello! The weather in New York is mostly cloudy +Hello! The current temperature in New York is 22.7 C. ``` ### Set the version @@ -494,8 +492,8 @@ Change `build.sbt` as follows: ### Switch scalaVersion temporarily ``` -sbt:Hello> ++2.12.14! -[info] Forcing Scala version to 2.12.14 on all projects. +sbt:Hello> ++3.3.0! +[info] Forcing Scala version to 3.3.0 on all projects. [info] Reapplying settings... [info] Set current project to Hello (in build file:/tmp/foo-build/) ``` @@ -505,9 +503,9 @@ Check the `scalaVersion` setting: ``` sbt:Hello> scalaVersion [info] helloCore / scalaVersion -[info] 2.12.14 +[info] 3.3.0 [info] scalaVersion -[info] 2.12.14 +[info] 3.3.0 ``` This setting will go away after `reload`. diff --git a/src/reference/es/00-Getting-Started/02-sbt-by-example.md b/src/reference/es/00-Getting-Started/02-sbt-by-example.md index 7a3c5bf56..c51072dbd 100644 --- a/src/reference/es/00-Getting-Started/02-sbt-by-example.md +++ b/src/reference/es/00-Getting-Started/02-sbt-by-example.md @@ -27,11 +27,13 @@ o por qué sbt funciona. ``` \$ sbt -[info] Updated file /tmp/foo-build/project/build.properties: set sbt.version to 1.1.4 +[info] Updated file /tmp/foo-build/project/build.properties: set sbt.version to 1.9.3 +[info] welcome to sbt 1.9.3 (Eclipse Adoptium Java 17.0.8) [info] Loading project definition from /tmp/foo-build/project -[info] Loading settings from build.sbt ... +[info] loading settings for project foo-build from build.sbt ... [info] Set current project to foo-build (in build file:/tmp/foo-build/) [info] sbt server started at local:///Users/eed3si9n/.sbt/1.0/server/abc4fb6c89985a00fd95/sock +[info] started sbt server sbt:foo-build> ``` @@ -62,8 +64,9 @@ fuente dentro del proyecto sea modificado. Por ejemplo: ``` sbt:foo-build> ~compile -[success] Total time: 0 s, completed May 6, 2018 3:52:08 PM -1. Waiting for source changes... (press enter to interrupt) +[success] Total time: 0 s, completed 28 Jul 2023, 13:32:35 +[info] 1. Monitoring source files for foo-build/compile... +[info] Press to interrupt or '?' for more options. ``` ### Crear un fichero fuente @@ -87,10 +90,11 @@ object Hello { Este nuevo fichero debería de ser detectado por el comando en ejecución: ``` -[info] Compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/classes ... -[info] Done compiling. -[success] Total time: 2 s, completed May 6, 2018 3:53:42 PM -2. Waiting for source changes... (press enter to interrupt) +[info] Build triggered by /tmp/foo-build/src/main/scala/example/Hello.scala. Running 'compile'. +[info] compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/classes ... +[success] Total time: 0 s, completed 28 Jul 2023, 13:38:55 +[info] 2. Monitoring source files for foo-build/compile... +[info] Press to interrupt or '?' for more options. ``` Pulsa `Intro` para salir de `~compile`. @@ -111,13 +115,14 @@ Usa el comando `help` para obtener ayuda básica sobre los comandos disponibles. ``` sbt:foo-build> help - about Displays basic information about sbt and the build. - tasks Lists the tasks defined for the current project. - settings Lists the settings defined for the current project. - reload (Re)loads the current project or changes to plugins project or returns from it. - new Creates a new sbt build. - projects Lists the names of available projects or temporarily adds/removes extra builds to the session. - project Displays the current project or changes to the provided `project`. + (; )* Runs the provided semicolon-separated commands. +about Displays basic information about sbt and the build. +tasks Lists the tasks defined for the current project. +settings Lists the settings defined for the current project. +reload (Re)loads the current project or changes to plugins project or returns from it. +new Creates a new sbt build. +new Creates a new sbt build. +projects Lists the names of available projects or temporarily adds/removes extra builds to the session. .... ``` @@ -133,11 +138,9 @@ Runs a main class, passing along arguments provided on the command line. ``` sbt:foo-build> run -[info] Packaging /tmp/foo-build/target/scala-2.12/foo-build_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Running example.Hello +[info] running example.Hello Hello -[success] Total time: 1 s, completed May 6, 2018 4:10:44 PM +[success] Total time: 0 s, completed 28 Jul 2023, 13:40:31 ``` ### Establecer `ThisBuild / scalaVersion` desde el shell de sbt @@ -145,6 +148,10 @@ Hello ``` sbt:foo-build> set ThisBuild / scalaVersion := "$example_scala213$" [info] Defining ThisBuild / scalaVersion +[info] The new value will be used by Compile / bspBuildTarget, Compile / dependencyTreeCrossProjectId and 50 others. +[info] Run `last` for details. +[info] Reapplying settings... +[info] set current project to foo-build (in build file:/tmp/foo-build/) ``` ### Comprobar la entrada `scalaVersion`: @@ -161,6 +168,13 @@ Podemos guardar la configuración temporal utilizando `session save`. ``` sbt:foo-build> session save [info] Reapplying settings... +[info] set current project to foo-build (in build file:/tmp/foo-build/) +[warn] build source files have changed +[warn] modified files: +[warn] /tmp/foo-build/build.sbt +[warn] Apply these changes by running `reload`. +[warn] Automatically reload the build when source changes are detected by setting `Global / onChangedBuildSource := ReloadOnSourceChanges`. +[warn] Disable this warning by setting `Global / onChangedBuildSource := IgnoreSourceChanges`. ``` El fichero `build.sbt` ahora debería de contener: @@ -183,9 +197,10 @@ aplicada. ``` sbt:foo-build> reload -[info] Loading project definition from /tmp/foo-build/project -[info] Loading settings from build.sbt ... -[info] Set current project to Hello (in build file:/tmp/foo-build/) +[info] welcome to sbt 1.9.3 (Eclipse Adoptium Java 17.0.8) +[info] loading project definition from /tmp/foo-build/project +[info] loading settings for project hello from build.sbt ... +[info] set current project to Hello (in build file:/tmp/foo-build/) sbt:Hello> ``` @@ -218,34 +233,33 @@ sbt:Hello> ~testQuick ### Escribir un test Con el comando anterior ejecutándose, crea un fichero llamado -`src/test/scala/HelloSpec.scala` utilizando un editor: +`src/test/scala/example/HelloSpec.scala` utilizando un editor: -@@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/src/test/scala/HelloSpec.scala) {} +@@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/src/test/scala/example/HelloSpec.scala) {} `~testQuick` debería de coger el cambio: ``` -2. Waiting for source changes... (press enter to interrupt) -[info] Compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/test-classes ... -[info] Done compiling. +[info] 2. Monitoring source files for hello/testQuick... +[info] Press to interrupt or '?' for more options. +[info] Build triggered by /private/tmp/foo-build/src/test/scala/HelloSpec.scala. Running 'testQuick'. +[info] compiling 1 Scala source to /private/tmp/foo-build/target/scala-2.13/test-classes ... [info] HelloSpec: [info] - Hello should start with H *** FAILED *** -[info] assert("hello".startsWith("H")) -[info] | | | -[info] "hello" false "H" (HelloSpec.scala:5) -[info] Run completed in 135 milliseconds. +[info] "hello" did not start with "H" (HelloSpec.scala:5) +[info] Run completed in 44 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0 [info] *** 1 TEST FAILED *** [error] Failed tests: -[error] HelloSpec -[error] (Test / testQuick) sbt.TestsFailedException: Tests unsuccessful +[error] HelloSpec +[error] (Test / testQuick) sbt.TestsFailedException: Tests unsuccessfull ``` ### Hacer que el test pase -Utilizando un editor, cambia `src/test/scala/HelloSpec.scala` a: +Utilizando un editor, cambia `src/test/scala/example/HelloSpec.scala` a: @@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/changes/HelloSpec.scala) {} @@ -263,65 +277,57 @@ Usa el comando `reload` para reflejar los cambios de `build.sbt`. Podemos averiguar qué tiempo hace actualmente en Nueva York. + ```scala sbt:Hello> console [info] Starting scala interpreter... -Welcome to Scala 2.12.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_171). +Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java 17). Type in expressions for evaluation. Or try :help. scala> :paste // Entering paste mode (ctrl-D to finish) -import scala.concurrent._, duration._ -import gigahorse._, support.okhttp.Gigahorse -import play.api.libs.json._ - -Gigahorse.withHttp(Gigahorse.config) { http => - val baseUrl = "https://www.metaweather.com/api/location" - val rLoc = Gigahorse.url(baseUrl + "/search/").get. - addQueryString("query" -> "New York") - val fLoc = http.run(rLoc, Gigahorse.asString) - val loc = Await.result(fLoc, 10.seconds) - val woeid = (Json.parse(loc) \\ 0 \\ "woeid").get - val rWeather = Gigahorse.url(baseUrl + s"/\$woeid/").get - val fWeather = http.run(rWeather, Gigahorse.asString) - val weather = Await.result(fWeather, 10.seconds) - ({Json.parse(_: String)} andThen Json.prettyPrint)(weather) -} +import sttp.client4.quick._ +import sttp.client4.Response + +val newYorkLatitude: Double = 40.7143 +val newYorkLongitude: Double = -74.006 +val response: Response[String] = quickRequest + .get( + uri"https://api.open-meteo.com/v1/forecast?latitude=\$newYorkLatitude&longitude=\$newYorkLongitude¤t_weather=true" + ) + .send() + +println(ujson.read(response.body).render(indent = 2)) // press Ctrl+D // Exiting paste mode, now interpreting. -import scala.concurrent._ -import duration._ -import gigahorse._ -import support.okhttp.Gigahorse -import play.api.libs.json._ -res0: String = { - "consolidated_weather" : [ { - "id" : 6446939314847744, - "weather_state_name" : "Light Rain", - "weather_state_abbr" : "lr", - "wind_direction_compass" : "WNW", - "created" : "2019-02-21T04:39:47.747805Z", - "applicable_date" : "2019-02-21", - "min_temp" : 0.48000000000000004, - "max_temp" : 7.84, - "the_temp" : 2.1700000000000004, - "wind_speed" : 5.996333145703094, - "wind_direction" : 293.12257757287307, - "air_pressure" : 1033.115, - "humidity" : 77, - "visibility" : 14.890539250775472, - "predictability" : 75 - }, { - "id" : 5806299509948416, - "weather_state_name" : "Heavy Cloud", -... + "latitude": 40.710335, + "longitude": -73.99307, + "generationtime_ms": 0.36704540252685547, + "utc_offset_seconds": 0, + "timezone": "GMT", + "timezone_abbreviation": "GMT", + "elevation": 51, + "current_weather": { + "temperature": 21.3, + "windspeed": 16.7, + "winddirection": 205, + "weathercode": 3, + "is_day": 1, + "time": "2023-08-04T10:00" + } +} +import sttp.client4.quick._ +import sttp.client4.Response +val newYorkLatitude: Double = 40.7143 +val newYorkLongitude: Double = -74.006 +val response: sttp.client4.Response[String] = Response({"latitude":40.710335,"longitude":-73.99307,"generationtime_ms":0.36704540252685547,"utc_offset_seconds":0,"timezone":"GMT","timezone_abbreviation":"GMT","elevation":51.0,"current_weather":{"temperature":21.3,"windspeed":16.7,"winddirection":205.0,"weathercode":3,"is_day":1,"time":"2023-08-04T10:00"}},200,,List(:status: 200, content-encoding: deflate, content-type: application/json; charset=utf-8, date: Fri, 04 Aug 2023 10:09:11 GMT),List(),RequestMetadata(GET,https://api.open-meteo.com/v1/forecast?latitude=40.7143&longitude... -scala> :q // para salir +scala> :q // to quit ``` ### Crear un subproyecto @@ -374,9 +380,9 @@ Además, movamos la dependencia de Gigahorse a `helloCore`. @@snip [example-sub4]($root$/src/sbt-test/ref/example-sub4/build.sbt) {} -### Parsear JSON con Play JSON +### Parsear JSON con uJson -Vamos a añadir Play JSON a `helloCore`. +Vamos a añadir uJson a `helloCore`. @@snip [example-weather-build]($root$/src/sbt-test/ref/example-weather/build.sbt) {} @@ -385,46 +391,38 @@ Tras un `reload`, añade `core/src/main/scala/example/core/Weather.scala`: ```scala package example.core -import gigahorse._, support.okhttp.Gigahorse -import scala.concurrent._, duration._ -import play.api.libs.json._ +import sttp.client4.quick._ +import sttp.client4.Response object Weather { - lazy val http = Gigahorse.http(Gigahorse.config) - - def weather: Future[String] = { - val baseUrl = "https://www.metaweather.com/api/location" - val locUrl = baseUrl + "/search/" - val weatherUrl = baseUrl + "/%s/" - val rLoc = Gigahorse.url(locUrl).get. - addQueryString("query" -> "New York") - import ExecutionContext.Implicits.global - for { - loc <- http.run(rLoc, parse) - woeid = (loc \\ 0 \\ "woeid").get - rWeather = Gigahorse.url(weatherUrl format woeid).get - weather <- http.run(rWeather, parse) - } yield (weather \\\\ "weather_state_name")(0).as[String].toLowerCase - } - - private def parse = Gigahorse.asString andThen Json.parse + def weather() = { + val response: Response[String] = quickRequest + .get( + uri"https://api.open-meteo.com/v1/forecast?latitude=\$newYorkLatitude&longitude=\$newYorkLongitude¤t_weather=true" + ) + .send() + val json = ujson.read(response.body) + json.obj("current_weather")("temperature").num + } + + private val newYorkLatitude: Double = 40.7143 + private val newYorkLongitude: Double = -74.006 } ``` Ahora, cambia `src/main/scala/example/Hello.scala` como sigue: + ```scala package example -import scala.concurrent._, duration._ -import core.Weather +import example.core.Weather object Hello { - def main(args: Array[String]): Unit = { - val w = Await.result(Weather.weather, 10.seconds) - println(s"Hello! The weather in New York is \$w.") - Weather.http.close() - } + def main(args: Array[String]): Unit = { + val temp = Weather.weather() + println(s"Hello! The current temperature in New York is \$temp C.") + } } ``` @@ -432,16 +430,10 @@ Vamos a ejecutar la aplicación para ver si funciona: ``` sbt:Hello> run -[info] Compiling 1 Scala source to /tmp/foo-build/core/target/scala-2.12/classes ... -[info] Done compiling. -[info] Compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/classes ... -[info] Packaging /tmp/foo-build/core/target/scala-2.12/hello-core_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Done compiling. -[info] Packaging /tmp/foo-build/target/scala-2.12/hello_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Running example.Hello -Hello! The weather in New York is mostly cloudy. +[info] compiling 1 Scala source to /tmp/foo-build/core/target/scala-2.13/classes ... +[info] compiling 1 Scala source to /tmp/foo-build/target/scala-2.13/classes ... +[info] running example.Hello +Hello! The current temperature in New York is 22.7 C. ``` ### Añadir el plugin sbt-native-packager @@ -456,12 +448,21 @@ Después cambia `build.sbt` como sigue para añadir `JavaAppPackaging`: ### Recargar y crear una distribución .zip + ``` sbt:Hello> reload ... sbt:Hello> dist -[info] Wrote /tmp/foo-build/target/scala-2.12/hello_2.12-0.1.0-SNAPSHOT.pom -[info] Wrote /tmp/foo-build/core/target/scala-2.12/hello-core_2.12-0.1.0-SNAPSHOT.pom +[info] Wrote /private/tmp/foo-build/target/scala-2.13/hello_2.13-0.1.0-SNAPSHOT.pom +[info] Main Scala API documentation to /tmp/foo-build/target/scala-2.13/api... +[info] Main Scala API documentation successful. +[info] Main Scala API documentation to /tmp/foo-build/core/target/scala-2.13/api... +[info] Wrote /tmp/foo-build/core/target/scala-2.13/hello-core_2.13-0.1.0-SNAPSHOT.pom +[info] Main Scala API documentation successful. +[warn] [1] The maintainer is empty +[warn] Add this to your build.sbt +[warn] maintainer := "your.name@company.org" +[success] All package validations passed [info] Your package is ready in /tmp/foo-build/target/universal/hello-0.1.0-SNAPSHOT.zip ``` @@ -472,7 +473,7 @@ Así es cómo puedes ejecutar la app una vez empaquetada: \$ cd /tmp/someother \$ unzip -o -d /tmp/someother /tmp/foo-build/target/universal/hello-0.1.0-SNAPSHOT.zip \$ ./hello-0.1.0-SNAPSHOT/bin/hello -Hello! The weather in New York is mostly cloudy. +Hello! The current temperature in New York is 22.7 C. ``` ### Dockerizar tu app @@ -480,17 +481,15 @@ Hello! The weather in New York is mostly cloudy. ``` sbt:Hello> Docker/publishLocal .... -[info] Successfully built b6ce1b6ab2c0 -[info] Successfully tagged hello:0.1.0-SNAPSHOT -[info] Built image hello:0.1.0-SNAPSHOT +[info] Built image hello with tags [0.1.0-SNAPSHOT] ``` Así es cómo puedes ejecutar la app Dockerizada: ``` \$ docker run hello:0.1.0-SNAPSHOT -Hello! The weather in New York is mostly cloudy -``` +Hello! The current temperature in New York is 22.7 C. +`` ### Establecer la versión @@ -501,8 +500,8 @@ Cambia `build.sbt` como sigue: ### Cambiar `scalaVersion` temporalmente ``` -sbt:Hello> ++2.12.14! -[info] Forcing Scala version to 2.12.14 on all projects. +sbt:Hello> ++3.3.0! +[info] Forcing Scala version to 3.3.0 on all projects. [info] Reapplying settings... [info] Set current project to Hello (in build file:/tmp/foo-build/) ``` @@ -512,9 +511,9 @@ Comprueba la entrada `scalaVersion`: ``` sbt:Hello> scalaVersion [info] helloCore / scalaVersion -[info] 2.12.14 +[info] 3.3.0 [info] scalaVersion -[info] 2.12.14 +[info] 3.3.0 ``` Esta entrada se esfumará tras un `reload`. diff --git a/src/reference/ja/00-Getting-Started/02-sbt-by-example.md b/src/reference/ja/00-Getting-Started/02-sbt-by-example.md index 8cd12431d..0556fa7be 100644 --- a/src/reference/ja/00-Getting-Started/02-sbt-by-example.md +++ b/src/reference/ja/00-Getting-Started/02-sbt-by-example.md @@ -27,11 +27,13 @@ sbt の内部がどうなっているかや理由みたいなことを解説す ``` \$ sbt -[info] Updated file /tmp/foo-build/project/build.properties: set sbt.version to 1.1.4 -[info] Loading project definition from /private/tmp/foo-build/project -[info] Loading settings from build.sbt ... -[info] Set current project to foo-build (in build file:/private/tmp/foo-build/) +[info] Updated file /tmp/foo-build/project/build.properties: set sbt.version to 1.9.3 +[info] welcome to sbt 1.9.3 (Eclipse Adoptium Java 17.0.8) +[info] Loading project definition from /tmp/foo-build/project +[info] loading settings for project foo-build from build.sbt ... +[info] Set current project to foo-build (in build file:/tmp/foo-build/) [info] sbt server started at local:///Users/eed3si9n/.sbt/1.0/server/abc4fb6c89985a00fd95/sock +[info] started sbt server sbt:foo-build> ``` @@ -58,8 +60,9 @@ sbt:foo-build> compile ``` sbt:foo-build> ~compile -[success] Total time: 0 s, completed May 6, 2018 3:52:08 PM -1. Waiting for source changes... (press enter to interrupt) +[success] Total time: 0 s, completed 28 Jul 2023, 13:32:35 +[info] 1. Monitoring source files for foo-build/compile... +[info] Press to interrupt or '?' for more options. ``` ### ソース・ファイルを書く @@ -79,10 +82,11 @@ object Hello { この新しいファイルは実行中のコマンドが自動的に検知したはずだ: ``` -[info] Compiling 1 Scala source to /private/tmp/foo-build/target/scala-2.12/classes ... -[info] Done compiling. -[success] Total time: 2 s, completed May 6, 2018 3:53:42 PM -2. Waiting for source changes... (press enter to interrupt) +[info] Build triggered by /tmp/foo-build/src/main/scala/example/Hello.scala. Running 'compile'. +[info] compiling 1 Scala source to /tmp/foo-build/target/scala-2.12/classes ... +[success] Total time: 0 s, completed 28 Jul 2023, 13:38:55 +[info] 2. Monitoring source files for foo-build/compile... +[info] Press to interrupt or '?' for more options. ``` `~compile` を抜けるには `Enter` を押す。 @@ -102,13 +106,14 @@ sbt:foo-build> compile ``` sbt:foo-build> help - about Displays basic information about sbt and the build. - tasks Lists the tasks defined for the current project. - settings Lists the settings defined for the current project. - reload (Re)loads the current project or changes to plugins project or returns from it. - new Creates a new sbt build. - projects Lists the names of available projects or temporarily adds/removes extra builds to the session. - project Displays the current project or changes to the provided `project`. + (; )* Runs the provided semicolon-separated commands. +about Displays basic information about sbt and the build. +tasks Lists the tasks defined for the current project. +settings Lists the settings defined for the current project. +reload (Re)loads the current project or changes to plugins project or returns from it. +new Creates a new sbt build. +new Creates a new sbt build. +projects Lists the names of available projects or temporarily adds/removes extra builds to the session. .... ``` @@ -124,11 +129,9 @@ Runs a main class, passing along arguments provided on the command line. ``` sbt:foo-build> run -[info] Packaging /private/tmp/foo-build/target/scala-2.12/foo-build_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Running example.Hello +[info] running example.Hello Hello -[success] Total time: 1 s, completed May 6, 2018 4:10:44 PM +[success] Total time: 0 s, completed 28 Jul 2023, 13:40:31 ``` ### sbt シェルから ThisBuild / scalaVersion をセットする @@ -136,6 +139,10 @@ Hello ``` sbt:foo-build> set ThisBuild / scalaVersion := "$example_scala213$" [info] Defining ThisBuild / scalaVersion +[info] The new value will be used by Compile / bspBuildTarget, Compile / dependencyTreeCrossProjectId and 50 others. +[info] Run `last` for details. +[info] Reapplying settings... +[info] set current project to foo-build (in build file:/tmp/foo-build/) ``` `scalaVersion` セッティングを確認する: @@ -152,6 +159,13 @@ sbt:foo-build> scalaVersion ``` sbt:foo-build> session save [info] Reapplying settings... +[info] set current project to foo-build (in build file:/tmp/foo-build/) +[warn] build source files have changed +[warn] modified files: +[warn] /tmp/foo-build/build.sbt +[warn] Apply these changes by running `reload`. +[warn] Automatically reload the build when source changes are detected by setting `Global / onChangedBuildSource := ReloadOnSourceChanges`. +[warn] Disable this warning by setting `Global / onChangedBuildSource := IgnoreSourceChanges`. ``` `build.sbt` ファイルは以下のようになったはずだ: @@ -172,9 +186,10 @@ ThisBuild / scalaVersion := "$example_scala213$" ``` sbt:foo-build> reload -[info] Loading project definition from /private/tmp/foo-build/project -[info] Loading settings from build.sbt ... -[info] Set current project to Hello (in build file:/private/tmp/foo-build/) +[info] welcome to sbt 1.9.3 (Eclipse Adoptium Java 17.0.8) +[info] loading project definition from /tmp/foo-build/project +[info] loading settings for project hello from build.sbt ... +[info] set current project to Hello (in build file:/tmp/foo-build/) sbt:Hello> ``` @@ -206,34 +221,33 @@ sbt:Hello> ~testQuick ### テストを書く -上のコマンドを走らせたままで、エディタから `src/test/scala/HelloSpec.scala` という名前のファイルを作成する: +上のコマンドを走らせたままで、エディタから `src/test/scala/example/HelloSpec.scala` という名前のファイルを作成する: -@@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/src/test/scala/HelloSpec.scala) {} +@@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/src/test/scala/example/HelloSpec.scala) {} `~testQuick` が検知したはずだ: ``` -2. Waiting for source changes... (press enter to interrupt) -[info] Compiling 1 Scala source to /private/tmp/foo-build/target/scala-2.12/test-classes ... -[info] Done compiling. +[info] 2. Monitoring source files for hello/testQuick... +[info] Press to interrupt or '?' for more options. +[info] Build triggered by /private/tmp/foo-build/src/test/scala/HelloSpec.scala. Running 'testQuick'. +[info] compiling 1 Scala source to /private/tmp/foo-build/target/scala-2.13/test-classes ... [info] HelloSpec: [info] - Hello should start with H *** FAILED *** -[info] assert("hello".startsWith("H")) -[info] | | | -[info] "hello" false "H" (HelloSpec.scala:5) -[info] Run completed in 135 milliseconds. +[info] "hello" did not start with "H" (HelloSpec.scala:5) +[info] Run completed in 44 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0 [info] *** 1 TEST FAILED *** [error] Failed tests: -[error] HelloSpec -[error] (Test / testQuick) sbt.TestsFailedException: Tests unsuccessful +[error] HelloSpec +[error] (Test / testQuick) sbt.TestsFailedException: Tests unsuccessfull ``` ### テストが通るようにする -エディタを使って `src/test/scala/HelloSpec.scala` を以下のように変更する: +エディタを使って `src/test/scala/example/HelloSpec.scala` を以下のように変更する: @@snip [scalatest]($root$/src/sbt-test/ref/example-scalatest/changes/HelloSpec.scala) {} @@ -252,63 +266,53 @@ New York の現在の天気を調べてみる: ```scala sbt:Hello> console [info] Starting scala interpreter... -Welcome to Scala 2.12.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_171). +Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java 17). Type in expressions for evaluation. Or try :help. scala> :paste // Entering paste mode (ctrl-D to finish) -import scala.concurrent._, duration._ -import gigahorse._, support.okhttp.Gigahorse -import play.api.libs.json._ - -Gigahorse.withHttp(Gigahorse.config) { http => - val baseUrl = "https://www.metaweather.com/api/location" - val rLoc = Gigahorse.url(baseUrl + "/search/").get. - addQueryString("query" -> "New York") - val fLoc = http.run(rLoc, Gigahorse.asString) - val loc = Await.result(fLoc, 10.seconds) - val woeid = (Json.parse(loc) \\ 0 \\ "woeid").get - val rWeather = Gigahorse.url(baseUrl + s"/\$woeid/").get - val fWeather = http.run(rWeather, Gigahorse.asString) - val weather = Await.result(fWeather, 10.seconds) - ({Json.parse(_: String)} andThen Json.prettyPrint)(weather) -} +import sttp.client4.quick._ +import sttp.client4.Response + +val newYorkLatitude: Double = 40.7143 +val newYorkLongitude: Double = -74.006 +val response: Response[String] = quickRequest +.get( + uri"https://api.open-meteo.com/v1/forecast?latitude=\$newYorkLatitude&longitude=\$newYorkLongitude¤t_weather=true" +) +.send() -// Ctrl+D を押してペーストモードを抜ける +println(ujson.read(response.body).render(indent = 2)) + +// press Ctrl+D // Exiting paste mode, now interpreting. -import scala.concurrent._ -import duration._ -import gigahorse._ -import support.okhttp.Gigahorse -import play.api.libs.json._ -res0: String = { - "consolidated_weather" : [ { - "id" : 5325278131781632, - "weather_state_name" : "Light Rain", - "weather_state_abbr" : "lr", - "wind_direction_compass" : "W", - "created" : "2019-11-23T09:16:43.892336Z", - "applicable_date" : "2019-11-23", - "min_temp" : 0.36, - "max_temp" : 8.375, - "the_temp" : 3.98, - "wind_speed" : 4.813710565158143, - "wind_direction" : 266.48254020294627, - "air_pressure" : 1017, - "humidity" : 58, - "visibility" : 15.37583015191283, - "predictability" : 75 - }, { - "id" : 6428406054912000, - "weather_state_name" : "Heavy Rain", - "weather_state_abbr" : "hr", - ... - -scala> :q // これで REPL を抜ける + "latitude": 40.710335, + "longitude": -73.99307, + "generationtime_ms": 0.36704540252685547, + "utc_offset_seconds": 0, + "timezone": "GMT", + "timezone_abbreviation": "GMT", + "elevation": 51, + "current_weather": { + "temperature": 21.3, + "windspeed": 16.7, + "winddirection": 205, + "weathercode": 3, + "is_day": 1, + "time": "2023-08-04T10:00" + } +} +import sttp.client4.quick._ +import sttp.client4.Response +val newYorkLatitude: Double = 40.7143 +val newYorkLongitude: Double = -74.006 +val response: sttp.client4.Response[String] = Response({"latitude":40.710335,"longitude":-73.99307,"generationtime_ms":0.36704540252685547,"utc_offset_seconds":0,"timezone":"GMT","timezone_abbreviation":"GMT","elevation":51.0,"current_weather":{"temperature":21.3,"windspeed":16.7,"winddirection":205.0,"weathercode":3,"is_day":1,"time":"2023-08-04T10:00"}},200,,List(:status: 200, content-encoding: deflate, content-type: application/json; charset=utf-8, date: Fri, 04 Aug 2023 10:09:11 GMT),List(),RequestMetadata(GET,https://api.open-meteo.com/v1/forecast?latitude=40.7143&longitude... + +scala> :q // to quit ``` ### サブプロジェクトを作成する @@ -360,40 +364,34 @@ sbt:Hello> ~testQuick @@snip [example-sub4]($root$/src/sbt-test/ref/example-sub4/build.sbt) {} -### Play JSON を使って JSON をパースする +### uJson を使って JSON をパースする -`helloCore` に Play JSON を追加しよう。 +`helloCore` に uJson を追加しよう。 @@snip [example-weather-build]($root$/src/sbt-test/ref/example-weather/build.sbt) {} `reload` 後、`core/src/main/scala/example/core/Weather.scala` を追加する: ```scala + package example.core -import gigahorse._, support.okhttp.Gigahorse -import scala.concurrent._, duration._ -import play.api.libs.json._ +import sttp.client4.quick._ +import sttp.client4.Response object Weather { - lazy val http = Gigahorse.http(Gigahorse.config) - - def weather: Future[String] = { - val baseUrl = "https://www.metaweather.com/api/location" - val locUrl = baseUrl + "/search/" - val weatherUrl = baseUrl + "/%s/" - val rLoc = Gigahorse.url(locUrl).get. - addQueryString("query" -> "New York") - import ExecutionContext.Implicits.global - for { - loc <- http.run(rLoc, parse) - woeid = (loc \\ 0 \\ "woeid").get - rWeather = Gigahorse.url(weatherUrl format woeid).get - weather <- http.run(rWeather, parse) - } yield (weather \\\\ "weather_state_name")(0).as[String].toLowerCase - } - - private def parse = Gigahorse.asString andThen Json.parse + def weather() = { + val response: Response[String] = quickRequest + .get( + uri"https://api.open-meteo.com/v1/forecast?latitude=\$newYorkLatitude&longitude=\$newYorkLongitude¤t_weather=true" + ) + .send() + val json = ujson.read(response.body) + json.obj("current_weather")("temperature").num + } + + private val newYorkLatitude: Double = 40.7143 + private val newYorkLongitude: Double = -74.006 } ``` @@ -402,15 +400,13 @@ object Weather { ```scala package example -import scala.concurrent._, duration._ -import core.Weather +import example.core.Weather object Hello { - def main(args: Array[String]): Unit = { - val w = Await.result(Weather.weather, 10.seconds) - println(s"Hello! The weather in New York is \$w.") - Weather.http.close() - } + def main(args: Array[String]): Unit = { + val temp = Weather.weather() + println(s"Hello! The current temperature in New York is \$temp C.") + } } ``` @@ -418,16 +414,10 @@ object Hello { ``` sbt:Hello> run -[info] Compiling 1 Scala source to /private/tmp/foo-build/core/target/scala-2.12/classes ... -[info] Done compiling. -[info] Compiling 1 Scala source to /private/tmp/foo-build/target/scala-2.12/classes ... -[info] Packaging /private/tmp/foo-build/core/target/scala-2.12/hello-core_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Done compiling. -[info] Packaging /private/tmp/foo-build/target/scala-2.12/hello_2.12-0.1.0-SNAPSHOT.jar ... -[info] Done packaging. -[info] Running example.Hello -Hello! The weather in New York is mostly cloudy. +[info] compiling 1 Scala source to /tmp/foo-build/core/target/scala-2.13/classes ... +[info] compiling 1 Scala source to /tmp/foo-build/target/scala-2.13/classes ... +[info] running example.Hello +Hello! The current temperature in New York is 22.7 C. ``` ### sbt-native-packger プラグインを追加する @@ -442,11 +432,22 @@ Hello! The weather in New York is mostly cloudy. ### 配布用の .zip ファイルを作る + ``` +sbt:Hello> reload +... sbt:Hello> dist -[info] Wrote /private/tmp/foo-build/target/scala-2.12/hello_2.12-0.1.0-SNAPSHOT.pom -[info] Wrote /private/tmp/foo-build/core/target/scala-2.12/hello-core_2.12-0.1.0-SNAPSHOT.pom -[info] Your package is ready in /private/tmp/foo-build/target/universal/hello-0.1.0-SNAPSHOT.zip +[info] Wrote /private/tmp/foo-build/target/scala-2.13/hello_2.13-0.1.0-SNAPSHOT.pom +[info] Main Scala API documentation to /tmp/foo-build/target/scala-2.13/api... +[info] Main Scala API documentation successful. +[info] Main Scala API documentation to /tmp/foo-build/core/target/scala-2.13/api... +[info] Wrote /tmp/foo-build/core/target/scala-2.13/hello-core_2.13-0.1.0-SNAPSHOT.pom +[info] Main Scala API documentation successful. +[warn] [1] The maintainer is empty +[warn] Add this to your build.sbt +[warn] maintainer := "your.name@company.org" +[success] All package validations passed +[info] Your package is ready in /tmp/foo-build/target/universal/hello-0.1.0-SNAPSHOT.zip ``` パッケージ化されたアプリの実行は以下のように行う: @@ -456,25 +457,23 @@ sbt:Hello> dist \$ cd /tmp/someother \$ unzip -o -d /tmp/someother /tmp/foo-build/target/universal/hello-0.1.0-SNAPSHOT.zip \$ ./hello-0.1.0-SNAPSHOT/bin/hello -Hello! The weather in New York is mostly cloudy. -``` +Hello! The current temperature in New York is 22.7 C. +`` ### アプリを Docker化させる ``` sbt:Hello> Docker/publishLocal .... -[info] Successfully built b6ce1b6ab2c0 -[info] Successfully tagged hello:0.1.0-SNAPSHOT -[info] Built image hello:0.1.0-SNAPSHOT +[info] Built image hello with tags [0.1.0-SNAPSHOT] ``` Docker化されたアプリは以下のように実行する: ``` \$ docker run hello:0.1.0-SNAPSHOT -Hello! The weather in New York is mostly cloudy -``` +Hello! The current temperature in New York is 22.7 C. +`` ### version を設定する @@ -485,8 +484,8 @@ Hello! The weather in New York is mostly cloudy ### Switch scalaVersion temporarily ``` -sbt:Hello> ++2.12.14! -[info] Forcing Scala version to 2.12.14 on all projects. +sbt:Hello> ++3.3.0! +[info] Forcing Scala version to 3.3.0 on all projects. [info] Reapplying settings... [info] Set current project to Hello (in build file:/private/tmp/foo-build/) ``` @@ -496,9 +495,9 @@ sbt:Hello> ++2.12.14! ``` sbt:Hello> scalaVersion [info] helloCore / scalaVersion -[info] 2.12.14 +[info] 3.3.0 [info] scalaVersion -[info] 2.12.14 +[info] 3.3.0 ``` このセッティングは `reload` 後には無くなる。 diff --git a/src/sbt-test/ref/example-library/build.sbt b/src/sbt-test/ref/example-library/build.sbt index 276de577a..56c027d26 100644 --- a/src/sbt-test/ref/example-library/build.sbt +++ b/src/sbt-test/ref/example-library/build.sbt @@ -1,10 +1,13 @@ ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .settings( name := "Hello", - libraryDependencies += "com.typesafe.play" %% "play-json" % "2.9.2", - libraryDependencies += "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0", - libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.7" % Test, + libraryDependencies ++= Seq( + "com.softwaremill.sttp.client4" %% "core" % "4.0.0-M2", + "com.lihaoyi" %% "ujson" % "3.1.2", + "org.scalatest" %% "scalatest" % "3.2.16" % Test + ) ) diff --git a/src/sbt-test/ref/example-scalatest/build.sbt b/src/sbt-test/ref/example-scalatest/build.sbt index 7b18718cf..d3b0ffb62 100644 --- a/src/sbt-test/ref/example-scalatest/build.sbt +++ b/src/sbt-test/ref/example-scalatest/build.sbt @@ -1,8 +1,9 @@ ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .settings( name := "Hello", - libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.7" % Test, + libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.16" % Test ) diff --git a/src/sbt-test/ref/example-scalatest/src/test/scala/HelloSpec.scala b/src/sbt-test/ref/example-scalatest/src/test/scala/example/HelloSpec.scala similarity index 100% rename from src/sbt-test/ref/example-scalatest/src/test/scala/HelloSpec.scala rename to src/sbt-test/ref/example-scalatest/src/test/scala/example/HelloSpec.scala diff --git a/src/sbt-test/ref/example-scalatest/test b/src/sbt-test/ref/example-scalatest/test index 7c58b402e..9c6e62134 100644 --- a/src/sbt-test/ref/example-scalatest/test +++ b/src/sbt-test/ref/example-scalatest/test @@ -1,4 +1,4 @@ > compile -> testQuick -$copy-file changes/HelloSpec.scala src/test/scala/HelloSpec.scala +$copy-file changes/HelloSpec.scala src/test/scala/example/HelloSpec.scala > testQuick diff --git a/src/sbt-test/ref/example-sub1/build.sbt b/src/sbt-test/ref/example-sub1/build.sbt index bae3ed78c..cbc5f1c3f 100644 --- a/src/sbt-test/ref/example-sub1/build.sbt +++ b/src/sbt-test/ref/example-sub1/build.sbt @@ -1,14 +1,19 @@ ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .settings( name := "Hello", - libraryDependencies += "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0", - libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.7" % Test, + libraryDependencies ++= Seq( + "com.softwaremill.sttp.client4" %% "core" % "4.0.0-M2", + "com.lihaoyi" %% "ujson" % "3.1.2", + "org.scalatest" %% "scalatest" % "3.2.16" % Test + ) ) -lazy val helloCore = (project in file("core")) +lazy val helloCore = project + .in(file("core")) .settings( - name := "Hello Core", + name := "Hello Core" ) diff --git a/src/sbt-test/ref/example-sub2/build.sbt b/src/sbt-test/ref/example-sub2/build.sbt index 73735ee84..b1056ae65 100644 --- a/src/sbt-test/ref/example-sub2/build.sbt +++ b/src/sbt-test/ref/example-sub2/build.sbt @@ -1,17 +1,22 @@ ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -val scalaTest = "org.scalatest" %% "scalatest" % "3.2.7" +val scalaTest = "org.scalatest" %% "scalatest" % "3.2.16" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .settings( name := "Hello", - libraryDependencies += "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0", - libraryDependencies += scalaTest % Test, + libraryDependencies ++= Seq( + "com.softwaremill.sttp.client4" %% "core" % "4.0.0-M2", + "com.lihaoyi" %% "ujson" % "3.1.2", + scalaTest % Test + ) ) -lazy val helloCore = (project in file("core")) +lazy val helloCore = project + .in(file("core")) .settings( name := "Hello Core", - libraryDependencies += scalaTest % Test, + libraryDependencies += scalaTest % Test ) diff --git a/src/sbt-test/ref/example-sub3/build.sbt b/src/sbt-test/ref/example-sub3/build.sbt index 8a6d34118..81611c674 100644 --- a/src/sbt-test/ref/example-sub3/build.sbt +++ b/src/sbt-test/ref/example-sub3/build.sbt @@ -1,18 +1,23 @@ ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -val scalaTest = "org.scalatest" %% "scalatest" % "3.2.7" +val scalaTest = "org.scalatest" %% "scalatest" % "3.2.16" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .aggregate(helloCore) .settings( name := "Hello", - libraryDependencies += "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0", - libraryDependencies += scalaTest % Test, + libraryDependencies ++= Seq( + "com.softwaremill.sttp.client4" %% "core" % "4.0.0-M2", + "com.lihaoyi" %% "ujson" % "3.1.2", + scalaTest % Test + ) ) -lazy val helloCore = (project in file("core")) +lazy val helloCore = project + .in(file("core")) .settings( name := "Hello Core", - libraryDependencies += scalaTest % Test, + libraryDependencies += scalaTest % Test ) diff --git a/src/sbt-test/ref/example-sub4/build.sbt b/src/sbt-test/ref/example-sub4/build.sbt index 925fec68d..2c347980c 100644 --- a/src/sbt-test/ref/example-sub4/build.sbt +++ b/src/sbt-test/ref/example-sub4/build.sbt @@ -1,19 +1,24 @@ ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -val scalaTest = "org.scalatest" %% "scalatest" % "3.2.7" +val scalaTest = "org.scalatest" %% "scalatest" % "3.2.16" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .aggregate(helloCore) .dependsOn(helloCore) .settings( name := "Hello", - libraryDependencies += scalaTest % Test, + libraryDependencies ++= Seq( + "com.softwaremill.sttp.client4" %% "core" % "4.0.0-M2", + "com.lihaoyi" %% "ujson" % "3.1.2", + scalaTest % Test + ) ) -lazy val helloCore = (project in file("core")) +lazy val helloCore = project + .in(file("core")) .settings( name := "Hello Core", - libraryDependencies += "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0", - libraryDependencies += scalaTest % Test, + libraryDependencies += scalaTest % Test ) diff --git a/src/sbt-test/ref/example-weather/build.sbt b/src/sbt-test/ref/example-weather/build.sbt index 12ad38421..17b778a43 100644 --- a/src/sbt-test/ref/example-weather/build.sbt +++ b/src/sbt-test/ref/example-weather/build.sbt @@ -1,21 +1,26 @@ ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -val scalaTest = "org.scalatest" %% "scalatest" % "3.2.7" -val gigahorse = "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0" -val playJson = "com.typesafe.play" %% "play-json" % "2.9.2" +val scalaTest = "org.scalatest" %% "scalatest" % "3.2.16" +val sttp = "com.softwaremill.sttp.client4" %% "core" % "4.0.0-M2" +val ujson = "com.lihaoyi" %% "ujson" % "3.1.2" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .aggregate(helloCore) .dependsOn(helloCore) .settings( name := "Hello", - libraryDependencies += scalaTest % Test, + libraryDependencies += scalaTest % Test ) -lazy val helloCore = (project in file("core")) +lazy val helloCore = project + .in(file("core")) .settings( name := "Hello Core", - libraryDependencies ++= Seq(gigahorse, playJson), - libraryDependencies += scalaTest % Test, + libraryDependencies ++= Seq( + scalaTest % Test, + sttp, + ujson + ) ) diff --git a/src/sbt-test/ref/example-weather/changes/build.sbt b/src/sbt-test/ref/example-weather/changes/build.sbt index b713aa0c1..591231d5f 100644 --- a/src/sbt-test/ref/example-weather/changes/build.sbt +++ b/src/sbt-test/ref/example-weather/changes/build.sbt @@ -1,22 +1,27 @@ ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -val scalaTest = "org.scalatest" %% "scalatest" % "3.2.7" -val gigahorse = "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0" -val playJson = "com.typesafe.play" %% "play-json" % "2.9.2" +val scalaTest = "org.scalatest" %% "scalatest" % "3.2.16" +val sttp = "com.softwaremill.sttp.client4" %% "core" % "4.0.0-M2" +val ujson = "com.lihaoyi" %% "ujson" % "3.1.2" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .aggregate(helloCore) .dependsOn(helloCore) .enablePlugins(JavaAppPackaging) .settings( name := "Hello", - libraryDependencies += scalaTest % Test, + libraryDependencies += scalaTest % Test ) -lazy val helloCore = (project in file("core")) +lazy val helloCore = project + .in(file("core")) .settings( name := "Hello Core", - libraryDependencies ++= Seq(gigahorse, playJson), - libraryDependencies += scalaTest % Test, + libraryDependencies ++= Seq( + scalaTest % Test, + sttp, + ujson + ) ) diff --git a/src/sbt-test/ref/example-weather/changes/build3.sbt b/src/sbt-test/ref/example-weather/changes/build3.sbt index d434adf75..3991aeac6 100644 --- a/src/sbt-test/ref/example-weather/changes/build3.sbt +++ b/src/sbt-test/ref/example-weather/changes/build3.sbt @@ -1,23 +1,28 @@ -ThisBuild / version := "0.1.0" +ThisBuild / version := "0.1.0" ThisBuild / scalaVersion := "2.13.6" ThisBuild / organization := "com.example" -val scalaTest = "org.scalatest" %% "scalatest" % "3.2.7" -val gigahorse = "com.eed3si9n" %% "gigahorse-okhttp" % "0.5.0" -val playJson = "com.typesafe.play" %% "play-json" % "2.9.2" +val scalaTest = "org.scalatest" %% "scalatest" % "3.2.16" +val sttp = "com.softwaremill.sttp.client4" %% "core" % "4.0.0-M2" +val ujson = "com.lihaoyi" %% "ujson" % "3.1.2" -lazy val hello = (project in file(".")) +lazy val hello = project + .in(file(".")) .aggregate(helloCore) .dependsOn(helloCore) .enablePlugins(JavaAppPackaging) .settings( name := "Hello", - libraryDependencies += scalaTest % Test, + libraryDependencies += scalaTest % Test ) -lazy val helloCore = (project in file("core")) +lazy val helloCore = project + .in(file("core")) .settings( name := "Hello Core", - libraryDependencies ++= Seq(gigahorse, playJson), - libraryDependencies += scalaTest % Test, + libraryDependencies ++= Seq( + scalaTest % Test, + sttp, + ujson + ) ) diff --git a/src/sbt-test/ref/example-weather/changes/plugins.sbt b/src/sbt-test/ref/example-weather/changes/plugins.sbt index 84668ba94..9a1605498 100644 --- a/src/sbt-test/ref/example-weather/changes/plugins.sbt +++ b/src/sbt-test/ref/example-weather/changes/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.4") +addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.9.4") diff --git a/src/sbt-test/ref/example-weather/core/src/main/scala/example/core/Weather.scala b/src/sbt-test/ref/example-weather/core/src/main/scala/example/core/Weather.scala index 7f6de5f40..aedc6af3a 100644 --- a/src/sbt-test/ref/example-weather/core/src/main/scala/example/core/Weather.scala +++ b/src/sbt-test/ref/example-weather/core/src/main/scala/example/core/Weather.scala @@ -1,26 +1,19 @@ package example.core -import gigahorse._, support.okhttp.Gigahorse -import scala.concurrent._, duration._ -import play.api.libs.json._ +import sttp.client4.quick._ +import sttp.client4.Response object Weather { - lazy val http = Gigahorse.http(Gigahorse.config) - - def weather: Future[String] = { - val baseUrl = "https://www.metaweather.com/api/location" - val locUrl = baseUrl + "/search/" - val weatherUrl = baseUrl + "/%s/" - val rLoc = Gigahorse.url(locUrl).get. - addQueryString("query" -> "New York") - import ExecutionContext.Implicits.global - for { - loc <- http.run(rLoc, parse) - woeid = (loc \ 0 \ "woeid").get - rWeather = Gigahorse.url(weatherUrl format woeid).get - weather <- http.run(rWeather, parse) - } yield (weather \\ "weather_state_name")(0).as[String].toLowerCase + def weather() = { + val response: Response[String] = quickRequest + .get( + uri"https://api.open-meteo.com/v1/forecast?latitude=$newYorkLatitude&longitude=$newYorkLongitude¤t_weather=true" + ) + .send() + val json = ujson.read(response.body) + json.obj("current_weather")("temperature").num } - private def parse = Gigahorse.asString andThen Json.parse + private val newYorkLatitude: Double = 40.7143 + private val newYorkLongitude: Double = -74.006 } diff --git a/src/sbt-test/ref/example-weather/src/main/scala/example/Hello.scala b/src/sbt-test/ref/example-weather/src/main/scala/example/Hello.scala index d1c81d0d4..84f5b5b6a 100644 --- a/src/sbt-test/ref/example-weather/src/main/scala/example/Hello.scala +++ b/src/sbt-test/ref/example-weather/src/main/scala/example/Hello.scala @@ -1,12 +1,10 @@ package example -import scala.concurrent._, duration._ -import core.Weather +import example.core.Weather object Hello { def main(args: Array[String]): Unit = { - val w = Await.result(Weather.weather, 10.seconds) - println(s"Hello! The weather in New York is $w.") - Weather.http.close() + val temp = Weather.weather() + println(s"Hello! The current temperature in New York is $temp C.") } } diff --git a/src/sbt-test/ref/example-weather/pending b/src/sbt-test/ref/example-weather/test similarity index 100% rename from src/sbt-test/ref/example-weather/pending rename to src/sbt-test/ref/example-weather/test