2014-09-04 14:31:22 +02:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2014 Typesafe Inc. <http://www.typesafe.com>
|
|
|
|
|
*/
|
2014-10-27 14:35:41 +01:00
|
|
|
package akka.stream.scaladsl
|
2014-09-04 14:31:22 +02:00
|
|
|
|
2015-06-23 17:32:55 +02:00
|
|
|
import akka.stream.Attributes._
|
2015-06-23 18:28:53 +02:00
|
|
|
import akka.stream.ActorMaterializer
|
2014-12-01 20:07:55 +02:00
|
|
|
import akka.stream.OverflowStrategy
|
2015-04-24 11:45:03 +03:00
|
|
|
import akka.stream.testkit._
|
2014-11-12 10:43:39 +01:00
|
|
|
import akka.stream.stage._
|
2014-09-30 15:40:08 +02:00
|
|
|
|
|
|
|
|
object FlowGraphCompileSpec {
|
|
|
|
|
class Fruit
|
|
|
|
|
class Apple extends Fruit
|
|
|
|
|
}
|
2014-09-04 14:31:22 +02:00
|
|
|
|
|
|
|
|
class FlowGraphCompileSpec extends AkkaSpec {
|
2014-09-30 15:40:08 +02:00
|
|
|
import FlowGraphCompileSpec._
|
2014-09-04 14:31:22 +02:00
|
|
|
|
2015-06-23 18:28:53 +02:00
|
|
|
implicit val mat = ActorMaterializer()
|
2014-09-04 14:31:22 +02:00
|
|
|
|
2014-11-12 10:43:39 +01:00
|
|
|
def op[In, Out]: () ⇒ PushStage[In, Out] = { () ⇒
|
|
|
|
|
new PushStage[In, Out] {
|
2015-04-09 22:28:16 +02:00
|
|
|
override def onPush(elem: In, ctx: Context[Out]): SyncDirective =
|
2014-11-12 10:43:39 +01:00
|
|
|
ctx.push(elem.asInstanceOf[Out])
|
2014-09-04 14:31:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-09 21:09:50 +01:00
|
|
|
val apples = () ⇒ Iterator.continually(new Apple)
|
|
|
|
|
|
2015-04-09 15:16:59 +02:00
|
|
|
val f1 = Flow[String].transform(op[String, String]).named("f1")
|
|
|
|
|
val f2 = Flow[String].transform(op[String, String]).named("f2")
|
|
|
|
|
val f3 = Flow[String].transform(op[String, String]).named("f3")
|
|
|
|
|
val f4 = Flow[String].transform(op[String, String]).named("f4")
|
|
|
|
|
val f5 = Flow[String].transform(op[String, String]).named("f5")
|
|
|
|
|
val f6 = Flow[String].transform(op[String, String]).named("f6")
|
2014-10-02 17:32:08 +02:00
|
|
|
|
2014-10-17 14:05:50 +02:00
|
|
|
val in1 = Source(List("a", "b", "c"))
|
|
|
|
|
val in2 = Source(List("d", "e", "f"))
|
|
|
|
|
val out1 = Sink.publisher[String]
|
2014-11-06 18:13:06 +01:00
|
|
|
val out2 = Sink.head[String]
|
2014-09-04 14:31:22 +02:00
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
"A Graph" should {
|
2014-09-04 14:31:22 +02:00
|
|
|
"build simple merge" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
val merge = b.add(Merge[String](2))
|
|
|
|
|
b.addEdge(b.add(in1), f1, merge.in(0))
|
|
|
|
|
b.addEdge(b.add(in2), f2, merge.in(1))
|
|
|
|
|
b.addEdge(merge.out, f3, b.add(out1))
|
2014-09-10 11:25:38 +02:00
|
|
|
}.run()
|
2014-09-04 14:31:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"build simple broadcast" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
val bcast = b.add(Broadcast[String](2))
|
|
|
|
|
b.addEdge(b.add(in1), f1, bcast.in)
|
|
|
|
|
b.addEdge(bcast.out(0), f2, b.add(out1))
|
|
|
|
|
b.addEdge(bcast.out(1), f3, b.add(out2))
|
2014-09-10 11:25:38 +02:00
|
|
|
}.run()
|
2014-09-04 14:31:22 +02:00
|
|
|
}
|
|
|
|
|
|
2014-10-03 09:00:08 +03:00
|
|
|
"build simple balance" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
val balance = b.add(Balance[String](2))
|
|
|
|
|
b.addEdge(b.add(in1), f1, balance.in)
|
|
|
|
|
b.addEdge(balance.out(0), f2, b.add(out1))
|
|
|
|
|
b.addEdge(balance.out(1), f3, b.add(out2))
|
2014-10-03 09:00:08 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-04 14:31:22 +02:00
|
|
|
"build simple merge - broadcast" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
val merge = b.add(Merge[String](2))
|
|
|
|
|
val bcast = b.add(Broadcast[String](2))
|
|
|
|
|
b.addEdge(b.add(in1), f1, merge.in(0))
|
|
|
|
|
b.addEdge(b.add(in2), f2, merge.in(1))
|
|
|
|
|
b.addEdge(merge.out, f3, bcast.in)
|
|
|
|
|
b.addEdge(bcast.out(0), f4, b.add(out1))
|
|
|
|
|
b.addEdge(bcast.out(1), f5, b.add(out2))
|
2014-09-10 11:25:38 +02:00
|
|
|
}.run()
|
2014-09-04 14:31:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"build simple merge - broadcast with implicits" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
val merge = b.add(Merge[String](2))
|
|
|
|
|
val bcast = b.add(Broadcast[String](2))
|
|
|
|
|
b.add(in1) ~> f1 ~> merge.in(0)
|
|
|
|
|
merge.out ~> f2 ~> bcast.in
|
|
|
|
|
bcast.out(0) ~> f3 ~> b.add(out1)
|
|
|
|
|
b.add(in2) ~> f4 ~> merge.in(1)
|
|
|
|
|
bcast.out(1) ~> f5 ~> b.add(out2)
|
2014-09-10 11:25:38 +02:00
|
|
|
}.run()
|
2014-09-04 14:31:22 +02:00
|
|
|
}
|
|
|
|
|
|
2015-04-09 15:16:59 +02:00
|
|
|
/*
|
2015-01-28 14:19:50 +01:00
|
|
|
* in ---> f1 -+-> f2 -+-> f3 ---> b.add(out1)
|
2014-09-04 14:31:22 +02:00
|
|
|
* ^ |
|
|
|
|
|
* | V
|
|
|
|
|
* f5 <-+- f4
|
|
|
|
|
* |
|
|
|
|
|
* V
|
2015-01-28 14:19:50 +01:00
|
|
|
* f6 ---> b.add(out2)
|
2014-09-04 14:31:22 +02:00
|
|
|
*/
|
|
|
|
|
"detect cycle in " in {
|
2015-01-28 14:19:50 +01:00
|
|
|
pending // FIXME needs cycle detection capability
|
2014-09-04 14:31:22 +02:00
|
|
|
intercept[IllegalArgumentException] {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
val merge = b.add(Merge[String](2))
|
|
|
|
|
val bcast1 = b.add(Broadcast[String](2))
|
|
|
|
|
val bcast2 = b.add(Broadcast[String](2))
|
2014-10-02 17:32:08 +02:00
|
|
|
val feedbackLoopBuffer = Flow[String].buffer(10, OverflowStrategy.dropBuffer)
|
2015-01-28 14:19:50 +01:00
|
|
|
b.addEdge(b.add(in1), f1, merge.in(0))
|
|
|
|
|
b.addEdge(merge.out, f2, bcast1.in)
|
|
|
|
|
b.addEdge(bcast1.out(0), f3, b.add(out1))
|
|
|
|
|
b.addEdge(bcast1.out(1), feedbackLoopBuffer, bcast2.in)
|
|
|
|
|
b.addEdge(bcast2.out(0), f5, merge.in(1)) // cycle
|
|
|
|
|
b.addEdge(bcast2.out(1), f6, b.add(out2))
|
2014-09-04 14:31:22 +02:00
|
|
|
}
|
|
|
|
|
}.getMessage.toLowerCase should include("cycle")
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"express complex topologies in a readable way" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
val merge = b.add(Merge[String](2))
|
|
|
|
|
val bcast1 = b.add(Broadcast[String](2))
|
|
|
|
|
val bcast2 = b.add(Broadcast[String](2))
|
2014-10-02 17:32:08 +02:00
|
|
|
val feedbackLoopBuffer = Flow[String].buffer(10, OverflowStrategy.dropBuffer)
|
2015-01-28 14:19:50 +01:00
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
b.add(in1) ~> f1 ~> merge ~> f2 ~> bcast1 ~> f3 ~> b.add(out1)
|
2014-09-11 08:56:58 +02:00
|
|
|
bcast1 ~> feedbackLoopBuffer ~> bcast2 ~> f5 ~> merge
|
2015-01-28 14:19:50 +01:00
|
|
|
bcast2 ~> f6 ~> b.add(out2)
|
2014-09-11 08:56:58 +02:00
|
|
|
}.run()
|
2014-09-04 14:31:22 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-10 12:56:18 +02:00
|
|
|
"build broadcast - merge" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
val bcast = b.add(Broadcast[String](2))
|
|
|
|
|
val merge = b.add(Merge[String](2))
|
|
|
|
|
import FlowGraph.Implicits._
|
2014-09-10 12:56:18 +02:00
|
|
|
in1 ~> f1 ~> bcast ~> f2 ~> merge ~> f3 ~> out1
|
2014-09-11 07:43:05 +02:00
|
|
|
bcast ~> f4 ~> merge
|
2014-09-10 12:56:18 +02:00
|
|
|
}.run()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"build wikipedia Topological_sorting" in {
|
|
|
|
|
// see https://en.wikipedia.org/wiki/Topological_sorting#mediaviewer/File:Directed_acyclic_graph.png
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
val b3 = b.add(Broadcast[String](2))
|
|
|
|
|
val b7 = b.add(Broadcast[String](2))
|
|
|
|
|
val b11 = b.add(Broadcast[String](3))
|
|
|
|
|
val m8 = b.add(Merge[String](2))
|
|
|
|
|
val m9 = b.add(Merge[String](2))
|
|
|
|
|
val m10 = b.add(Merge[String](2))
|
|
|
|
|
val m11 = b.add(Merge[String](2))
|
2014-10-17 14:05:50 +02:00
|
|
|
val in3 = Source(List("b"))
|
|
|
|
|
val in5 = Source(List("b"))
|
|
|
|
|
val in7 = Source(List("a"))
|
|
|
|
|
val out2 = Sink.publisher[String]
|
|
|
|
|
val out9 = Sink.publisher[String]
|
|
|
|
|
val out10 = Sink.publisher[String]
|
2015-04-09 15:16:59 +02:00
|
|
|
def f(s: String) = Flow[String].transform(op[String, String]).named(s)
|
2015-01-28 14:19:50 +01:00
|
|
|
import FlowGraph.Implicits._
|
2014-09-10 12:56:18 +02:00
|
|
|
|
|
|
|
|
in7 ~> f("a") ~> b7 ~> f("b") ~> m11 ~> f("c") ~> b11 ~> f("d") ~> out2
|
|
|
|
|
b11 ~> f("e") ~> m9 ~> f("f") ~> out9
|
|
|
|
|
b7 ~> f("g") ~> m8 ~> f("h") ~> m9
|
|
|
|
|
b11 ~> f("i") ~> m10 ~> f("j") ~> out10
|
|
|
|
|
in5 ~> f("k") ~> m11
|
|
|
|
|
in3 ~> f("l") ~> b3 ~> f("m") ~> m8
|
|
|
|
|
b3 ~> f("n") ~> m10
|
|
|
|
|
}.run()
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-11 07:45:19 +02:00
|
|
|
"make it optional to specify flows" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
val merge = b.add(Merge[String](2))
|
|
|
|
|
val bcast = b.add(Broadcast[String](2))
|
|
|
|
|
import FlowGraph.Implicits._
|
2014-09-11 07:45:19 +02:00
|
|
|
in1 ~> merge ~> bcast ~> out1
|
|
|
|
|
in2 ~> merge
|
|
|
|
|
bcast ~> out2
|
|
|
|
|
}.run()
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-30 14:03:22 +02:00
|
|
|
"build unzip - zip" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
val zip = b.add(Zip[Int, String]())
|
|
|
|
|
val unzip = b.add(Unzip[Int, String]())
|
2014-10-17 14:05:50 +02:00
|
|
|
val out = Sink.publisher[(Int, String)]
|
2015-01-28 14:19:50 +01:00
|
|
|
import FlowGraph.Implicits._
|
2014-10-02 17:32:08 +02:00
|
|
|
Source(List(1 -> "a", 2 -> "b", 3 -> "c")) ~> unzip.in
|
2015-01-28 14:19:50 +01:00
|
|
|
unzip.out0 ~> Flow[Int].map(_ * 2) ~> zip.in0
|
|
|
|
|
unzip.out1 ~> zip.in1
|
2014-09-30 14:03:22 +02:00
|
|
|
zip.out ~> out
|
|
|
|
|
}.run()
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-09 15:22:49 +02:00
|
|
|
"distinguish between input and output ports" in {
|
|
|
|
|
intercept[IllegalArgumentException] {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
val zip = b.add(Zip[Int, String]())
|
|
|
|
|
val unzip = b.add(Unzip[Int, String]())
|
2014-10-17 14:05:50 +02:00
|
|
|
val wrongOut = Sink.publisher[(Int, Int)]
|
|
|
|
|
val whatever = Sink.publisher[Any]
|
2014-10-02 17:32:08 +02:00
|
|
|
"Flow(List(1, 2, 3)) ~> zip.left ~> wrongOut" shouldNot compile
|
|
|
|
|
"""Flow(List("a", "b", "c")) ~> zip.left""" shouldNot compile
|
|
|
|
|
"""Flow(List("a", "b", "c")) ~> zip.out""" shouldNot compile
|
2014-09-09 15:22:49 +02:00
|
|
|
"zip.left ~> zip.right" shouldNot compile
|
2014-10-02 17:32:08 +02:00
|
|
|
"Flow(List(1, 2, 3)) ~> zip.left ~> wrongOut" shouldNot compile
|
|
|
|
|
"""Flow(List(1 -> "a", 2 -> "b", 3 -> "c")) ~> unzip.in ~> whatever""" shouldNot compile
|
2014-09-09 15:22:49 +02:00
|
|
|
}
|
2015-01-28 14:19:50 +01:00
|
|
|
}.getMessage should include("unconnected")
|
2014-09-12 12:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-30 15:40:08 +02:00
|
|
|
"build with variance" in {
|
2015-04-24 11:45:03 +03:00
|
|
|
val out = Sink(TestSubscriber.manualProbe[Fruit]())
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
val merge = b.add(Merge[Fruit](2))
|
|
|
|
|
b.addEdge(b add Source[Fruit](apples), Flow[Fruit], merge.in(0))
|
|
|
|
|
b.addEdge(b add Source[Apple](apples), Flow[Apple], merge.in(1))
|
|
|
|
|
b.addEdge(merge.out, Flow[Fruit].map(identity), b add out)
|
2014-09-30 15:40:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-02 14:47:22 +03:00
|
|
|
"build with variance when indices are not specified" in {
|
|
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
val fruitMerge = b.add(Merge[Fruit](2))
|
|
|
|
|
Source[Fruit](apples) ~> fruitMerge
|
|
|
|
|
Source[Apple](apples) ~> fruitMerge
|
|
|
|
|
fruitMerge ~> Sink.head[Fruit]
|
|
|
|
|
"fruitMerge ~> Sink.head[Apple]" shouldNot compile
|
|
|
|
|
|
|
|
|
|
val appleMerge = b.add(Merge[Apple](1))
|
|
|
|
|
"Source[Fruit](apples) ~> appleMerge" shouldNot compile
|
|
|
|
|
Source[Apple](apples) ~> appleMerge
|
|
|
|
|
appleMerge ~> Sink.head[Fruit]
|
|
|
|
|
|
|
|
|
|
val appleMerge2 = b.add(Merge[Apple](1))
|
|
|
|
|
Source[Apple](apples) ~> appleMerge2
|
|
|
|
|
appleMerge2 ~> Sink.head[Apple]
|
|
|
|
|
|
|
|
|
|
val fruitBcast = b.add(Broadcast[Fruit](1))
|
|
|
|
|
Source[Fruit](apples) ~> fruitBcast
|
|
|
|
|
//Source[Apple](apples) ~> fruitBcast // FIXME: should compile #16997
|
|
|
|
|
fruitBcast ~> Sink.head[Fruit]
|
|
|
|
|
"fruitBcast ~> Sink.head[Apple]" shouldNot compile
|
|
|
|
|
|
|
|
|
|
val appleBcast = b.add(Broadcast[Apple](2))
|
|
|
|
|
"Source[Fruit](apples) ~> appleBcast" shouldNot compile
|
|
|
|
|
Source[Apple](apples) ~> appleBcast
|
|
|
|
|
appleBcast ~> Sink.head[Fruit]
|
|
|
|
|
appleBcast ~> Sink.head[Apple]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-30 15:40:08 +02:00
|
|
|
"build with implicits and variance" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
2015-06-18 22:24:24 +02:00
|
|
|
def appleSource = b.add(Source(TestPublisher.manualProbe[Apple]()))
|
|
|
|
|
def fruitSource = b.add(Source(TestPublisher.manualProbe[Fruit]()))
|
2015-04-24 11:45:03 +03:00
|
|
|
val outA = b add Sink(TestSubscriber.manualProbe[Fruit]())
|
|
|
|
|
val outB = b add Sink(TestSubscriber.manualProbe[Fruit]())
|
2015-01-28 14:19:50 +01:00
|
|
|
val merge = b add Merge[Fruit](11)
|
|
|
|
|
val unzip = b add Unzip[Int, String]()
|
|
|
|
|
val whatever = b add Sink.publisher[Any]
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
b.add(Source[Fruit](apples)) ~> merge.in(0)
|
|
|
|
|
appleSource ~> merge.in(1)
|
|
|
|
|
appleSource ~> merge.in(2)
|
|
|
|
|
fruitSource ~> merge.in(3)
|
|
|
|
|
fruitSource ~> Flow[Fruit].map(identity) ~> merge.in(4)
|
|
|
|
|
appleSource ~> Flow[Apple].map(identity) ~> merge.in(5)
|
|
|
|
|
b.add(Source(apples)) ~> merge.in(6)
|
|
|
|
|
b.add(Source(apples)) ~> Flow[Fruit].map(identity) ~> merge.in(7)
|
|
|
|
|
b.add(Source(apples)) ~> Flow[Apple].map(identity) ~> merge.in(8)
|
|
|
|
|
merge.out ~> Flow[Fruit].map(identity) ~> outA
|
|
|
|
|
|
|
|
|
|
b.add(Source(apples)) ~> Flow[Apple] ~> merge.in(9)
|
|
|
|
|
b.add(Source(apples)) ~> Flow[Apple] ~> outB
|
|
|
|
|
b.add(Source(apples)) ~> Flow[Apple] ~> b.add(Sink.publisher[Fruit])
|
|
|
|
|
appleSource ~> Flow[Apple] ~> merge.in(10)
|
2014-09-30 15:40:08 +02:00
|
|
|
|
2014-10-02 17:32:08 +02:00
|
|
|
Source(List(1 -> "a", 2 -> "b", 3 -> "c")) ~> unzip.in
|
2015-01-28 14:19:50 +01:00
|
|
|
unzip.out1 ~> whatever
|
|
|
|
|
unzip.out0 ~> b.add(Sink.publisher[Any])
|
2014-10-01 13:24:57 +02:00
|
|
|
|
2015-01-28 14:19:50 +01:00
|
|
|
"merge.out ~> b.add(Broadcast[Apple](2))" shouldNot compile
|
|
|
|
|
"merge.out ~> Flow[Fruit].map(identity) ~> b.add(Broadcast[Apple](2))" shouldNot compile
|
|
|
|
|
"fruitSource ~> merge ~> b.add(Broadcast[Apple](2))" shouldNot compile
|
2014-09-30 15:40:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-01 09:41:34 +02:00
|
|
|
"build with plain flow without junctions" in {
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
b.addEdge(b.add(in1), f1, b.add(out1))
|
2014-10-01 09:41:34 +02:00
|
|
|
}.run()
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
b.addEdge(b.add(in1), f1, b.add(f2.to(out1)))
|
2014-10-01 09:41:34 +02:00
|
|
|
}.run()
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { b ⇒
|
|
|
|
|
b.addEdge(b.add(in1 via f1), f2, b.add(out1))
|
2014-10-01 09:41:34 +02:00
|
|
|
}.run()
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
b.add(in1) ~> f1 ~> b.add(out1)
|
2014-10-01 09:41:34 +02:00
|
|
|
}.run()
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
b.add(in1) ~> b.add(out1)
|
2014-10-01 09:41:34 +02:00
|
|
|
}.run()
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
b.add(in1) ~> b.add(f1 to out1)
|
2014-10-01 09:41:34 +02:00
|
|
|
}.run()
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
b.add(in1 via f1) ~> b.add(out1)
|
2014-10-01 09:41:34 +02:00
|
|
|
}.run()
|
2015-01-28 14:19:50 +01:00
|
|
|
FlowGraph.closed() { implicit b ⇒
|
|
|
|
|
import FlowGraph.Implicits._
|
|
|
|
|
b.add(in1 via f1) ~> b.add(f2 to out1)
|
2014-10-03 15:13:26 +02:00
|
|
|
}.run()
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-04 14:31:22 +02:00
|
|
|
}
|
|
|
|
|
}
|