Skip to content

Commit

Permalink
usage progress checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
raulraja committed Jul 4, 2016
1 parent 34fe35f commit 1c10aef
Show file tree
Hide file tree
Showing 11 changed files with 746 additions and 0 deletions.
36 changes: 36 additions & 0 deletions .gitignore
@@ -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
9 changes: 9 additions & 0 deletions .travis.yml
@@ -0,0 +1,9 @@
language: scala
scala:
- 2.11.7
jdk:
- oraclejdk8
script:
- sbt test
after_success:
- bash deploy.sh
51 changes: 51 additions & 0 deletions build.sbt
@@ -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")
}
)
23 changes: 23 additions & 0 deletions deploy.sh
@@ -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 added keys.tar.gpg
Binary file not shown.
1 change: 1 addition & 0 deletions project/build.properties
@@ -0,0 +1 @@
sbt.version=0.13.9
2 changes: 2 additions & 0 deletions project/plugins.sbt
@@ -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")
55 changes: 55 additions & 0 deletions src/main/scala/fetchlib/CachingSection.scala
@@ -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)
}

}
17 changes: 17 additions & 0 deletions src/main/scala/fetchlib/FetchLibrary.scala
@@ -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
)
}
90 changes: 90 additions & 0 deletions src/main/scala/fetchlib/FetchTutorialHelper.scala
@@ -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"))

}

0 comments on commit 1c10aef

Please sign in to comment.