Skip to content

Commit

Permalink
FS-229 Pass codeblocks to tut
Browse files Browse the repository at this point in the history
We pass some of the blocks of code in the documentation to the `tut`
format. We leave as  `Scala` those that are not to be executed.
  • Loading branch information
diesalbla committed Apr 18, 2017
1 parent f083f23 commit c485590
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 38 deletions.
58 changes: 40 additions & 18 deletions docs/src/main/tut/docs/effects/cache/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,52 @@ permalink: /docs/effects/Cache/

The `Cache` effect algebra allows interacting with a _global_ key-value data store.
It declares several abstract operations to read and write data into the store.
This algebra is parametrized on the types `K`, and `V`, for keys and values in the store, respectively.
This algebra is parametrized on the types `Key`, and `Val`, for keys and values in the store, respectively.

The algebra assumes no specific implementation or representation of the data store, for
that is given by each _interpreter or handler_ for the algebra.
For the same reason, it poses no type constraint on `K` or `V` with regards to ordering, hashing, or encoding.
Except, of course, that equality is defined for both types.
```Scala
class KeyValueProvider[Key, Val] {
@free sealed trait CacheM[F[_]] {
def get(key: Key): FreeS.Par[F, Option[Val]]
def put(key: Key, newVal: Val): FreeS.Par[F, Unit]
def del(key: Key): FreeS.Par[F, Unit]
def has(key: Key): FreeS.Par[F, Boolean]
def keys: FreeS.Par[F, List[Key]]
def clear: FreeS.Par[F, Unit]
}
}
```

### Operations
To make the algebra parametric on the types of `Key` and `Value`, we wrap the declaration of the algebra inside a `KeyValueProvider`; but note that this class has no instance data.
The algebra assumes no specific implementation or representation of the data store, since that is a matter for each _handler_ of the algebra.
For the same reason, it poses no type constraint on `Key` or `Val` with regards to ordering, hashing, or encoding, but it is assumed that equality is defined for both types.

The set of abstract operations of the `Cache` algebra are specified as follows.
### Using the Cache Effect

```Scala
class KeyValueProvider[Key, Value] {
@free sealed trait CacheM[F[_]] {
def get(key: Key): FreeS.Par[F, Option[Val]]
def put(key: Key, newVal: Val): FreeS.Par[F, Unit]
def del(key: Key): FreeS.Par[F, Unit]
def has(key: Key): FreeS.Par[F, Boolean]
def keys: FreeS.Par[F, List[Key]]
def clear: FreeS.Par[F, Unit]
}
The following code snippet shows how to import and use the operations from the Cache algebra inside a program.

```tut:book
import freestyle._
import freestyle.implicits._
import freestyle.cache._
import cats.implicits._
val prov = new KeyValueProvider[Char, Int]
import prov.CacheM
import prov.implicits._
def loadFrom[F[_]: prov.CacheM] = {
for {
a <- 1.pure[FreeS[F, ?]]
b <- CacheM[F].get('a')
c <- 1.pure[FreeS[F, ?]]
} yield a + b.getOrElse(0) + c
}
```
To make the algebra parametric on the types of `Key` and `Value`, we wrap the declaration of the algebra inside a `KeyValueProvider`; but note that this class has no instance data.

### Operations

The set of abstract operations of the `Cache` algebra are specified as follows.

* `get(key: Key): M[Option[Val]]` issues a query to the data store on a given key. The result can be `None`, if the store has no mapping for that key, or `Some(v)` if the key is mapped to the value `v`.
* `put(key: Key, v: Value)` issues a command to
Expand Down
45 changes: 26 additions & 19 deletions docs/src/main/tut/docs/integrations/akkahttp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,28 @@ the [Akka HTTP docs](http://doc.akka.io/docs/akka-http/10.0.5/java/http/introduc
Thus, the `freestyle` integration for Akka HTTP provides an extension of that _magnet_ pattern, which allow us to generate
response [marshallers](http://doc.akka.io/docs/akka-http/current/scala/http/common/marshalling.html).
To be precise, what the integration gives is an `implicit` method that may generate an object of type

```Scala
marsh: ToEntityMarshaller[ FreeS[ F, A ] ]
```
for some types parameters `F[_]` , which is the target of the algebra, and for some base result type `A`.
To be precise, what the integration gives is a couple of `implicit` methods to generate an instance of
`ToEntityMarshaller[ FreeS[ F, A ] ] `, or `ToEntityMarshaller[ FreeS.Par[F, A]]`, where
the parameter `F[_]` is the target of the algebra, `A` is the type of the base result.
Note that the method has to be parametrised both on the `F` and on `A`, to make it as generic as possible.
This is the method we have:

```Scala
implicit def seqToEntityMarshaller[F[_], G[_], A](
implicit NT: F ~> G,
MonG: Monad[G],
gem: ToEntityMarshaller[G[A]]
): ToEntityMarshaller[FreeS[F, A]] =
gem.compose((fs: FreeS[F, A]) => fs.exec[G])

