Skip to content

Commit

Permalink
Now able to produce a contentUnified view
Browse files Browse the repository at this point in the history
  • Loading branch information
themerius committed Jun 3, 2014
1 parent 2a87ab2 commit 230e695
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 12 deletions.
58 changes: 53 additions & 5 deletions src/main/scala/scaltex/BaseActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import akka.actor.Actor
import akka.actor.ActorRef
import akka.actor.ActorSelection

import com.github.pathikrit.dijon.`{}`
import com.github.pathikrit.dijon.{ `{}`, `[]` }
import com.github.pathikrit.dijon.parse

import com.m3.curly.HTTP
Expand All @@ -25,10 +25,12 @@ abstract class BaseActor(updater: ActorRef) extends Actor with DiscoverReference
// State (to be saved in DB):
var state = `{}`
this.state._id = self.path.name
this.state.variableName = ""
this.state.documentElement = ""
this.state.contentSrc = ""
this.state.contentRepr = ""
this.state.contentEval = ""
this.state.contentUnified = `[]`

var rev = ""
var stateHash = 0
Expand All @@ -42,6 +44,9 @@ abstract class BaseActor(updater: ActorRef) extends Actor with DiscoverReference
case Change(to) =>
`change current doc elem`(to)

case ChangeName(to) =>
`change variable name`(to)

case Next(id) =>
`change next ref`(id)

Expand All @@ -62,8 +67,8 @@ abstract class BaseActor(updater: ActorRef) extends Actor with DiscoverReference
case RequestForCodeGen(requester, others) =>
`reply with code, pass request along`(requester, others)

case ReplyForCodeGen(code, replyEnd) =>
`buffer code then trigger interpretation`(code, replyEnd)
case ReplyForCodeGen(code, shortName, replyEnd) =>
`buffer code then trigger interpretation`(code, shortName, replyEnd)

case ReturnValue(repr) =>
`change content repr, send curr state`(repr)
Expand Down Expand Up @@ -202,14 +207,53 @@ abstract class BaseActor(updater: ActorRef) extends Actor with DiscoverReference
if (!triggered) sendCurrentState
}

def `buffer code then trigger interpretation`(code: String, replyEnd: Boolean): Unit = {
def `buffer code then trigger interpretation`(code: String, shortName: Tuple2[String, String], replyEnd: Boolean): Unit = {
replyCodeBuffer += code
val uuid = shortName._1
val name = shortName._2
replyNameBuffer(uuid) = name
if (replyEnd) triggerInterpreter
}

def `change content repr, send curr state`(repr: Any): Unit = {
this.state.contentRepr = repr.toString
val reprTuple = repr.asInstanceOf[scaltex.utils.StringContext.Unify]
this.state.contentRepr = reprTuple._1.toString
documentElement._gotUpdate(this.state, refs)
// TODO: refactor
val results = reprTuple._2
val staticParts = reprTuple._3

val contentSrc = this.state.contentSrc.as[String].get
val expressions = expRegex.findAllIn(contentSrc).map(_.toString).toList
val splittedExpr = expressions.map(_.split(uuidRegex.toString)).toList
val uuids = expressions.map(uuidRegex.findAllMatchIn(_).map(_.toString).toList)

val shortNames = replyNameBuffer.toMap
replyNameBuffer.clear // TODO: risky? Other interpreation may already run?

// equal size: expressions, splittedExpr, uuids->shortName, results
// size + 1: static parts
for (idx <- 0 until results.size) {
this.state.contentUnified(idx) = `{}`
this.state.contentUnified(idx).str = staticParts(idx)
this.state.contentUnified(idx).result = results(idx)
this.state.contentUnified(idx).expression = `[]`
var currJsonIdx = 0
for (jdx <- 0 until splittedExpr(idx).size) {
this.state.contentUnified(idx).expression(currJsonIdx) = splittedExpr(idx)(jdx)
if (uuids(idx).indices.contains(jdx)) {
currJsonIdx += 1
this.state.contentUnified(idx).expression(currJsonIdx) = `{}`
this.state.contentUnified(idx).expression(currJsonIdx).uuid = uuids(idx)(jdx)
this.state.contentUnified(idx).expression(currJsonIdx).shortName = shortNames(uuids(idx)(jdx))
}
currJsonIdx += 1
}
}

this.state.contentUnified(staticParts.size - 1) = `{}`
this.state.contentUnified(staticParts.size - 1).str = staticParts.last

sendCurrentState
}

Expand All @@ -225,4 +269,8 @@ abstract class BaseActor(updater: ActorRef) extends Actor with DiscoverReference
this.state.documentElement = to
}

def `change variable name`(to: String): Unit = {
this.state.variableName = to
}

}
21 changes: 15 additions & 6 deletions src/main/scala/scaltex/DiscoverReferences.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package scaltex

