Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tut to mdoc #3595

Merged
merged 6 commits into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ As a side note, the latter command uses [sbt-mima](https://github.com/lightbend/
### source for the documentation
The documentation for this website is stored alongside the source, in the [docs subproject](https://github.com/typelevel/cats/tree/master/docs).

* The source for the tut compiled pages is in `docs/src/main/tut`
* The source for the tut compiled pages is in `docs/src/main/mdoc`
* The menu structure for these pages is in `docs/src/main/resources/microsite/data/menu.yml`

### Generating the Site
Expand All @@ -206,7 +206,7 @@ run `sbt docs/makeMicrosite`

Or just dropping into a `nix-shell` if you are using the [Nix Cats development environment](#nix-cats-development-environment).

2. In a shell, navigate to the generated site directory in `docs/target/site`
2. In a shell, navigate to the generated site directory in `cats-docs/target/site`

3. Start jekyll with `jekyll serve`

Expand All @@ -216,7 +216,7 @@ run `sbt docs/makeMicrosite`

### Compiler verified documentation

We use [tut](https://github.com/tpolecat/tut) to compile source code
We use [mdoc](https://github.com/scalameta/mdoc) to compile source code
which appears in the documentation, this ensures us that our examples
should always compile, and our documentation has a better chance of
staying up-to-date.
Expand Down
15 changes: 11 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ lazy val docSettings = Seq(
micrositeDocumentationUrl := "/cats/api/cats/index.html",
micrositeDocumentationLabelDescription := "API Documentation",
micrositeGithubOwner := "typelevel",
micrositeExtraMdFilesOutput := resourceManaged.value / "main" / "jekyll",
micrositeExtraMdFiles := Map(
file("CONTRIBUTING.md") -> ExtraMdFileConfig(
"contributing.md",
Expand All @@ -210,13 +211,13 @@ lazy val docSettings = Seq(
"gray-lighter" -> "#F4F3F4",
"white-color" -> "#FFFFFF"
),
micrositeCompilingDocsTool := WithTut,
micrositeCompilingDocsTool := WithMdoc,
autoAPIMappings := true,
unidocProjectFilter in (ScalaUnidoc, unidoc) := inProjects(kernel.jvm, core.jvm, free.jvm),
docsMappingsAPIDir := "api",
addMappingsToSiteDir(mappings in (ScalaUnidoc, packageDoc), docsMappingsAPIDir),
ghpagesNoJekyll := false,
fork in tut := true,
fork in mdoc := true,
fork in (ScalaUnidoc, unidoc) := true,
scalacOptions in (ScalaUnidoc, unidoc) ++= Seq(
"-Xfatal-warnings",
Expand All @@ -230,10 +231,14 @@ lazy val docSettings = Seq(
Seq("-Yno-adapted-args")
else
Nil),
scalacOptions in Tut ~= (_.filterNot(Set("-Ywarn-unused-import", "-Ywarn-unused:imports", "-Ywarn-dead-code"))),
scalacOptions ~= (_.filterNot(
Set("-Ywarn-unused-import", "-Ywarn-unused:imports", "-Ywarn-dead-code", "-Xfatal-warnings")
)),
git.remoteRepo := "git@github.com:typelevel/cats.git",
includeFilter in makeSite := "*.html" | "*.css" | "*.png" | "*.jpg" | "*.gif" | "*.js" | "*.swf" | "*.yml" | "*.md" | "*.svg",
includeFilter in Jekyll := (includeFilter in makeSite).value
includeFilter in Jekyll := (includeFilter in makeSite).value,
mdocIn := baseDirectory.in(LocalRootProject).value / "docs" / "src" / "main" / "mdoc",
mdocExtraArguments := Seq("--no-link-hygiene")
)

def mimaPrevious(moduleName: String, scalaVer: String, ver: String, includeCats1: Boolean = true): List[ModuleID] = {
Expand Down Expand Up @@ -401,6 +406,8 @@ def mimaSettings(moduleName: String, includeCats1: Boolean = true) =
)

lazy val docs = project
.in(file("cats-docs"))
.enablePlugins(MdocPlugin)
.enablePlugins(MicrositesPlugin)
.enablePlugins(ScalaUnidocPlugin)
.settings(moduleName := "cats-docs")
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ It's a simple ADT that has only 4 cases.
It is either an empty `Chain` with no elements, a singleton `Chain` with exactly one element, a concatenation of two chains or a wrapper for another collection.
In code it looks like this:

```tut:book
```scala mdoc
sealed abstract class Chain[+A]

case object Empty extends Chain[Nothing]
final case class Singleton[A](a: A) extends Chain[A]
final case class Append[A](left: Chain[A], right: Chain[A]) extends Chain[A]
final case class Wrap[A](seq: Seq[A]) extends Chain[A]
case class Singleton[A](a: A) extends Chain[A]
case class Append[A](left: Chain[A], right: Chain[A]) extends Chain[A]
case class Wrap[A](seq: Seq[A]) extends Chain[A]
```

The `Append` constructor is what gives us the fast concatenation ability.
Expand Down Expand Up @@ -121,7 +121,7 @@ Likewise, it defines a `NonEmptyTraverse` instance, but no `TraverseFilter` inst

There are numerous ways to construct a `NonEmptyChain`, e.g. you can create one from a single element, a `NonEmptyList` or a `NonEmptyVector`:

```tut:book
```scala mdoc
import cats.data._

NonEmptyChain(1, 2, 3, 4)
Expand All @@ -136,7 +136,7 @@ NonEmptyChain.one(1)

You can also create an `Option` of `NonEmptyChain` from a `Chain` or any other collection type:

```tut:book
```scala mdoc
import cats.data._

NonEmptyChain.fromChain(Chain(1, 2, 3))
Expand All @@ -146,7 +146,7 @@ NonEmptyChain.fromSeq(Vector(1, 2, 3))

Sometimes, you'll want to prepend or append a single element to a chain and return the result as a `NonEmptyChain`:

```tut:book
```scala mdoc
import cats.data._

NonEmptyChain.fromChainAppend(Chain(1, 2, 3), 4)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ have its uses, which serve as a nice example of the consistency and elegance of
## Thinking about `Const`
The `Const` data type can be thought of similarly to the `const` function, but as a data type.

```tut:silent
```scala mdoc:silent
def const[A, B](a: A)(b: => B): A = a
```

The `const` function takes two arguments and simply returns the first argument, ignoring the second.

```tut:silent
final case class Const[A, B](getConst: A)
```scala mdoc:silent
case class Const[A, B](getConst: A)
```

The `Const` data type takes two type parameters, but only ever stores a value of the first type parameter.
Expand All @@ -44,7 +44,7 @@ to use a lens.
A lens can be thought of as a first class getter/setter. A `Lens[S, A]` is a data type that knows how to get
an `A` out of an `S`, or set an `A` in an `S`.

```tut:silent
```scala mdoc:silent
trait Lens[S, A] {
def get(s: S): A

Expand All @@ -58,7 +58,7 @@ trait Lens[S, A] {
It can be useful to have effectful modifications as well - perhaps our modification can fail (`Option`) or
can return several values (`List`).

```tut:silent
```scala mdoc:nest:silent
trait Lens[S, A] {
def get(s: S): A

Expand All @@ -78,7 +78,7 @@ trait Lens[S, A] {
Note that both `modifyOption` and `modifyList` share the *exact* same implementation. If we look closely, the
only thing we need is a `map` operation on the data type. Being good functional programmers, we abstract.

```tut:silent
```scala mdoc:nest:silent
import cats.Functor
import cats.implicits._

Expand All @@ -99,7 +99,7 @@ We can redefine `modify` in terms of `modifyF` by using `cats.Id`. We can also t
that simply ignores the current value. Due to these modifications however, we must leave `modifyF` abstract
since having it defined in terms of `set` would lead to infinite circular calls.

```tut:silent
```scala mdoc:nest:silent
import cats.Id

trait Lens[S, A] {
Expand Down Expand Up @@ -136,7 +136,8 @@ define a `Functor` instance for `Const`, where the first type parameter is fixed

*Note*: the example below assumes usage of the [kind-projector compiler plugin](https://github.com/typelevel/kind-projector) and will not compile if it is not being used in a project.

```tut:silent
```scala mdoc:reset:silent
import cats.Functor
import cats.data.Const

implicit def constFunctor[X]: Functor[Const[X, *]] =
Expand All @@ -149,7 +150,9 @@ implicit def constFunctor[X]: Functor[Const[X, *]] =

Now that that's taken care of, let's substitute and see what happens.

```tut:silent
```scala mdoc:silent
import cats.Id

trait Lens[S, A] {
def modifyF[F[_] : Functor](s: S)(f: A => F[A]): F[S]

Expand All @@ -176,7 +179,7 @@ In the popular [The Essence of the Iterator Pattern](https://www.cs.ox.ac.uk/jer
paper, Jeremy Gibbons and Bruno C. d. S. Oliveria describe a functional approach to iterating over a collection of
data. Among the abstractions presented are `Foldable` and `Traverse`, replicated below (also available in Cats).

```tut:silent
```scala mdoc:silent
import cats.{Applicative, Monoid}

trait Foldable[F[_]] {
Expand All @@ -196,7 +199,7 @@ These two type classes seem unrelated - one reduces a collection down to a singl
a collection with an effectful function, collecting results. It may be surprising to see that in fact `Traverse`
subsumes `Foldable`.

```tut:silent
```scala mdoc:nest:silent
trait Traverse[F[_]] extends Foldable[F] {
def traverse[G[_] : Applicative, A, X](fa: F[A])(f: A => G[X]): G[F[X]]

Expand All @@ -213,7 +216,7 @@ However, if we imagine `G[_]` to be a sort of type-level constant function, wher
`F[X]` is the value we want to ignore, we treat it as the second type parameter and hence, leave it as the free
one.

```tut:silent
```scala mdoc:nest:silent
import cats.data.Const

implicit def constApplicative[Z]: Applicative[Const[Z, *]] =
Expand All @@ -237,7 +240,7 @@ should try to do something more useful. This suggests composition of `Z`s, which
So now we need a constant `Z` value, and a binary function that takes two `Z`s and produces a `Z`. Sound familiar?
We want `Z` to have a `Monoid` instance!

```tut:silent
```scala mdoc:nest:silent
implicit def constApplicative[Z : Monoid]: Applicative[Const[Z, *]] =
new Applicative[Const[Z, *]] {
def pure[A](a: A): Const[Z, A] = Const(Monoid[Z].empty)
Expand All @@ -263,7 +266,7 @@ So to summarize, what we want is a function `A => Const[B, Nothing]`, and we hav
that `Const[B, Z]` (for any `Z`) is the moral equivalent of just `B`, so `A => Const[B, Nothing]` is equivalent
to `A => B`, which is exactly what we have, we just need to wrap it.

```tut:silent
```scala mdoc:nest:silent
trait Traverse[F[_]] extends Foldable[F] {
def traverse[G[_] : Applicative, A, X](fa: F[A])(f: A => G[X]): G[F[X]]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ computation of the final result.

For example:

```tut:silent
```scala mdoc:silent
case class User(id: Int, name: String, age: Int)
sealed abstract class UserUpdateResult
case class Succeeded(updatedUserId: Int) extends UserUpdateResult
case object Failed extends UserUpdateResult
```

```tut:book
```scala mdoc
import cats.Eval

def updateUser(persistToDatabase: User => Eval[UserUpdateResult])
Expand Down Expand Up @@ -54,7 +54,7 @@ Note the following characteristics:

In Cats we can encode this pattern using the `ContT` data type:

```tut:book
```scala mdoc
import cats.data.ContT

def updateUserCont(existingUser: User,
Expand All @@ -71,7 +71,7 @@ def updateUserCont(existingUser: User,

We can construct a computation as follows:

```tut:book
```scala mdoc
val existingUser = User(100, "Alice", 42)

val computation = updateUserCont(existingUser, "Bob", 200)
Expand All @@ -80,7 +80,7 @@ val computation = updateUserCont(existingUser, "Bob", 200)
And then call `run` on it, passing in a function of type `User =>
Eval[UserUpdateResult]` as the continuation:

```tut:book
```scala mdoc
val eval = computation.run { user =>
Eval.later {
println(s"Persisting updated user to the DB: $user")
Expand All @@ -91,7 +91,7 @@ val eval = computation.run { user =>

Finally we can run the resulting `Eval` to actually execute the computation:

```tut:book
```scala mdoc
eval.value
```

Expand All @@ -106,7 +106,7 @@ The point is that `ContT` is a monad, so by rewriting our function into a

For example we can `map` over a `ContT`:

```tut:book
```scala mdoc
val anotherComputation = computation.map { user =>
Map(
"id" -> user.id.toString,
Expand All @@ -132,7 +132,7 @@ update the user model, one to persist the updated user to the database, and one
to publish a message saying the user was updated. It then chains them together
in continuation-passing style using `flatMap` and runs the whole computation.

```tut:book
```scala mdoc:nest
val updateUserModel: ContT[Eval, UserUpdateResult, User] =
updateUserCont(existingUser, "Bob", 200).map { updatedUser =>
println("Updated user model")
Expand Down
Loading