Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Pulled some template samples out

  • Loading branch information...
commit b3ce8d71308a62965483c1beae383a33afbec822 1 parent a4d3994
@jroper jroper authored
Showing with 449 additions and 227 deletions.
  1. +31 −118 documentation/manual/scalaGuide/main/templates/ScalaTemplates.md
  2. +5 −0 documentation/manual/scalaGuide/main/templates/code/AbsoluteImportTester.scala
  3. +139 −0 documentation/manual/scalaGuide/main/templates/code/ScalaTemplates.scala
  4. +5 −0 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/curriedParameters.scala.html
  5. +5 −0 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/defaultParameters.scala.html
  6. +10 −0 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/firstLineComment.scala.html
  7. +15 −0 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/importStatement.scala.html
  8. +5 −0 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/simpleParameters.scala.html
  9. +71 −0 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/snippets.scala.html
  10. +11 −0 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/views/Application/index.scala.html
  11. +28 −3 documentation/project/Build.scala
  12. +1 −19 framework/src/sbt-plugin/src/main/scala/PlayAssetsCompiler.scala
  13. +0 −53 framework/src/sbt-plugin/src/main/scala/PlayCommands.scala
  14. +36 −0 framework/src/sbt-plugin/src/main/scala/PlayKeys.scala
  15. +6 −33 framework/src/sbt-plugin/src/main/scala/PlaySettings.scala
  16. +80 −0 framework/src/sbt-plugin/src/main/scala/PlaySourceGenerators.scala
  17. +1 −1  framework/src/sbt-plugin/src/main/scala/play/Project.scala
View
149 documentation/manual/scalaGuide/main/templates/ScalaTemplates.md
@@ -11,18 +11,9 @@ Play 2.0 comes with a new and really powerful Scala-based template engine, whose
 