import Messages._
import akka.actor.ActorRef
import scala.collection.mutable.Buffer
import scala.collection.mutable.Map

trait DiscoverReferences {
this: BaseActor =>

val uuidRegex = "id_[\\$_a-zA-Z0-9]*_id".r
val expRegex = """\$\{.*?\}""".r

def findAllActorRefs(in: String) = {
val allIds = "id_[\\$_a-zA-Z0-9]*_id".r.findAllIn(in)
val allIds = uuidRegex.findAllIn(in)
val withCuttedIds = allIds.map(x => x.slice(3, x.size - 3))
withCuttedIds.toList
}
Expand All @@ -24,7 +29,9 @@ trait DiscoverReferences {
}

def `reply with code, pass request along`(requester: ActorRef, others: List[String]): Unit = {
requester ! ReplyForCodeGen(genCode, others.size == 0)
val shortName = this.state.variableName.as[String].get
val uuid = "id_" + this.id + "_id"
requester ! ReplyForCodeGen(genCode, (uuid, shortName), others.size == 0)
if (others.size > 0) {
val codeGenRequest = RequestForCodeGen(requester, others.tail)
root ! Pass(others.head, codeGenRequest)
Expand All @@ -40,19 +47,21 @@ trait DiscoverReferences {
code
}

val replyCodeBuffer = scala.collection.mutable.Buffer[String]()
val replyCodeBuffer = Buffer[String]()
val replyNameBuffer = Map[String, String]()

def triggerInterpreter = {
val references = replyCodeBuffer.toSet.mkString("\n")
replyCodeBuffer.clear

// Note: this.state.contentSrc delivers already quotes -> "..."
val content = "s\"\"" + this.state.contentSrc + "\"\""
val content = "unify\"\"" + this.state.contentSrc + "\"\""
val completeCode = s"""
| import com.github.pathikrit.dijon.JsonStringContext
| import scaltex.utils.StringContext.Unifier
| ${references}
| val contentRepr = ${content}
| contentRepr
| val (contentRepr, exprResults, staticParts) = ${content}
| (contentRepr, exprResults, staticParts)
""".stripMargin

val interpreterActor = context.actorSelection("/user/interpreter") // TODO: inject from outside?
Expand Down
3 changes: 2 additions & 1 deletion src/main/scala/scaltex/Messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ object Messages {

// modify actors
case class Change(to: String)
case class ChangeName(to: String)
case class Content(content: String)

case class UpdateStateProperty(json: String)
Expand All @@ -23,7 +24,7 @@ object Messages {
case class Interpret(code: String, returnId: String)
case class ReturnValue(is: Any)
case class RequestForCodeGen(requester: ActorRef, others: List[String])
case class ReplyForCodeGen(code: String, replyEnd: Boolean)
case class ReplyForCodeGen(code: String, shortName: Tuple2[String, String], replyEnd: Boolean)

// Messages for registring websockets
case class RegisterWebsocket(ref: ActorRef)
Expand Down
15 changes: 15 additions & 0 deletions src/main/scala/scaltex/utils/UnifierStringContext.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package scaltex.utils

object StringContext {

type Unify = Tuple3[String, List[String], List[String]]

implicit class Unifier(val sc: StringContext) {
def unify(args: Any*): Unify = {
val exprResults = args.map(_.toString).toList
val parts = sc.parts.toList
(sc.s(args: _*), exprResults, parts)
}
}

}
21 changes: 21 additions & 0 deletions src/test/scala/scaltex/DiscoverReferencesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,25 @@ class DiscoverReferencesSpec

}

"Unified content" should {

"be an array with the expression details" in {
`1` ! ChangeName("nameOfX")
`2` ! Update

updater.expectMsgPF() {
case CurrentState(json) =>
val state = parse(json)
state._id should be(`2`.path.name)
state.contentRepr should be("Has one reference: Section!")
state.contentUnified(0).str should be ("Has one reference: ")
state.contentUnified(0).result should be ("Section")
state.contentUnified(0).expression(0) should be ("${")
state.contentUnified(0).expression(1).uuid should be ("id_" + `1`.path.name + "_id")
state.contentUnified(0).expression(1).shortName should be ("nameOfX")
state.contentUnified(0).expression(2) should be (".getClass.getSimpleName}")
}
}
}

}
18 changes: 18 additions & 0 deletions src/test/scala/scaltex/models/ReportSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,22 @@ class ReportSpec

}

"A element with a variable (short) name" should {

"be part of the base actor state" in {
val ref = TestActorRef(new AvailableModels.Report(updater.ref))

ref.underlyingActor.state.variableName should be("")
}

"be changeable" in {
val ref = TestActorRef(new AvailableModels.Report(updater.ref))

ref.underlyingActor.state.variableName should be("")
ref ! ChangeName("myName")
ref.underlyingActor.state.variableName should be("myName")
}

}

}

0 comments on commit 230e695

Please sign in to comment.