diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 0000000..31e7fc4 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,60 @@ +jobs: + build: + name: Build + needs: + - checks + runs-on: ubuntu-latest + steps: + - uses: "actions/checkout@v2" + with: + submodules: 'true' + - name: "~/.sbt\n\"~/.cache/coursier\"\n cache" + uses: "actions/cache@v3" + with: + key: "${{ runner.os }}-sbt-${{ hashFiles('build.sbt', 'project/plugins.sbt', 'project/build.properties') }}" + path: | + ~/.sbt + "~/.cache/coursier" + restore-keys: | + ${{ runner.os }}-sbt + - name: "java ${{ matrix.java}} setup" + uses: "actions/setup-java@v1.4.3" + with: + architecture: x64 + java-package: jdk + java-version: "${{ matrix.java}}" + - run: "sbt -DJDK_VERSION=${{ matrix.java}} \"++${{ matrix.scala}} test\"" + strategy: + matrix: + java: + - '8.0.382' + - '11.0.21' + - '17.0.9' + scala: + - '2.13.11' + checks: + name: Check formatting + runs-on: ubuntu-latest + steps: + - uses: "actions/checkout@v2" + with: + submodules: 'true' + - name: "~/.sbt\n\"~/.cache/coursier\"\n cache" + uses: "actions/cache@v3" + with: + key: "${{ runner.os }}-sbt-${{ hashFiles('build.sbt', 'project/plugins.sbt', 'project/build.properties') }}" + path: | + ~/.sbt + "~/.cache/coursier" + restore-keys: | + ${{ runner.os }}-sbt + - name: java 17 setup + uses: "actions/setup-java@v1.4.3" + with: + architecture: x64 + java-package: jdk + java-version: '17' + - run: sbt scalafmtCheckAll scalafmtSbtCheck +name: scall_build_and_test +on: + push: {} diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..d08d327 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,18 @@ +# See https://scalameta.org/scalafmt/docs/configuration.html +version=3.7.17 # This is the version of the scalafmt formatter core. +runner.dialect=scala213 # May need to override this for some files. +preset=IntelliJ +maxColumn = 160 +align.preset=most +rewrite.trailingCommas.style = multiple +rewrite.trailingCommas.allowFolding = true +verticalMultiline.arityThreshold = 5 +verticalMultiline.newlineAfterOpenParen = true +rewriteTokens = { + "⇒": "=>" + "→": "->" + "←": "<-" +} +importSelectors = singleLine +optIn.breakChainOnFirstMethodDot = false +optIn.breaksInsideChains = true diff --git a/README.md b/README.md index c8208a6..f02b235 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ # sofp-solutions + Solutions for exercises in the book "Science of functional programming" + +Solutions for each chapter is a submodule in this project. + +Common code may be put into the `common` submodule. + +# Code formatting + +The GitHub job will verify that all code is properly formatted. + +To reformat code, run the script: + +`bash reformat_all_code.sh` + diff --git a/build.sbt b/build.sbt index a9cfa59..5408d57 100644 --- a/build.sbt +++ b/build.sbt @@ -5,9 +5,7 @@ val scalaV = scala2V val munitTest = "org.scalameta" %% "munit" % "0.7.29" % Test def munitFramework = new TestFramework("munit.Framework") - -val assertVerboseTest = "com.eed3si9n.expecty" %% "expecty" % "0.16.0" % Test - +val assertVerboseTest = "com.eed3si9n.expecty" %% "expecty" % "0.16.0" % Test lazy val root = (project in file(".")) .settings(scalaVersion := scalaV, crossScalaVersions := Seq(scalaV), name := "sofp-solutions-root") @@ -21,10 +19,7 @@ lazy val chapter01 = (project in file("chapter01")) Test / fork := false, scalafmtFailOnErrors := false, testFrameworks += munitFramework, - libraryDependencies ++= Seq( - munitTest, - assertVerboseTest, - ), + libraryDependencies ++= Seq(munitTest, assertVerboseTest), ).dependsOn(common) lazy val chapter02 = (project in file("chapter02")) @@ -35,22 +30,15 @@ lazy val chapter02 = (project in file("chapter02")) Test / fork := false, scalafmtFailOnErrors := false, testFrameworks += munitFramework, - libraryDependencies ++= Seq( - munitTest, - assertVerboseTest, - ), + libraryDependencies ++= Seq(munitTest, assertVerboseTest), ).dependsOn(common) -lazy val common = (project in file("common")) - .settings( - scalaVersion := scalaV, - crossScalaVersions := Seq(scala2V, scala3V), - Test / parallelExecution := true, - Test / fork := false, - scalafmtFailOnErrors := false, - testFrameworks += munitFramework, - libraryDependencies ++= Seq( - munitTest, - assertVerboseTest, - ), - ) +lazy val common = (project in file("common")).settings( + scalaVersion := scalaV, + crossScalaVersions := Seq(scala2V, scala3V), + Test / parallelExecution := true, + Test / fork := false, + scalafmtFailOnErrors := false, + testFrameworks += munitFramework, + libraryDependencies ++= Seq(munitTest, assertVerboseTest), +) diff --git a/chapter01/src/test/scala/sofp/unit/Exercise1.1.scala b/chapter01/src/test/scala/sofp/unit/Exercise1.1.scala deleted file mode 100644 index ecfee64..0000000 --- a/chapter01/src/test/scala/sofp/unit/Exercise1.1.scala +++ /dev/null @@ -1,13 +0,0 @@ -package sofp.unit - -import com.eed3si9n.expecty.Expecty.expect - -import munit.FunSuite - -class Exercise1_1 extends FunSuite { - - test("exercise 1.1") { - expect(1 == 0) - } - -} diff --git a/chapter01/src/test/scala/sofp/unit/Exercises_1_6_1.scala b/chapter01/src/test/scala/sofp/unit/Exercises_1_6_1.scala new file mode 100644 index 0000000..60b1e38 --- /dev/null +++ b/chapter01/src/test/scala/sofp/unit/Exercises_1_6_1.scala @@ -0,0 +1,17 @@ +package sofp.unit + +import com.eed3si9n.expecty.Expecty.expect + +import munit.FunSuite + +class Exercises_1_6_1 extends FunSuite { + + test("exercise 1.6.1.1") { + + def staggeredFactorial(n: Int): Int = (n to 1 by -2).product + + expect(staggeredFactorial(8) == 384) + expect(staggeredFactorial(9) == 945) + } + +} diff --git a/github-scala-build-and-test.dhall b/github-scala-build-and-test.dhall new file mode 100644 index 0000000..10876d2 --- /dev/null +++ b/github-scala-build-and-test.dhall @@ -0,0 +1,56 @@ +let GithubActions = + https://regadas.dev/github-actions-dhall/package.dhall + sha256:71df44892a17abca817cfb35e2612d117f7fceec55114a6eb76b65a7eea4e6f4 + +let matrix = + toMap { java = [ "8.0.382", "11.0.21", "17.0.9" ], scala = [ "2.13.11" ] } + +let setup = + [ GithubActions.steps.actions/checkout // { `with` = Some (toMap { submodules = "true" }) } + , GithubActions.steps.actions/cache + { path = + '' + ~/.sbt + "~/.cache/coursier" + '' + , key = "sbt" + , hashFiles = + [ "build.sbt" + , "project/plugins.sbt" + , "project/build.properties" + ] + } + ] + +in GithubActions.Workflow::{ + , name = "scall_build_and_test" + , on = GithubActions.On::{ + , push = Some GithubActions.Push::{=} + --, pull_request = Some GithubActions.PullRequest::{=} + } + , jobs = toMap + { checks = GithubActions.Job::{ + , name = Some "Check formatting" + , runs-on = GithubActions.types.RunsOn.ubuntu-latest + , steps = + setup + # [ GithubActions.steps.actions/setup-java { java-version = "17" } + , GithubActions.steps.run + { run = "sbt scalafmtCheckAll scalafmtSbtCheck" } + ] + } + , build = GithubActions.Job::{ + , name = Some "Build" + , needs = Some [ "checks" ] + , strategy = Some GithubActions.Strategy::{ matrix } + , runs-on = GithubActions.types.RunsOn.ubuntu-latest + , steps = + setup + # [ GithubActions.steps.actions/setup-java + { java-version = "\${{ matrix.java}}" } + , GithubActions.steps.run + { run = "sbt -DJDK_VERSION=\${{ matrix.java}} \"++\${{ matrix.scala}} test\"" } + ] + } + } + } diff --git a/reformat_all_code.sh b/reformat_all_code.sh new file mode 100644 index 0000000..e4a6d95 --- /dev/null +++ b/reformat_all_code.sh @@ -0,0 +1 @@ +sbt scalafmtAll scalafmtSbt diff --git a/update_github_actions.sh b/update_github_actions.sh new file mode 100644 index 0000000..0bc45ae --- /dev/null +++ b/update_github_actions.sh @@ -0,0 +1 @@ +dhall-to-yaml --file github-scala-build-and-test.dhall > .github/workflows/build-and-test.yml