ちょっとしたことがしたくてScalateを別のものと組み合わせて使おうとしてみたのですが、どハマりしたので切り分けを兼ねて単品で使ってみることに。
ScalateでScala 2.11に対応したものを使いたければ、Scalate 1.7を使う、でいいんですよね、きっと…。
というわけで作ったbuild.sbt。
name := "scalate-example-1.7" version := "0.0.1-SNAPSHOT" scalaVersion := "2.11.2" organization := "org.litlewings" scalacOptions ++= Seq("-Xlint", "-deprecation", "-unchecked", "-feature") incOptions := incOptions.value.withNameHashing(true) libraryDependencies ++= Seq( "org.scalatra.scalate" %% "scalate-core" % "1.7.0" )
groupId(organization)変わった?
で、試しに作ったコード。
src/main/scala/org/littlewings/scalate/ScalateExample.scala
package org.littlewings.scalate import java.io.File import org.fusesource.scalate.TemplateEngine object ScalateExample { def main(args: Array[String]): Unit = { val engine = new TemplateEngine engine.workingDirectory = new File("./tmp") val bindings = Map("name" -> "Scalate", "languages" -> List("Java", "Scala", "Groovy", "Clojure")) val output = engine.layout("src/main/resources/template/hello.mustache", bindings) println(output) } }
テンプレートのコンパイル時の出力先は、「tmp」としました。
engine.workingDirectory = new File("./tmp")
テンプレート。Mustacheにしました。
src/main/resources/template/hello.mustache
Hello {{name}} by Mustache Template Programming Languages: {{#languages}} {{.}} {{/languages}}
実行。
> run [info] Compiling 1 Scala source to /xxxxx/scalate-example-1.7/target/scala-2.11/classes... [info] Running org.littlewings.scalate.ScalateExample SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Hello Scalate by Mustache Template Programming Languages: Java Scala Groovy Clojure [success] Total time: 2 s, completed 2014/08/23 11:27:20
…普通に動いた。やっぱ、合ってるんだ。
クラスパスからロードしてみたい
ちょっとやりたいことのひとつとして。テンプレートを、クラスパスからロードしてみようと。
テンプレートをロードするのはResourceLoaderというものにやらせるのですが、普通にやるとFileResourceLoader(とServletResourceLoader)しかないですよね…?
というわけで、まずは先ほど書いたimport文を修正。
import java.io.{File, InputStreamReader} import java.nio.charset.StandardCharsets import org.fusesource.scalate.TemplateEngine import org.fusesource.scalate.util.{Resource, ResourceLoader, StringResource}
クラス作成。
class ClassPathResourceLoader extends ResourceLoader { override def resource(uri: String): Option[Resource] = { val cl = Thread.currentThread.getContextClassLoader val is = cl.getResourceAsStream(uri) if (is != null) { val reader = new InputStreamReader(is, StandardCharsets.UTF_8) try { val text = Iterator .continually(reader.read()) .takeWhile(_ != -1) .map(_.asInstanceOf[Char]) .mkString Some(StringResource(uri, text)) } finally { is.close() } } else { None } } }
テンプレート利用箇所変更。
val engine = new TemplateEngine engine.workingDirectory = new File("./tmp") engine.resourceLoader = new ClassPathResourceLoader val bindings = Map("name" -> "Scalate", "languages" -> List("Java", "Scala", "Groovy", "Clojure")) val output = engine.layout("template/hello.mustache", bindings) println(output)
実行。
> run [info] Running org.littlewings.scalate.ScalateExample SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Hello Scalate by Mustache Template Programming Languages: Java Scala Groovy Clojure [success] Total time: 2 s, completed 2014/08/23 11:33:21
…普通に動いた。まあ、1回のテンプレート評価でResourceLoader#resourceが何度か呼び出されているようですが、いいでしょう。
というわけで、普通に使えてしまったので、いったんここまで…。
参考)
Scalate Embedding Guide
http://scalate.fusesource.org/documentation/scalate-embedding-guide.html
scalate-project(ここから1.6-SNAPSHOTのScaladoc)
http://scalate.fusesource.org/maven/1.6.0-SNAPSHOT/
作成したコード全体は、こちら。
src/main/scala/org/littlewings/scalate/ScalateExample.scala
package org.littlewings.scalate import java.io.{File, InputStreamReader} import java.nio.charset.StandardCharsets import org.fusesource.scalate.TemplateEngine import org.fusesource.scalate.util.{Resource, ResourceLoader, StringResource} object ScalateExample { def main(args: Array[String]): Unit = { val engine = new TemplateEngine engine.workingDirectory = new File("./tmp") engine.resourceLoader = new ClassPathResourceLoader val bindings = Map("name" -> "Scalate", "languages" -> List("Java", "Scala", "Groovy", "Clojure")) val output = engine.layout("template/hello.mustache", bindings) println(output) } } class ClassPathResourceLoader extends ResourceLoader { override def resource(uri: String): Option[Resource] = { val cl = Thread.currentThread.getContextClassLoader val is = cl.getResourceAsStream(uri) if (is != null) { val reader = new InputStreamReader(is, StandardCharsets.UTF_8) try { val text = Iterator .continually(reader.read()) .takeWhile(_ != -1) .map(_.asInstanceOf[Char]) .mkString Some(StringResource(uri, text)) } finally { is.close() } } else { None } } }