Skip to content

@eamelink /iteratees-by-example.scala
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Scala-IDE worksheet with some examples of iteratees, enumerators and enumeratees and how to use and compose them. Originated from a presentation at Dutch Scala Enthusiasts.
import play.api.libs.iteratee._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.concurrent.duration._
import play.api.libs.concurrent.Promise
object iteratees {
// Implicit conversion to add 'await' to a Future
implicit class WFuture[A](val inner: Future[A]) extends AnyVal {
def await(implicit timeout: Duration) = Await.result(inner, timeout)
}
// Default timeout for futures.
implicit val timeout = 10 second //> timeout : scala.concurrent.duration.FiniteDuration = 10 seconds
// Simple enumerator with pre-known values
val enumerator = Enumerator(1, 2, 3, 4, 5) //> enumerator : play.api.libs.iteratee.Enumerator[Int] = play.api.libs.iterate
//| e.Enumerator$$anon$21@571a75a2
// Iteratee that just prints all input
val printIteratee = Iteratee.foreach[Int] { i => print("[" + i + "]") }
//> printIteratee : play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.libs.i
//| teratee.Cont$$anon$3@6f25844f
// Apply anumerator to iteratee
(enumerator |>> printIteratee).await //> [1][2][3][4][5]res0: play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.li
//| bs.iteratee.Iteratee$$anon$1@148238f4
// Create an iteratee that just takes the first five elements, by transforming the regular
// printIteratee with an enumeratee that only takes five elements.
def printFiveIteratee = Enumeratee.take(5) &>> printIteratee
//> printFiveIteratee: => play.api.libs.iteratee.Iteratee[Int,Unit]
// Test whether our printFiveIteratee actually only consumes the
// first five elements of an enumerator with more chunks
(Enumerator(1, 2, 3, 4, 5, 6, 7, 8) |>> printFiveIteratee).await
//> [1][2][3][4][5]res1: play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.l
//| ibs.iteratee.Iteratee$$anon$1@716c9867
// Now we have the printFiveIteratee, we can make endless enumerators and still show
// their first chunks, without blowing up.
val ones = Enumerator.repeat(1) //> ones : play.api.libs.iteratee.Enumerator[Int] = play.api.libs.iteratee.Enu
//| merator$$anon$15@5982bcde
// Print the first five chunks from an infinite enumerator
(ones |>> printFiveIteratee).await //> [1][1][1][1][1]res2: play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.l
//| ibs.iteratee.Done$$anon$2@4e513d61
// So far, our enumerators had no internal state.
// Here we create one with the 'unfold' method that has
// a state, and uses the state to compute an element and a new state
val counting = Enumerator.unfold(0)(counter => Some(counter + 1, counter))
//> counting : play.api.libs.iteratee.Enumerator[Int] = play.api.libs.iteratee
//| .Enumerator$$anon$12@2bb5340c
// Test it
(counting |>> printFiveIteratee).await //> [0][1][2][3][4]res3: play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.l
//| ibs.iteratee.Done$$anon$2@71060478
// Create an enumerator with state, that computes the element
// and new state asynchronously. The 'Promise' is a play.api.libs.concurrent.Promise,
// not the scala.concurrent one, because the Play one has a nice 'timeout' method
// to create a future that will be completed after some time.
val slowCounting = Enumerator.unfoldM(0) { counter =>
Promise.timeout(Some(counter + 1, counter), 1 second)
} //> slowCounting : play.api.libs.iteratee.Enumerator[Int] = play.api.libs.iter
//| atee.Enumerator$$anon$12@60491c4c
// Apply our slow enumerator on the printing iteratee
// Note that this prints one element every second.
// Commented out by default, because it's slow
// (slowCounting |>> printFiveIteratee).await
// So far, our iteratees were stateless. Here we create
// an iteratee that maintains state, using the 'fold' method on the
// Iteratee object. Notice the similarity with the 'fold' method
// on classes from the collections api.
val summingIteratee = Iteratee.fold(0)((state, elem: Int) => state + elem)
//> summingIteratee : play.api.libs.iteratee.Iteratee[Int,Int] = play.api.libs
//| .iteratee.Cont$$anon$3@7632efa7
// With an iteratee that has state, it's actually interesting
// to look at the iteratee future that the enumerator produces
// after being applied to the original iteratee.
// The enumerator returns the iteratee as it is after pushing
// in all the chunks. So this iteratee will have an internal state
// of '15'
val iterateeFuture = (enumerator |>> summingIteratee)
//> iterateeFuture : scala.concurrent.Future[play.api.libs.iteratee.Iteratee[I
//| nt,Int]] = scala.concurrent.impl.Promise$DefaultPromise@a13f991
// With the 'run' method on an Iteratee, we feed it an EOF
// and then extract the value.
Await.result(iterateeFuture.flatMap(_.run), 1 second)
//> res4: Int = 15
// An enumeratee that only keeps even numbers
val evenEnumeratee = Enumeratee.filter[Int](i => i % 2 == 0)
//> evenEnumeratee : play.api.libs.iteratee.Enumeratee[Int,Int] = play.api.lib
//| s.iteratee.Enumeratee$$anon$18@6f878144
// This transforms (&>>) the iteratee with the enumeratee
(counting |>> evenEnumeratee &>> printFiveIteratee).await
//> [0][2][4][6][8]res5: play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.l
//| ibs.iteratee.Done$$anon$2@15f48262
// Same as the above, but with parentheses to make the operator
// precedence explicit
(counting |>> (evenEnumeratee &>> printFiveIteratee)).await
//> [0][2][4][6][8]res6: play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.l
//| ibs.iteratee.Done$$anon$2@679bfb30
// This "throughs" the enumerator through the enumerate. Give the
// same result as the previous two, but this time the enumeratee is
// composed with the enumerator, and not with the iteratee.
// So whether you are dealing with an Enumerator or an Iteratee,
// you can always compose with an Enumeratee.
(counting &> evenEnumeratee |>> printFiveIteratee).await
//> [0][2][4][6][8]res7: play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.l
//| ibs.iteratee.Iteratee$$anon$1@7d95d4fe
// Same as the above
((counting &> evenEnumeratee) |>> printFiveIteratee).await
//> [0][2][4][6][8]res8: play.api.libs.iteratee.Iteratee[Int,Unit] = play.api.l
//| ibs.iteratee.Iteratee$$anon$1@77d2b01b
}
@keepscoding

await can't print value on worksheet.
any idea?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.