```tut:book
import freestyle._
import freestyle.implicits._
import cats.{ ~>, Monad }
import _root_.akka.http.scaladsl.marshalling.ToEntityMarshaller
implicit def seqToEntityMarshaller[F[_], G[_], A](
implicit NT: F ~> G,
MonG: Monad[G],
gem: ToEntityMarshaller[G[A]]): ToEntityMarshaller[FreeS[F, A]] =
gem.compose((fs: FreeS[F, A]) => fs.exec[G])
implicit def parToEntityMarshaller[F[_], G[_], A](
implicit NT: F ~> G,
MonG: Monad[G],
gem: ToEntityMarshaller[G[A]]): ToEntityMarshaller[FreeS.Par[F, A]] =
gem.compose((fp: FreeS.Par[F, A]) => FreeS.liftPar(fp).exec[G])
```

To build such an object `marsh`, our method needs to find in scope :
Expand All @@ -66,7 +72,7 @@ First, we (1) define a domain class `User`, (2) write
a `@free` algebra that returns values of a type `FreeS[F, User]`, and then (3) define an interpreter for that algebra to a type for
which a `Marshaller` _magnet_ exists. To keep things simple, we just interpret to `Id`.

```Scala
```tut:book
import freestyle._
import freestyle.implicits._
Expand All @@ -83,8 +89,9 @@ val app = UserApp.to[UserApp.Op]
To use this `@free` algebra in a route, we need (1) an `EntityMarshaller` for our domain object,
and (2) an interpreter of the algebra to a suitable domain, which for this example will be `Id`.

```Scala
import _root_.akka.http.scaladsl.marshalling.ToEntityMarshaller
```tut:book
import _root_.akka.http.scaladsl.marshalling.{ Marshaller, ToEntityMarshaller }
import cats.Id
implicit val userMarshaller: ToEntityMarshaller[User] =
Marshaller.StringMarshaller.compose((user: User) => s"User(${user.name})")
Expand All @@ -97,7 +104,7 @@ implicit val handler: UserApp.Handler[Id] = new UserApp.Handler[Id] {

With these in scope, one can now write the route by using the marshaller generators from Akka HTTP.

```Scala
```tut:book
import _root_.akka.http.scaladsl.server.Directives._
import _root_.akka.http.scaladsl.server.Route
import _root_.akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
Expand Down
15 changes: 14 additions & 1 deletion freestyle-cache/shared/src/test/scala/CacheTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import cats.syntax.cartesian._
import cats.instances.option._
import freestyle._
import freestyle.implicits._
import org.scalatest._
import org.scalatest.{ Matchers, WordSpec }

class CacheTests extends WordSpec with Matchers with CacheTestContext {

Expand All @@ -30,6 +30,19 @@ class CacheTests extends WordSpec with Matchers with CacheTestContext {
import provider.implicits._
import CacheM._

"CacheM algebra" should {

"allow a CacheM operation to interleaved inside a program monadic flow" in {
def prog[F[_]: CacheM]: FreeS[F, Int] =
for {
a <- FreeS.pure(1)
b <- CacheM[F].get("a")
c <- FreeS.pure(1)
} yield a + b.getOrElse(0) + c
prog[CacheM.Op].exec[Id] shouldBe 2
}
}

"GET" should {
"result in None if the datastore is empty" in {
def program[F[_] : CacheM]: FreeS[F, Option[Int]] =
Expand Down

0 comments on commit c485590

Please sign in to comment.