-> **Note:** Even though the template engine uses Scala as expression language, this is not a problem for Java developers. You can almost use it as if the language were Java.
->
-> Remember that a template is not a place to write complex logic. You don’t have to write complicated Scala code here. Most of the time you will just access data from your model objects, as follows:
->
-> ```
-> myUser.getProfile().getUsername()
-> ```
-> Parameter types are specified using a suffix syntax. Generic types are specified using the `[]` symbols instead of the usual `<>` Java syntax. For example, you write `List[String]`, which is the same as `List<String>` in Java.
-
Templates are compiled, so you will see any errors in your browser:
-![tempaltesyntax](https://raw.github.com/wiki/playframework/Play20/javaGuide/main/templates/images/templatesError.png)
+[[images/templatesError.png]]
## Overview
@@ -30,91 +21,66 @@ A Play Scala template is a simple text file that contains small blocks of Scala
The template system has been designed to feel comfortable to those used to working with HTML, allowing front-end developers to easily work with the templates.
-Templates are compiled as standard Scala functions, following a simple naming convention. If you create a `views/Application/index.scala.html` template file, it will generate a `views.html.Application.index` class that has a `render()` method.
+Templates are compiled as standard Scala functions, following a simple naming convention. If you create a `views/Application/index.scala.html` template file, it will generate a `views.html.Application.index` class that has an `apply()` method.
For example, here is a simple template:
-```html
-@(customer: Customer, orders: List[Order])
-
-<h1>Welcome @customer.name!</h1>
-
-<ul>
-@for(order <- orders) {
- <li>@order.getTitle()</li>
-}
-</ul>
-```
+@[example-template](code/scalaguide/templates/views/Application/index.scala.html)
-You can then call this from any Java code as you would normally call a method on a class:
+You can then call this from any Scala code as you would normally call a method on a class:
-```java
-Content html = views.html.Application.index.render(customer, orders);
-```
+@[invoke-template](code/ScalaTemplates.scala)
## Syntax: the magic ‘@’ character
The Scala template uses `@` as the single special character. Every time this character is encountered, it indicates the beginning of a dynamic statement. You are not required to explicitly close the code block - the end of the dynamic statement will be inferred from your code:
```
-Hello @customer.getName()!
- ^^^^^^^^^^^^^^^^^^
- Dynamic code
+Hello @customer.name!
+ ^^^^^^^^^^^^^
+ Dynamic code
```
Because the template engine automatically detects the end of your code block by analysing your code, this syntax only supports simple statements. If you want to insert a multi-token statement, explicitly mark it using brackets:
```
-Hello @(customer.getFirstName() + customer.getLastName())!
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Dynamic Code
+Hello @(customer.firstName + customer.lastName)!
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ Dynamic Code
```
You can also use curly brackets, to write a multi-statement block:
```
-Hello @{val name = customer.getFirstName() + customer.getLastName(); name}!
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Dynamic Code
+Hello @{val name = customer.firstName + customer.lastName; name}!
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ Dynamic Code
```
Because `@` is a special character, you’ll sometimes need to escape it. Do this by using `@@`:
-```
-My email is bob@@example.com
-```
+@[escape-at](code/scalaguide/templates/snippets.scala.html)
## Template parameters
A template is like a function, so it needs parameters, which must be declared at the top of the template file:
-```scala
-@(customer: models.Customer, orders: List[models.Order])
-```
+@[simple-parameters](code/scalaguide/templates/simpleParameters.scala.html)
You can also use default values for parameters:
-```scala
-@(title: String = "Home")
-```
+@[default-parameters](code/scalaguide/templates/defaultParameters.scala.html)
Or even several parameter groups:
-```scala
-@(title:String)(body: Html)
-```
+@[curried-parameters](code/scalaguide/templates/curriedParameters.scala.html)
## Iterating
You can use the `for` keyword, in a pretty standard way:
-```html
-<ul>
-@for(p <- products) {
- <li>@p.getName() ($@p.getPrice())</li>
-}
-</ul>
-```
+@[for-loop](code/scalaguide/templates/snippets.scala.html)
+
> **Note:** Make sure that `{` is on the same line with `for` to indicate that the expression continues to next line.
@@ -123,79 +89,43 @@ You can use the `for` keyword, in a pretty standard way:
If-blocks are nothing special. Simply use Scala’s standard `if` statement:
-```html
-@if(items.isEmpty()) {
- <h1>Nothing to display</h1>
-} else {
- <h1>@items.size() items!</h1>
-}
-```
+@[conditional](code/scalaguide/templates/snippets.scala.html)
## Declaring reusable blocks
You can create reusable code blocks:
-```html
-@display(product: models.Product) = {
- @product.getName() ($@product.getPrice())
-}
-
-<ul>
-@for(product <- products) {
- @display(product)
-}
-</ul>
-```
+@[reusable](code/scalaguide/templates/snippets.scala.html)
Note that you can also declare reusable pure code blocks:
-```html
-@title(text: String) = @{
- text.split(' ').map(_.capitalize).mkString(" ")
-}
-
-<h1>@title("hello world")</h1>
-```
+@[pure-reusable](code/scalaguide/templates/snippets.scala.html)
> **Note:** Declaring code block this way in a template can be sometime useful but keep in mind that a template is not the best place to write complex logic. It is often better to externalize these kind of code in a Java class (that you can store under the `views/` package as well if your want).
By convention a reusable block defined with a name starting with **implicit** will be marked as `implicit`:
-```
-@implicitFieldConstructor = @{ MyFieldConstructor() }
-```
+@[implicits](code/scalaguide/templates/snippets.scala.html)
## Declaring reusable values
You can define scoped values using the `defining` helper:
-```html
-@defining(user.getFirstName() + " " + user.getLastName()) { fullName =>
- <div>Hello @fullName</div>
-}
-```
+@[defining](code/scalaguide/templates/snippets.scala.html)
## Import statements
You can import whatever you want at the beginning of your template (or sub-template):
-```scala
-@(customer: models.Customer, orders: List[models.Order])
-
-@import utils._
-
-...
-```
+@[import](code/scalaguide/templates/importStatement.scala.html)
To make an absolute resolution, use **_root_** prefix in the import statement.
-```scala
-@import _root_.company.product.core._
-```
+@[absolute](code/scalaguide/templates/importStatement.scala.html)
If you have common imports, which you need in all templates, you can declare in `project/Build.scala`
-```
+```scala
val main = play.Project(…).settings(
templatesImport += "com.abc.backend._"
)
@@ -205,24 +135,11 @@ val main = play.Project(…).settings(
You can write server side block comments in templates using `@* *@`:
-```
-@*********************
- * This is a comment *
- *********************@
-```
+@[comment](code/scalaguide/templates/snippets.scala.html)
You can put a comment on the first line to document your template into the Scala API doc:
-```
-@*************************************
- * Home page. *
- * *
- * @param msg The message to display *
- *************************************@
-@(msg: String)
-
-<h1>@msg</h1>
-```
+@[comment](code/scalaguide/templates/firstLineComment.scala.html)
## Escaping
@@ -230,10 +147,6 @@ By default, dynamic content parts are escaped according to the template type’s
For example to output raw HTML:
-```html
-<p>
- @Html(article.content)
-</p>
-```
+@[raw-html](code/scalaguide/templates/snippets.scala.html)
> **Next:** [[Common use cases | ScalaTemplateUseCases]]
View
5 documentation/manual/scalaGuide/main/templates/code/AbsoluteImportTester.scala
@@ -0,0 +1,5 @@
+package company.product.core
+
+object AbsoluteImportTester {
+ def test = "absolute import is working"
+}
View
139 documentation/manual/scalaGuide/main/templates/code/ScalaTemplates.scala
@@ -0,0 +1,139 @@
+package scalaguide.templates
+
+import org.specs2.mutable.Specification
+import play.api.templates.Html
+
+// These have to be in the same package as the template
+package views.html.Application {
+ case class Order(title: String)
+ case class Customer(name: String)
+}
+
+package html.models {
+ case class Order(title: String)
+ case class Customer(name: String)
+ case class Product(name: String, price: String)
+ case class User(firstName: String, lastName: String)
+ case class Article(content: String)
+
+ case class MyFieldConstructor() {
+ val working = "implicit working"
+ }
+
+ object ImplicitTester {
+ def test(implicit f: MyFieldConstructor) = f.working
+ }
+}
+
+package html.utils {
+ object ImportTester {
+ def test = "import working"
+ }
+}
+
+object ScalaTemplatesSpec extends Specification {
+
+ import html.models._
+
+ val customer = Customer("mr customer")
+ val orders = List(Order("foo"), Order("bar"))
+
+
+ "Scala templates" should {
+ "support an example template" in {
+ import views.html.Application._
+
+ val c = Customer("mr customer")
+ val o = List(Order("foo"), Order("bar"))
+
+ //#invoke-template
+ val content = views.html.Application.index(c, o)
+ //#invoke-template
+
+ val body = content.body
+ body must contain("mr customer")
+ body must contain("foo")
+ body must contain("bar")
+ }
+
+ "allow simple parameters" in {
+ val body = html.simpleParameters(customer, orders).body
+ body must contain(customer.toString)
+ body must contain(orders(0).toString)
+ body must contain(orders(1).toString)
+ }
+
+ "allow default parameters" in {
+ html.defaultParameters("foo").body must contain("foo")
+ html.defaultParameters().body must contain("Home")
+ }
+
+ "allow curried parameters" in {
+ val body = html.curriedParameters("foo")(Html("bar")).body
+ body must contain("foo")
+ body must contain("bar")
+ }
+
+ "allow import statements" in {
+ html.importStatement(customer, orders).body must contain("import working")
+ }
+
+ "allow absolute import statements" in {
+ html.importStatement(customer, orders).body must contain("absolute import is working")
+ }
+
+ "allow comments on the first line" in {
+ val body = html.firstLineComment("blah").body
+ body must contain("blah")
+ body must not contain("Home page")
+ }
+
+ {
+ val body = html.snippets(Seq(Product("p1", "1"), Product("p2", "2")), User("John", "Doe"), Article("<foo>")).body
+ def segment(name: String) = {
+ body.lines.dropWhile(_ != "<span class=\"" + name + "\">").drop(1).takeWhile(_ != "</span>").mkString("\n")
+ }
+
+ "allow escaping the @ character" in {
+ body must contain("bob@example.com")
+ }
+
+ "allow iterating" in {
+ segment("for-loop") must contain("p1 ($1)")
+ segment("for-loop") must contain("p2 ($2)")
+ }
+
+ "allow conditionals" in {
+ body must contain("2 items!")
+ }
+
+ "allow reusable code blocks" in {
+ segment("reusable") must contain("p1 ($1)")
+ segment("reusable") must contain("p2 ($2)")
+ }
+
+ "allow pure scala reusable code blocks" in {
+ body must contain("Hello World")
+ }
+
+ "allow declaring implicit variables" in {
+ body must contain("implicit working")
+ }
+
+ "allow defining variables" in {
+ body must contain("Hello John Doe")
+ }
+
+ "allow comments" in {
+ body must not contain("This is a comment")
+ }
+
+ "allow intering raw HTML" in {
+ body must contain("<foo>")
+ }
+ }
+
+ {
+ }
+ }
+}
View
5 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/curriedParameters.scala.html
@@ -0,0 +1,5 @@
+@* #curried-parameters *@
+@(title: String)(body: Html)
+@* #curried-parameters *@
+
+@title @body
View
5 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/defaultParameters.scala.html
@@ -0,0 +1,5 @@
+@* #default-parameters *@
+@(title: String = "Home")
+@* #default-parameters *@
+
+@title
View
10 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/firstLineComment.scala.html
@@ -0,0 +1,10 @@
+@* #comment
+@*************************************
+ * Home page. *
+ * *
+ * @param msg The message to display *
+ *************************************@
+@(msg: String)
+
+<h1>@msg</h1>
+@* #comment *@
View
15 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/importStatement.scala.html
@@ -0,0 +1,15 @@
+@* #import *@
+@(customer: Customer, orders: List[Order])
+
+@import utils._
+
+...
+@* #import *@
+
+@ImportTester.test
+
+@* #absolute *@
+@import _root_.company.product.core._
+@* #absolute *@
+
+@AbsoluteImportTester.test
View
5 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/simpleParameters.scala.html
@@ -0,0 +1,5 @@
+@* #simple-parameters *@
+@(customer: Customer, orders: List[Order])
+@* #simple-parameters *@
+
+@customer @orders
View
71 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/snippets.scala.html
@@ -0,0 +1,71 @@
+@(products: Seq[Product], user: User, article: Article)
+
+
+@* #escape-at *@
+My email is bob@@example.com
+@* #escape-at *@
+
+<span class="for-loop">
+@* #for-loop *@
+<ul>
+@for(p <- products) {
+ <li>@p.name ($@p.price)</li>
+}
+</ul>
+@* #for-loop *@
+</span>
+
+@defining(List("a", "b")) { items =>
+ @* #conditional *@
+ @if(items.isEmpty) {
+ <h1>Nothing to display</h1>
+ } else {
+ <h1>@items.size items!</h1>
+ }
+ @* #conditional *@
+}
+
+<span class="reusable">
+@* #reusable *@
+@display(product: Product) = {
+ @product.name ($@product.price)
+}
+
+<ul>
+@for(product <- products) {
+ @display(product)
+}
+</ul>
+@* #reusable *@
+</span>
+
+@* #pure-reusable *@
+@title(text: String) = @{
+ text.split(' ').map(_.capitalize).mkString(" ")
+}
+
+<h1>@title("hello world")</h1>
+@* #pure-reusable *@
+
+@* #implicits *@
+@implicitFieldConstructor = @{ MyFieldConstructor() }
+@* #implicits *@
+@ImplicitTester.test
+
+@* #defining *@
+@defining(user.firstName + " " + user.lastName) { fullName =>
+ <div>Hello @fullName</div>
+}
+@* #defining *@
+
+@* #comment *@
+@*********************
+* This is a comment *
+*********************@
+@* #comment *@
+
+@* #raw-html *@
+<p>
+ @Html(article.content)
+</p>
+@* #raw-html *@
View
11 documentation/manual/scalaGuide/main/templates/code/scalaguide/templates/views/Application/index.scala.html
@@ -0,0 +1,11 @@
+@* #example-template *@
+@(customer: Customer, orders: List[Order])
+
+<h1>Welcome @customer.name!</h1>
+
+<ul>
+@for(order <- orders) {
+ <li>@order.title</li>
+}
+</ul>
+@* #example-template *@
View
31 documentation/project/Build.scala
@@ -1,6 +1,8 @@
import sbt._
import Keys._
+import PlayKeys._
import play.core.PlayVersion
+import PlaySourceGenerators._
object ApplicationBuild extends Build {
@@ -8,10 +10,33 @@ object ApplicationBuild extends Build {
version := PlayVersion.current,
scalaVersion := PlayVersion.scalaVersion,
libraryDependencies ++= Seq(
- "play" %% "play" % PlayVersion.current % "test",
- "play" %% "play-test" % PlayVersion.current % "test"
+ component("play") % "test",
+ component("play-test") % "test"
),
- unmanagedSourceDirectories in Test ++= (file("manual") ** "code").get
+
+ javaManualSourceDirectories := (file("manual") / "javaGuide" ** "code").get,
+ scalaManualSourceDirectories := (file("manual") / "scalaGuide" ** "code").get,
+
+ unmanagedSourceDirectories in Test <++= javaManualSourceDirectories,
+ unmanagedSourceDirectories in Test <++= scalaManualSourceDirectories,
+
+ // Need to ensure that templates in the Java docs get Java imports, and in the Scala docs get Scala imports
+ sourceGenerators in Test <+= (state, javaManualSourceDirectories, sourceManaged in Test, templatesTypes) map { (s, ds, g, t) =>
+ ds.flatMap(d => ScalaTemplates(s, d, g, t, defaultTemplatesImport ++ defaultJavaTemplatesImport))
+ },
+ sourceGenerators in Test <+= (state, scalaManualSourceDirectories, sourceManaged in Test, templatesTypes) map { (s, ds, g, t) =>
+ ds.flatMap(d => ScalaTemplates(s, d, g, t, defaultTemplatesImport ++ defaultScalaTemplatesImport))
+ },
+
+ templatesTypes := {
+ case "html" => ("play.api.templates.Html", "play.api.templates.HtmlFormat")
+ case "txt" => ("play.api.templates.Txt", "play.api.templates.TxtFormat")
+ case "xml" => ("play.api.templates.Xml", "play.api.templates.XmlFormat")
+ }
+
)
+ lazy val javaManualSourceDirectories = SettingKey[Seq[File]]("java-manual-source-directories")
+ lazy val scalaManualSourceDirectories = SettingKey[Seq[File]]("scala-manual-source-directories")
+
}
View
20 framework/src/sbt-plugin/src/main/scala/PlayAssetsCompiler.scala
@@ -51,7 +51,7 @@ trait PlayAssetsCompiler {
val (debug, min, dependencies) = try {
compile(sourceFile, options ++ requireSupport)
} catch {
- case e: AssetCompilationException => throw reportCompilationError(state, e)
+ case e: AssetCompilationException => throw PlaySourceGenerators.reportCompilationError(state, e)
}
val out = new File(resources, "public/" + naming(name, false))
IO.write(out, debug)
@@ -112,23 +112,5 @@ trait PlayAssetsCompiler {
coffeescriptOptions
)
- def reportCompilationError(state: State, error: PlayException.ExceptionSource) = {
- val log = state.log
- // log the source file and line number with the error message
- log.error(Option(error.sourceName).getOrElse("") + Option(error.line).map(":" + _).getOrElse("") + ": " + error.getMessage)
- Option(error.interestingLines(0)).map(_.focus).flatMap(_.headOption) map { line =>
- // log the line
- log.error(line)
- Option(error.position).map { pos =>
- // print a carat under the offending character
- val spaces = (line: Seq[Char]).take(pos).map {
- case '\t' => '\t'
- case x => ' '
- }
- log.error(spaces.mkString + "^")
- }
- }
- error
- }
}
View
53 framework/src/sbt-plugin/src/main/scala/PlayCommands.scala
@@ -272,59 +272,6 @@ exec java $* -cp $classpath """ + customFileName.map(fn => "-Dconfig.file=`dirna
analysis
}
- // ----- Source generators
-
- val RouteFiles = (state: State, confDirectory: File, generatedDir: File, additionalImports: Seq[String]) => {
- import play.router.RoutesCompiler._
-
- val javaRoutes = (generatedDir ** "routes.java")
- val scalaRoutes = (generatedDir ** "routes_*.scala")
- (javaRoutes.get ++ scalaRoutes.get).map(GeneratedSource(_)).foreach(_.sync())
- try {
- { (confDirectory * "*.routes").get ++ (confDirectory * "routes").get }.map { routesFile =>
- compile(routesFile, generatedDir, additionalImports)
- }
- } catch {
- case RoutesCompilationError(source, message, line, column) => {
- throw reportCompilationError(state, RoutesCompilationException(source, message, line, column.map(_ - 1)))
- }
- case e => throw e
- }
-
- (scalaRoutes.get ++ javaRoutes.get).map(_.getAbsoluteFile)
-
- }
-
- val ScalaTemplates = (state: State, sourceDirectory: File, generatedDir: File, templateTypes: Map[String, String], additionalImports: Seq[String]) => {
- import play.templates._
-
- val templateExt: PartialFunction[File, (File, String, String)] = {
- case p if templateTypes.contains(p.name.split('.').last) =>
- val extension = p.name.split('.').last
- val exts = templateTypes(extension)
- (p, extension, exts)
- }
- (generatedDir ** "*.template.scala").get.map(GeneratedSource(_)).foreach(_.sync())
- try {
-
- (sourceDirectory ** "*.scala.*").get.collect(templateExt).foreach {
- case (template, extension, format) =>
- ScalaTemplateCompiler.compile(
- template,
- sourceDirectory,
- generatedDir,
- format,
- additionalImports.map("import " + _.replace("%format%", extension)).mkString("\n"))
- }
- } catch {
- case TemplateCompilationError(source, message, line, column) => {
- throw reportCompilationError(state, TemplateCompilationException(source, message, line, column - 1))
- }
- }
-
- (generatedDir ** "*.template.scala").get.map(_.getAbsoluteFile)
- }
-
// ----- Play prompt
val playPrompt = { state: State =>
View
36 framework/src/sbt-plugin/src/main/scala/PlayKeys.scala
@@ -69,6 +69,42 @@ trait PlayKeys {
val devSettings = SettingKey[Seq[(String,String)]]("play-dev-settings")
val scalaIdePlay2Prefs = TaskKey[Unit]("scala-ide-play2-prefs")
+
+ // Constants that may be useful elsewhere
+ val defaultJavaTemplatesImport = Seq(
+ "models._",
+ "controllers._",
+
+ "java.lang._",
+ "java.util._",
+
+ "scala.collection.JavaConversions._",
+ "scala.collection.JavaConverters._",
+
+ "play.api.i18n._",
+ "play.core.j.PlayMagicForJava._",
+
+ "play.mvc._",
+ "play.data._",
+ "play.api.data.Field",
+
+ "play.mvc.Http.Context.Implicit._",
+
+ "views.%format%._")
+
+ val defaultScalaTemplatesImport = Seq(
+ "models._",
+ "controllers._",
+
+ "play.api.i18n._",
+
+ "play.api.mvc._",
+ "play.api.data._",
+
+ "views.%format%._")
+
+ val defaultTemplatesImport = Seq("play.api.templates._", "play.api.templates.PlayMagic._")
+
}
object PlayKeys extends PlayKeys
View
39 framework/src/sbt-plugin/src/main/scala/PlaySettings.scala
@@ -5,7 +5,7 @@ import PlayKeys._
import PlayEclipse._
trait PlaySettings {
- this: PlayCommands with PlayPositionMapper with PlayRun =>
+ this: PlayCommands with PlayPositionMapper with PlayRun with PlaySourceGenerators =>
protected def whichLang(name: String): Seq[Setting[_]] = {
if (name == JAVA) {
@@ -16,28 +16,10 @@ trait PlaySettings {
Seq.empty
}
}
- lazy val defaultJavaSettings = Seq[Setting[_]](
-
- templatesImport ++= Seq(
- "models._",
- "controllers._",
-
- "java.lang._",
- "java.util._",
-
- "scala.collection.JavaConversions._",
- "scala.collection.JavaConverters._",
-
- "play.api.i18n._",
- "play.core.j.PlayMagicForJava._",
-
- "play.mvc._",
- "play.data._",
- "play.api.data.Field",
- "play.mvc.Http.Context.Implicit._",
+ lazy val defaultJavaSettings = Seq[Setting[_]](
- "views.%format%._"),
+ templatesImport ++= defaultJavaTemplatesImport,
routesImport ++= Seq(
"play.libs.F"
@@ -48,17 +30,8 @@ trait PlaySettings {
)
lazy val defaultScalaSettings = Seq[Setting[_]](
-
- templatesImport ++= Seq(
- "models._",
- "controllers._",
-
- "play.api.i18n._",
-
- "play.api.mvc._",
- "play.api.data._",
-
- "views.%format%._"))
+ templatesImport ++= defaultScalaTemplatesImport
+ )
def closureCompilerSettings(optionCompilerOptions: com.google.javascript.jscomp.CompilerOptions) = Seq[Setting[_]](
resourceGenerators in Compile <<= JavascriptCompiler(Some(optionCompilerOptions))(Seq(_)),
@@ -216,7 +189,7 @@ trait PlaySettings {
// Templates
- templatesImport := Seq("play.api.templates._", "play.api.templates.PlayMagic._"),
+ templatesImport := defaultTemplatesImport,
scalaIdePlay2Prefs <<= (state, thisProjectRef, baseDirectory) map { (s, r, baseDir) => saveScalaIdePlay2Prefs(r, Project structure s, baseDir) },
View
80 framework/src/sbt-plugin/src/main/scala/PlaySourceGenerators.scala
@@ -0,0 +1,80 @@
+package sbt
+
+import sbt.PlayExceptions.{TemplateCompilationException, RoutesCompilationException}
+import play.api.PlayException
+
+trait PlaySourceGenerators {
+
+ val RouteFiles = (state: State, confDirectory: File, generatedDir: File, additionalImports: Seq[String]) => {
+ import play.router.RoutesCompiler._
+
+ val javaRoutes = (generatedDir ** "routes.java")
+ val scalaRoutes = (generatedDir ** "routes_*.scala")
+ (javaRoutes.get ++ scalaRoutes.get).map(GeneratedSource(_)).foreach(_.sync())
+ try {
+ { (confDirectory * "*.routes").get ++ (confDirectory * "routes").get }.map { routesFile =>
+ compile(routesFile, generatedDir, additionalImports)
+ }
+ } catch {
+ case RoutesCompilationError(source, message, line, column) => {
+ throw reportCompilationError(state, RoutesCompilationException(source, message, line, column.map(_ - 1)))
+ }
+ case e => throw e
+ }
+
+ (scalaRoutes.get ++ javaRoutes.get).map(_.getAbsoluteFile)
+
+ }
+
+ val ScalaTemplates = (state: State, sourceDirectory: File, generatedDir: File, templateTypes: PartialFunction[String, (String, String)], additionalImports: Seq[String]) => {
+ import play.templates._
+
+ val templateExt: PartialFunction[File, (File, String, String, String)] = {
+ case p if templateTypes.isDefinedAt(p.name.split('.').last) =>
+ val extension = p.name.split('.').last
+ val exts = templateTypes(extension)
+ (p, extension, exts._1, exts._2)
+ }
+ (generatedDir ** "*.template.scala").get.map(GeneratedSource(_)).foreach(_.sync())
+ try {
+
+ (sourceDirectory ** "*.scala.*").get.collect(templateExt).foreach {
+ case (template, extension, t, format) =>
+ ScalaTemplateCompiler.compile(
+ template,
+ sourceDirectory,
+ generatedDir,
+ t,
+ format,
+ additionalImports.map("import " + _.replace("%format%", extension)).mkString("\n"))
+ }
+ } catch {
+ case TemplateCompilationError(source, message, line, column) => {
+ throw reportCompilationError(state, TemplateCompilationException(source, message, line, column - 1))
+ }
+ }
+
+ (generatedDir ** "*.template.scala").get.map(_.getAbsoluteFile)
+ }
+
+ def reportCompilationError(state: State, error: PlayException.ExceptionSource) = {
+ val log = state.log
+ // log the source file and line number with the error message
+ log.error(Option(error.sourceName).getOrElse("") + Option(error.line).map(":" + _).getOrElse("") + ": " + error.getMessage)
+ Option(error.interestingLines(0)).map(_.focus).flatMap(_.headOption) map { line =>
+ // log the line
+ log.error(line)
+ Option(error.position).map { pos =>
+ // print a carat under the offending character
+ val spaces = (line: Seq[Char]).take(pos).map {
+ case '\t' => '\t'
+ case x => ' '
+ }
+ log.error(spaces.mkString + "^")
+ }
+ }
+ error
+ }
+}
+
+object PlaySourceGenerators extends PlaySourceGenerators
View
2  framework/src/sbt-plugin/src/main/scala/play/Project.scala
@@ -5,7 +5,7 @@ import play.console.Colors
import sbt.Keys._
object Project extends Plugin with PlayExceptions with PlayKeys with PlayReloader with PlayCommands
- with PlayRun with PlaySettings with PlayPositionMapper {
+ with PlayRun with PlaySettings with PlayPositionMapper with PlaySourceGenerators {
// ~~ Alerts
if(Option(System.getProperty("play.debug.classpath")).filter(_ == "true").isDefined) {
Please sign in to comment.
Something went wrong with that request. Please try again.