Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
746 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,36 @@ | |||
project/project | |||
project/target | |||
target | |||
.idea | |||
.tmp | |||
|
|||
*.iml | |||
/out | |||
.idea_modules | |||
.classpath | |||
.project | |||
/RUNNING_PID | |||
.settings | |||
.sass-cache | |||
scalajvm/upload/* | |||
|
|||
# temp files | |||
.~* | |||
*~ | |||
*.orig | |||
|
|||
# eclipse | |||
.scala_dependencies | |||
.buildpath | |||
.cache | |||
.target | |||
bin/ | |||
.ensime | |||
.ensime_cache | |||
|
|||
# OSX | |||
.DS_Store | |||
|
|||
# PGP keys | |||
pubring.gpg | |||
secring.gpg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,9 @@ | |||
language: scala | |||
scala: | |||
- 2.11.7 | |||
jdk: | |||
- oraclejdk8 | |||
script: | |||
- sbt test | |||
after_success: | |||
- bash deploy.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,51 @@ | |||
lazy val fetch = (project in file(".")) | |||
.settings(publishSettings:_*) | |||
.enablePlugins(ExerciseCompilerPlugin) | |||
.settings( | |||
organization := "org.scala-exercises", | |||
name := "exercises-fetch", | |||
scalaVersion := "2.11.7", | |||
version := "0.1.1", | |||
resolvers ++= Seq( | |||
Resolver.sonatypeRepo("snapshots"), | |||
Resolver.sonatypeRepo("releases") | |||
), | |||
libraryDependencies ++= Seq( | |||
"com.fortysevendeg" %% "fetch" % "0.3.0-SNAPSHOT", | |||
"com.chuusai" %% "shapeless" % "2.2.5", | |||
"org.scalatest" %% "scalatest" % "2.2.4", | |||
"org.scala-exercises" %% "exercise-compiler" % version.value, | |||
"org.scala-exercises" %% "definitions" % version.value, | |||
"org.scalacheck" %% "scalacheck" % "1.12.5", | |||
"com.github.alexarchambault" %% "scalacheck-shapeless_1.12" % "0.3.1", | |||
compilerPlugin("org.spire-math" %% "kind-projector" % "0.7.1") | |||
) | |||
) | |||
|
|||
// Distribution | |||
|
|||
lazy val gpgFolder = sys.env.getOrElse("SE_GPG_FOLDER", ".") | |||
|
|||
lazy val publishSettings = Seq( | |||
organizationName := "Scala Exercises", | |||
organizationHomepage := Some(new URL("http://scala-exercises.org")), | |||
startYear := Some(2016), | |||
description := "Scala Exercises: The path to enlightenment", | |||
homepage := Some(url("http://scala-exercises.org")), | |||
pgpPassphrase := Some(sys.env.getOrElse("SE_GPG_PASSPHRASE", "").toCharArray), | |||
pgpPublicRing := file(s"$gpgFolder/pubring.gpg"), | |||
pgpSecretRing := file(s"$gpgFolder/secring.gpg"), | |||
credentials += Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", sys.env.getOrElse("PUBLISH_USERNAME", ""), sys.env.getOrElse("PUBLISH_PASSWORD", "")), | |||
scmInfo := Some(ScmInfo(url("https://github.com/scala-exercises/exercises-fetch"), "https://github.com/scala-exercises/exercises-fetch.git")), | |||
licenses := Seq("Apache License, Version 2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")), | |||
publishMavenStyle := true, | |||
publishArtifact in Test := false, | |||
pomIncludeRepository := Function.const(false), | |||
publishTo := { | |||
val nexus = "https://oss.sonatype.org/" | |||
if (isSnapshot.value) | |||
Some("Snapshots" at nexus + "content/repositories/snapshots") | |||
else | |||
Some("Releases" at nexus + "service/local/staging/deploy/maven2") | |||
} | |||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,23 @@ | |||
|
|||
#!/bin/sh | |||
|
|||
function decipherKeys { | |||
echo $KEYS_PASSPHRASE | gpg --passphrase-fd 0 keys.tar.gpg | |||
tar xfv keys.tar | |||
} | |||
|
|||
function publish { | |||
sbt compile publishSigned | |||
} | |||
|
|||
function release { | |||
decipherKeys | |||
publish | |||
} | |||
|
|||
if [[ $TRAVIS_BRANCH == 'master' ]]; then | |||
echo "Master branch, releasing..." | |||
release | |||
else | |||
echo "Not in master branch, skipping release" | |||
fi |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1 @@ | |||
sbt.version=0.13.9 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,2 @@ | |||
addSbtPlugin("org.scala-exercises" % "sbt-exercise" % "0.1.1", "0.13", "2.10") | |||
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,55 @@ | |||
package fetchlib | |||
|
|||
import cats.data.NonEmptyList | |||
import org.scalatest._ | |||
import fetch._ | |||
|
|||
import cats._ | |||
import fetch.unsafe.implicits._ | |||
import fetch.syntax._ | |||
import cats.std.list._ | |||
import cats.syntax.cartesian._ | |||
import cats.syntax.traverse._ | |||
|
|||
/** | |||
* = Caching = | |||
* | |||
* As we have learned, Fetch caches intermediate results implicitly. You can | |||
* provide a prepopulated cache for running a fetch, replay a fetch with the cache of a previous | |||
* one, and even implement a custom cache. | |||
* | |||
* @param name caching | |||
*/ | |||
object CachingSection extends FlatSpec with Matchers with exercise.Section { | |||
|
|||
import FetchTutorialHelper._ | |||
|
|||
/** | |||
* = Prepopulating a cache = | |||
* | |||
* We'll be using the default in-memory cache, prepopulated with some data. The cache key of an identity | |||
* is calculated with the `DataSource`'s `identity` method. | |||
* {{{ | |||
* val cache = InMemoryCache(UserSource.identity(1) -> User(1, "@dialelo")) | |||
* }}} | |||
* We can pass a cache as argument when running a fetch | |||
*/ | |||
def prepopulating(res0: Int) = { | |||
|
|||
val env = getUser(1).runE[Id](cache) | |||
env.rounds.size should be(res0) | |||
|
|||
} | |||
|
|||
/** | |||
* As you can see, when all the data is cached, no query to the data sources is executed since the results are available | |||
* in the cache. | |||
* If only part of the data is cached, the cached data won't be asked for: | |||
* | |||
*/ | |||
def cachePartialHits(res0: Int) = { | |||
val env = List(1, 2, 3).traverse(getUser).runE[Id](cache) | |||
env.rounds.size should be(res0) | |||
} | |||
|
|||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,17 @@ | |||
package fetchlib | |||
|
|||
/** Fetch is a library for making access to data both simple & efficient. | |||
* | |||
* @param name fetch | |||
*/ | |||
object FetchLibrary extends exercise.Library { | |||
override def owner = "scala-exercises" | |||
override def repository = "exercises-fetch" | |||
|
|||
override def color = Some("#2F2859") | |||
|
|||
override def sections = List( | |||
UsageSection, | |||
CachingSection | |||
) | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,90 @@ | |||
package fetchlib | |||
|
|||
object FetchTutorialHelper { | |||
|
|||
import fetch._ | |||
import cats.std.list._ | |||
|
|||
type UserId = Int | |||
case class User(id: UserId, username: String) | |||
|
|||
def latency[A](result: A, msg: String) = { | |||
val id = Thread.currentThread.getId | |||
println(s"~~> [$id] $msg") | |||
Thread.sleep(100) | |||
println(s"<~~ [$id] $msg") | |||
result | |||
} | |||
|
|||
import cats.data.NonEmptyList | |||
|
|||
val userDatabase: Map[UserId, User] = Map( | |||
1 -> User(1, "@one"), | |||
2 -> User(2, "@two"), | |||
3 -> User(3, "@three"), | |||
4 -> User(4, "@four") | |||
) | |||
|
|||
implicit object UserSource extends DataSource[UserId, User] { | |||
override def fetchOne(id: UserId): Query[Option[User]] = { | |||
Query.sync({ | |||
latency(userDatabase.get(id), s"One User $id") | |||
}) | |||
} | |||
override def fetchMany(ids: NonEmptyList[UserId]): Query[Map[UserId, User]] = { | |||
Query.sync({ | |||
latency(userDatabase.filterKeys(ids.unwrap.contains), s"Many Users $ids") | |||
}) | |||
} | |||
} | |||
|
|||
def getUser(id: UserId): Fetch[User] = Fetch(id) | |||
|
|||
type PostId = Int | |||
case class Post(id: PostId, author: UserId, content: String) | |||
|
|||
val postDatabase: Map[PostId, Post] = Map( | |||
1 -> Post(1, 2, "An article"), | |||
2 -> Post(2, 3, "Another article"), | |||
3 -> Post(3, 4, "Yet another article") | |||
) | |||
|
|||
implicit object PostSource extends DataSource[PostId, Post] { | |||
override def fetchOne(id: PostId): Query[Option[Post]] = { | |||
Query.sync({ | |||
latency(postDatabase.get(id), s"One Post $id") | |||
}) | |||
} | |||
override def fetchMany(ids: NonEmptyList[PostId]): Query[Map[PostId, Post]] = { | |||
Query.sync({ | |||
latency(postDatabase.filterKeys(ids.unwrap.contains), s"Many Posts $ids") | |||
}) | |||
} | |||
} | |||
|
|||
def getPost(id: PostId): Fetch[Post] = Fetch(id) | |||
|
|||
def getAuthor(p: Post): Fetch[User] = Fetch(p.author) | |||
|
|||
type PostTopic = String | |||
|
|||
implicit object PostTopicSource extends DataSource[Post, PostTopic] { | |||
override def fetchOne(id: Post): Query[Option[PostTopic]] = { | |||
Query.sync({ | |||
val topic = if (id.id % 2 == 0) "monad" else "applicative" | |||
latency(Option(topic), s"One Post Topic $id") | |||
}) | |||
} | |||
override def fetchMany(ids: NonEmptyList[Post]): Query[Map[Post, PostTopic]] = { | |||
Query.sync({ | |||
val result = ids.unwrap.map(id => (id, if (id.id % 2 == 0) "monad" else "applicative")).toMap | |||
latency(result, s"Many Post Topics $ids") | |||
}) | |||
} | |||
} | |||
|
|||
def getPostTopic(post: Post): Fetch[PostTopic] = Fetch(post) | |||
|
|||
val cache = InMemoryCache(UserSource.identity(1) -> User(1, "@dialelo")) | |||
|
|||
} |
Oops, something went wrong.