Fixing Play Scalate

353 views
Skip to first unread message

Matt Raible

unread,
Aug 30, 2011, 3:17:35 PM8/30/11
to play-framework
Hello all,

I've tried contacting the Play-Scalate project owner, but haven't had
a response. I'm trying to upgrade the library to the latest
dependencies to get it working with Play 1.2.3 and Scalate 1.5.1. I've
forked the project and committed the following changes to try and get
it working.

https://github.com/mraible/play-scalate/commit/5743135cf6b6cfafe300f95239596347309677fe

There's a good chance I've messed things up, but there's less
compilation issues and it feels like I'm making progress. However, I'm
unable to diagnose and figure out how to solve the following
compilation error.

$ ant
Buildfile: /Users/mraible/dev/play-scalate/build.xml

clean:
[delete] Deleting directory /Users/mraible/dev/play-scalate/tmp

build:
[mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes
[scalac] Compiling 7 source files to /Users/mraible/dev/play-
scalate/tmp/classes
[scalac] error: class file needed by Binding is missing.
[scalac] reference type Serializable of package scala refers to
nonexisting symbol.
[scalac] one error found

BUILD FAILED
/Users/mraible/dev/play-scalate/build.xml:34: Compile failed with 1
error; see the compiler error output for details.

Total time: 8 seconds

If you have any advice, I'd love to hear it.

Guillaume Bort

unread,
Aug 30, 2011, 3:50:09 PM8/30/11
to play-fr...@googlegroups.com
It looks like an incompatible Scala version error. The play scala
module currently use Scala 2.8.1, what is the Scala version needed by
Scalate?

> --
> You received this message because you are subscribed to the Google Groups "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.
>
>

--
Guillaume Bort, http://guillaume.bort.fr

Matt Raible

unread,
Aug 30, 2011, 4:12:16 PM8/30/11
to play-framework
Good catch. If you look at the Scalate homepage, it says it's "Scala
2.8" template engine, but if you dig through the release notes, you
can see that they upgraded to 2.9 in 1.5.

On Aug 30, 1:50 pm, Guillaume Bort <guillaume.b...@gmail.com> wrote:
> It looks like an incompatible Scala version error. The play scala
> module currently use Scala 2.8.1, what is the Scala version needed by
> Scalate?
>
>
>
>
>
>
>
>
>
> On Tue, Aug 30, 2011 at 9:17 PM, Matt Raible <mrai...@gmail.com> wrote:
> > Hello all,
>
> > I've tried contacting the Play-Scalate project owner, but haven't had
> > a response. I'm trying to upgrade the library to the latest
> > dependencies to get it working with Play 1.2.3 and Scalate 1.5.1. I've
> > forked the project and committed the following changes to try and get
> > it working.
>
> >https://github.com/mraible/play-scalate/commit/5743135cf6b6cfafe300f9...

Matt Raible

unread,
Aug 30, 2011, 4:22:14 PM8/30/11
to play-framework
I changed the dependencies to use the Scala 2.8.1 compiler and
downgraded to Scalate 2.4.1 (which says it uses 2.8.1). This results
in the following error when building:

$ ant
Buildfile: /Users/mraible/dev/play-scalate/build.xml

clean:
[delete] Deleting directory /Users/mraible/dev/play-scalate/tmp

build:
[mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes
[scalac] Compiling 7 source files to /Users/mraible/dev/play-
scalate/tmp/classes
[scalac] error: class file needed by ScalaController is missing.
[scalac] reference value dispatch of package <root> refers to
nonexisting symbol.
[scalac] one error found

BUILD FAILED
/Users/mraible/dev/play-scalate/build.xml:34: Compile failed with 1
error; see the compiler error output for details.

Guillaume Bort

unread,
Aug 31, 2011, 3:57:28 AM8/31/11
to play-fr...@googlegroups.com
Again it looks like an incompatible Scala library in the compile path.
Perhaps it is another library, can you list the jar files you have
added?

Matt Raible

unread,
Aug 31, 2011, 12:41:58 PM8/31/11
to play-framework
Here's the JAR files I have in the lib directory:

play-scala-20110830.jar
scala-compiler-2.8.1.jar
scala-library-2.8.1.jar
scalate-core-1.4.1.jar
scalate-util-1.4.1.jar
scalatest-1.2-for-scala-2.8.0.RC7-SNAPSHOT.jar

I've checked in all my changes to https://github.com/mraible/play-scalate

Guillaume Bort

unread,
Aug 31, 2011, 3:43:09 PM8/31/11
to play-fr...@googlegroups.com
Matt,

Probably a better (and simpler) start for you, here is my test to make
Scalate work with the current Play version (my test use Jade):

https://gist.github.com/1184490

All you need is to drop scalate-core and scalate-utils jars into the
lib directory of your application (or add them as managed dependencies
to the yaml file).

There is no clean error report yet, but it should be really easy to
add for compilation errors since they already contain the problem
position. Not sure how difficult it will be to report properly
execution errors.

Matt Raible

unread,
Aug 31, 2011, 5:16:16 PM8/31/11
to play-fr...@googlegroups.com
Thanks Guillaume!

I was able to use this example to get things working.

Improvements I'd like to see:

1. Allow the Scalate syntax to be configurable.

I did this with the following in Scalate:

case class Template(name: String) {
val scalateType = "." + Play.configuration.get("scalate");

def render(args: (Symbol, Any)*) = {
scalateEngine.layout(name + scalateType, args.map {
case (k, v) => k.name -> v
} toMap)
}
}

2. Like regular templates, change things so def index {} in Application can have something like the following:

def index = {
render('user -> User("Guillaume"))
}

And "Application/index" will be passed into the Scalate constructor. What's the best way to do this? Create a ScalateController that overrides render() and is able to introspect the class/method names?

Thanks,

Matt

Matt Raible

unread,
Aug 31, 2011, 11:42:46 PM8/31/11
to play-framework


On Aug 31, 3:16 pm, Matt Raible <mrai...@gmail.com> wrote:
> Thanks Guillaume!
>
> I was able to use this example to get things working.
>
> Improvements I'd like to see:
>
> 1. Allow theScalatesyntax to be configurable.
>
> I did this with the following inScalate:
>
>  case class Template(name: String) {
>    val scalateType = "." + Play.configuration.get("scalate");
>
>    def render(args: (Symbol, Any)*) = {
>      scalateEngine.layout(name + scalateType, args.map {
>        case (k, v) => k.name -> v
>      } toMap)
>    }
>  }
>
> 2. Like regular templates, change things so def index {} in Application can have something like the following:
>
>  def index = {
>    render('user -> User("Guillaume"))
>  }
>
> And "Application/index" will be passed into theScalateconstructor. What's the best way to do this? Create a ScalateController that overrides render() and is able to introspect the class/method names?
>

I was able to get this working by creating a ScalateController as
follows:

package controllers

import play.mvc.{Http, Controller}
import models.User._

class ScalateController extends Controller {

def render(args: (Symbol, Any)*) = {
def defaultTemplate = Http.Request.current().action.replace(".",
"/")
Scalate(defaultTemplate).render(args: _*);
}
}

Then my controller's index() method is as simple as:

def index = {
render('user -> User("Raible"))
}

I'd like to further simplify things to match the Hello World example
for Java (http://www.playframework.org/documentation/1.0/firstapp).

How would I go about modifying things so I can have a method like the
following?

def sayHello(name: String) = {
render(name)
}

Without having to do render('name -> name)?

In my Jade template, I'd also like to simplify and not have to define
"name" as a variable. Currently, I have to have the following in
sayHello.jade:

-@ var name: String
p Hi #{name: String}

Thanks for any advice.

Matt




>
> On Aug 31, 2011, at 1:43 PM, Guillaume Bort wrote:
>
>
>
> > Matt,
>
> > Probably a better (and simpler) start for you, here is my test to make
> >Scalatework with the current Play version (my test use Jade):
>
> >https://gist.github.com/1184490
>
> > All you need is to dropscalate-core andscalate-utils jars into the
> > lib directory of your application (or add them as managed dependencies
> > to the yaml file).
>
> > There is no clean error report yet, but it should be really easy to
> > add for compilation errors since they already contain the problem
> > position. Not sure how difficult it will be to report properly
> > execution errors.
>
> > On Wed, Aug 31, 2011 at 6:41 PM, Matt Raible <mrai...@gmail.com> wrote:
> >> Here's the JAR files I have in the lib directory:
>
> >> play-scala-20110830.jar
> >> scala-compiler-2.8.1.jar
> >> scala-library-2.8.1.jar
> >>scalate-core-1.4.1.jar
> >>scalate-util-1.4.1.jar
> >> scalatest-1.2-for-scala-2.8.0.RC7-SNAPSHOT.jar
>
> >> I've checked in all my changes tohttps://github.com/mraible/play-scalate
>
> >> On Aug 31, 1:57 am, Guillaume Bort <guillaume.b...@gmail.com> wrote:
> >>> Again it looks like an incompatible Scala library in the compile path.
> >>> Perhaps it is another library, can you list the jar files you have
> >>> added?
>
> >>> On Tue, Aug 30, 2011 at 10:22 PM, Matt Raible <mrai...@gmail.com> wrote:
> >>>> I changed the dependencies to use the Scala 2.8.1 compiler and
> >>>> downgraded toScalate2.4.1 (which says it uses 2.8.1). This results
> >>>> in the following error when building:
>
> >>>> $ ant
> >>>> Buildfile: /Users/mraible/dev/play-scalate/build.xml
>
> >>>> clean:
> >>>>  [delete] Deleting directory /Users/mraible/dev/play-scalate/tmp
>
> >>>> build:
> >>>>   [mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes
> >>>>  [scalac] Compiling 7 source files to /Users/mraible/dev/play-
> >>>>scalate/tmp/classes
> >>>>  [scalac] error: class file needed by ScalaController is missing.
> >>>>  [scalac] reference value dispatch of package <root> refers to
> >>>> nonexisting symbol.
> >>>>  [scalac] one error found
>
> >>>> BUILD FAILED
> >>>> /Users/mraible/dev/play-scalate/build.xml:34: Compile failed with 1
> >>>> error; see the compiler error output for details.
>
> >>>> On Aug 30, 2:12 pm, Matt Raible <mrai...@gmail.com> wrote:
> >>>>> Good catch. If you look at theScalatehomepage, it says it's "Scala
> >>>>> 2.8" template engine, but if you dig through the release notes, you
> >>>>> can see that they upgraded to 2.9 in 1.5.
>
> >>>>> On Aug 30, 1:50 pm, Guillaume Bort <guillaume.b...@gmail.com> wrote:
>
> >>>>>> It looks like an incompatible Scala version error. The play scala
> >>>>>> module currently use Scala 2.8.1, what is the Scala version needed by
> >>>>>>Scalate?
>
> >>>>>> On Tue, Aug 30, 2011 at 9:17 PM, Matt Raible <mrai...@gmail.com> wrote:
> >>>>>>> Hello all,
>
> >>>>>>> I've tried contacting the Play-Scalateproject owner, but haven't had
> >>>>>>> a response. I'm trying to upgrade the library to the latest
> >>>>>>> dependencies to get it working with Play 1.2.3 andScalate1.5.1. I've

Guillaume Bort

unread,
Sep 1, 2011, 4:16:26 AM9/1/11
to play-fr...@googlegroups.com
> class ScalateController extends Controller {
>
>  def render(args: (Symbol, Any)*) = {
>    def defaultTemplate = Http.Request.current().action.replace(".",
> "/")
>    Scalate(defaultTemplate).render(args: _*);
>  }
> }

Yes, but you should use a Trait instead, so it's easier to mix several
concerns into your controller.

object Application extends Controller with Scalate {
...
}

> How would I go about modifying things so I can have a method like the
> following?
>
>  def sayHello(name: String) = {
>    render(name)
>  }
>

In Java, this feature relies on heavy bytecode manipulation that we
have disabled for Scala. In theory for your simple use case it could
work, but Scala is way more complicated and there is a lot of
constructs where it would not be possible to track local variable
names properly.

> In my Jade template, I'd also like to simplify and not have to define
> "name" as a variable. Currently, I have to have the following in
> sayHello.jade:
>
> -@ var name: String
> p Hi #{name: String}

I don't know if it is possible with Scalate? If yes, there should be a
configuration setting to set somewhere on the TemplateEngine.

Matt Raible

unread,
Sep 1, 2011, 6:56:47 PM9/1/11
to play-fr...@googlegroups.com
Thanks for the advice. Now I have it working with Scalate as a trait.

The next issue I'm running into is running it in prod mode. Is there any way to stop Groovy from trying to compile my Jade templates?

$ play run
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.2.3, http://www.playframework.org
~
~ Ctrl+C to stop
~
16:49:32,968 INFO ~ Starting /Users/mraible/dev/play-more
16:49:32,973 INFO ~ Module coffee is available (/Users/mraible/dev/play-more/modules/coffee-1.0)
16:49:32,974 INFO ~ Module scala is available (/opt/tools/play-1.2.1/modules/scala-0.9.1)
16:49:34,492 INFO ~ Scala support is active
16:49:34,642 INFO ~ Scala support is active
16:49:34,643 INFO ~ Precompiling ...
Compiling:
/Users/mraible/dev/play-more/modules/coffee-1.0/app/tags/CoffeeTags.java
16:49:37,491 ERROR ~

@67iec0he2
Cannot start in PROD mode with errors

Template compilation error (In /app/views/Application/index.jade around line 2)
The template /app/views/Application/index.jade does not compile : #{user.name} is not closed.

play.exceptions.TemplateCompilationException: #{user.name} is not closed.
at play.templates.TemplateCompiler.generate(TemplateCompiler.java:102)
at play.templates.TemplateCompiler.compile(TemplateCompiler.java:15)
at play.templates.GroovyTemplateCompiler.compile(GroovyTemplateCompiler.java:41)
at play.templates.TemplateCompiler.compile(TemplateCompiler.java:26)
at play.templates.TemplateLoader.load(TemplateLoader.java:82)
at play.templates.TemplateLoader.scan(TemplateLoader.java:222)
at play.templates.TemplateLoader.scan(TemplateLoader.java:235)
at play.templates.TemplateLoader.scan(TemplateLoader.java:235)
at play.templates.TemplateLoader.getAllTemplate(TemplateLoader.java:205)
at play.Play.preCompile(Play.java:570)
at play.Play.init(Play.java:291)
at play.server.Server.main(Server.java:158)

Guillaume Bort

unread,
Sep 2, 2011, 4:29:53 AM9/2/11
to play-fr...@googlegroups.com
Easy way: use another folder than view. Otherwise you can create a
plugin then redefine loadTemplate to ignore Scalates one (return null
as this interface is defined in the Java part):

override def loadTemplate(file:VirtualFile )

Matt Raible

unread,
Sep 2, 2011, 10:53:03 AM9/2/11
to play-fr...@googlegroups.com
Thanks! The easy way worked and it's "good enough" for now.

Matt Raible

unread,
Oct 16, 2011, 10:23:55 AM10/16/11
to play-framework
What's the best way to make renderArgs and local variable names
available to my Scalate templates? Here's a method I wrote to populate
them:

def populateRenderArgs(args: (Symbol, Any)*) = {
val renderArgs = Scope.RenderArgs.current();
for (o <- args) {
val names =
LocalVariablesNamesTracer.getAllLocalVariableNames(o);
for (name <- names) {
renderArgs.put(name, o);
}
}

renderArgs.put("session", Scope.Session.current());
renderArgs.put("request", Http.Request.current());
renderArgs.put("flash", Scope.Flash.current());
renderArgs.put("params", Scope.Params.current());
renderArgs.put("errors", Validation.errors());
}

However, I'm unsure of how to combine renderArgs with my args:

case class Template(name: String) {

def render(args: (Symbol, Any)*) = {
// this doesn't work: args ++ Scope.RenderArgs.current().data;
scalateEngine.layout(name + scalateType, args.map {
case (k, v) => k.name -> v
} toMap)
}
}

Thanks for any advice.

Matt

On Sep 2, 8:53 am, Matt Raible <mrai...@gmail.com> wrote:
> Thanks! The easy way worked and it's "good enough" for now.
>
> On Sep 2, 2011, at 2:29 AM, Guillaume Bort wrote:
>
>
>
>
>
>
>
> > Easy way: use another folder than view. Otherwise you can create a
> > plugin then redefine loadTemplate to ignore Scalates one (return null
> > as this interface is defined in the Java part):
>
> > override def loadTemplate(file:VirtualFile )
>
> > On Fri, Sep 2, 2011 at 12:56 AM, Matt Raible <mrai...@gmail.com> wrote:
> >> Thanks for the advice. Now I have it working withScalateas a trait.
>
> >> The next issue I'm running into is running it in prod mode. Is there any way to stop Groovy from trying to compile my Jade templates?
>
> >> $ play run
> >> ~        _            _
> >> ~  _ __ | | __ _ _  _| |
> >> ~ | '_ \| |/ _' | || |_|
> >> ~ |  __/|_|\____|\__ (_)
> >> ~ |_|            |__/
> >> ~
> >> ~ play! 1.2.3,http://www.playframework.org
> >>> I don't know if it is possible withScalate? If yes, there should be a
> >>> configuration setting to set somewhere on the TemplateEngine.
>
> ...
>
> read more »

Matt Raible

unread,
Oct 16, 2011, 6:30:42 PM10/16/11
to play-fr...@googlegroups.com
I figured this out today. Here's my populateRenderArgs method:

def populateRenderArgs(args: (Symbol, Any)*) = {
val renderArgs = Scope.RenderArgs.current();

args.foreach {
o =>
renderArgs.put(o._1.name, o._2)
}

renderArgs.put("session", Scope.Session.current());
renderArgs.put("request", Http.Request.current());
renderArgs.put("flash", Scope.Flash.current());
renderArgs.put("params", Scope.Params.current());
renderArgs.put("errors", Validation.errors());
}

Then I call it from my Template class and convert the RenderArgs map to a Scalate friendly map.

case class Template(name: String) {

import scala.collection.JavaConversions._

def render(args: (Symbol, Any)*) = {

populateRenderArgs(args: _*)
val convertedArgs: Map[String, Any] = Scope.RenderArgs.current().data.toMap
val argsMap = convertedArgs.map {
case (k, v) => k -> v
}.toMap

scalateEngine.layout(name + scalateType, argsMap)
}
}

This allows me to do things like get parameters in a Jade template:

-@ val params: play.mvc.Scope.Params

{params.get('foo')}

If I pass in http://localhost:9000?foo=bar, it'll render "bar".

I'd love it if there was a shortcut where I could write {params.foo} like you can with JSTL.

Please let me know if you think there's anything I could improve.

Thanks,

Matt

Matt Raible

unread,
Oct 26, 2011, 9:35:04 AM10/26/11
to play-framework
I've changed this to a trait and all has been working fine and
dandy...

trait Scalate {

def render(args: (Symbol, Any)*) = {
val defaultTemplate = Http.Request.current().action.replace(".",
"/")
ScalateTemplate(defaultTemplate).render(args: _*);
}
}

... until I started trying to call a method from a method in my
Controller. For example:

def postComment(postId:Long) = {
val author = params.get("author")
val content = params.get("content")
Validation.required("author", author)
Validation.required("content", content)
if (Validation.hasErrors) {
show(postId)
} else {
Comment.create(Comment(postId, author, content))
Action(show(postId))
}
}

When I have validation errors, I end up with the following error:

Could not load resource: [Timeline/postComment.jade]

When what I really want is it to try and render Timeline/show.jade.

I tried changing Http.Request.current().action to
play.classloading.enhancers.ControllersEnhancer.currentAction.get().peek(),
but this results in controllers.Timeline.render instead of
controllers.Timeline.show.

What's the best way to get the local show() call to be handled
properly?

Thanks,

Matt
Reply all
Reply to author
Forward
0 new messages