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

FS-229 Pass codeblocks to tut #233

Merged
merged 1 commit into from
Apr 18, 2017
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
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
16 changes: 14 additions & 2 deletions freestyle-cache/shared/src/test/scala/CacheTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ package freestyle.cache

import cats.{Applicative, Id, ~>}
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 +29,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