Skip to content
Browse files

adds a haml compiler

  • Loading branch information...
1 parent fe8cf2e commit 510a2b6e5abbd384754b5e994dc79f6378cc3692 @casualjim committed
View
2 .../java/io/backchat/brewsbt/RhinoUtils.java → .../java/io/backchat/sbtbrew/RhinoUtils.java
@@ -1,4 +1,4 @@
-package io.backchat.brewsbt;
+package io.backchat.sbtbrew;
import org.mozilla.javascript.*;
View
1 src/main/scala/io/backchat/sbtbrew/BrewPlugin.scala
@@ -14,6 +14,7 @@ object BrewPlugin extends sbt.Plugin {
val brew = TaskKey[Seq[File]]("brew", "Compile and optimize script source files.")
val coffee = TaskKey[Seq[File]]("coffee", "Compile coffee sources.")
+ val haml = TaskKey[Seq[File]]("haml", "Compile haml sources.")
val coffeeJade = TaskKey[Seq[File]]("coffee-jade", "Compile the jade views with coffee jade")
val optimize = TaskKey[Seq[File]]("optimize", "Optimize the web resources.")
val optimizer = SettingKey[Optimizer]("optimizer", "The optimizer to use.")
View
9 src/main/scala/io/backchat/sbtbrew/CoffeeJadeScriptEngine.scala
@@ -18,10 +18,13 @@ class CoffeeJadeScriptEngine(options: String, bare: Boolean, log: Logger) extend
withContext { ctx =>
val compileScope = ctx.newObject(scope)
compileScope.setParentScope(scope)
- compileScope.put("jadeSource", compileScope, scriptToCompile)
+
catchRhinoExceptions {
- val script = "window.jade.compile(jadeSource, %s).code;" format options
- val coffee = ctx.evaluateString(compileScope, script, "JCoffeeJadeCompiler", 0, null).toString
+ val coffee = evalString(
+ "window.jade.compile(jadeSource, opts).code;",
+ "JCoffeeJadeCompiler",
+ "jadeSource" -> scriptToCompile,
+ "opts" -> options)
coffeeCompiler.compile(coffee)
}
}
View
77 src/main/scala/io/backchat/sbtbrew/HamlPlugin.scala
@@ -0,0 +1,77 @@
+package io.backchat.sbtbrew
+
+import sbt._
+import java.nio.charset.Charset
+import sbt.Keys._
+
+object HamlPlugin extends sbt.Plugin with ScriptEnginePlugin {
+
+ import BrewPlugin.BrewKeys._
+
+ private def compileSources(charset: Charset, log: Logger)(pair: (File, File)) = {
+ val compiler = new HamlScriptEngine(log)
+ try {
+ val (haml, js) = pair
+ log.debug("Compiling %s" format haml)
+ compiler.compile(IO.read(haml, charset)).fold(
+ err => sys.error(err),
+ compiled => {
+ IO.write(js, compiled)
+ log.debug("Wrote to file %s" format js)
+ js
+ })
+
+ } catch {
+ case e: Exception =>
+ throw new RuntimeException(
+ "error occured while compiling %s with %s: %s" format(
+ pair._1, compiler, e.getMessage), e
+ )
+ }
+ }
+
+
+ private def compileChangedHaml(context: ScriptEngineContext, log: Logger) =
+ compileChanged(context, log) {
+ case Nil =>
+ log.debug("No haml views to compile")
+ compiled(context.targetDir, context.targetExtension)
+ case xs =>
+ log.info("Compiling %d haml views to %s" format(xs.size, context.targetDir))
+ xs map compileSources(context.charset, log)
+ log.debug("Compiled %s hamlScripts" format xs.size)
+ compiled(context.targetDir, context.targetExtension)
+ }
+
+ private def hamlCompilerTask =
+ (streams, engineContext in haml) map {
+ (out, context) =>
+ compileChangedHaml(context, out.log)
+ }
+
+ def hamlSettingsIn(c: Configuration): Seq[Setting[_]] =
+ inConfig(c)(hamlSettings0 ++ Seq(
+ sourceDirectory in haml <<= (sourceDirectory in c)(_ / "views"),
+ resourceManaged in haml <<= (resourceManaged in c)(_ / "views"),
+ engineContext in haml <<= buildEngineContext(haml),
+ cleanFiles in haml <<= (resourceManaged in haml)(_ :: Nil),
+ watchSources in haml <<= (unmanagedSources in haml)
+ )) ++ Seq(
+ cleanFiles <+= (resourceManaged in haml in c),
+ watchSources <++= (unmanagedSources in haml in c),
+ resourceGenerators in c <+= haml in c,
+ compile in c <<= (compile in c).dependsOn(haml in c)
+ )
+
+ def hamlSettings: Seq[Setting[_]] =
+ hamlSettingsIn(Compile) ++ hamlSettingsIn(Test)
+
+ def hamlSettings0: Seq[Setting[_]] = Seq(
+ bare in haml := false,
+ iced in haml := false,
+ sourceExtensions in haml <<= (iced in haml)(ice => if (ice) Seq("haml", "iced") else Seq("haml"))) ++
+ taskSettings(haml) ++ Seq(
+ haml <<= hamlCompilerTask
+ )
+}
+
View
34 src/main/scala/io/backchat/sbtbrew/HamlScriptEngine.scala
@@ -0,0 +1,34 @@
+package io.backchat.sbtbrew
+
+import java.io.InputStreamReader
+import sbt._
+
+object HamlScriptEngine {
+ val HamlScriptName = "haml.js"
+ val HamlScriptResource = "/haml/"+HamlScriptName
+}
+class HamlScriptEngine(log: Logger) extends ScriptEngine {
+
+ import ScriptEngine._
+ import HamlScriptEngine._
+
+
+ def compile(scriptToCompile: String) = {
+ withContext { ctx =>
+ catchRhinoExceptions {
+ Right(addModuleDefinition(
+ evalString("Haml.optimize(Haml.compile(hamlSource));","HamlCompiler", "hamlSource" -> scriptToCompile)))
+ }
+ }
+ }
+
+ lazy val scope = withContext { ctx =>
+ val ns = createScope(ctx, true)
+ addJsonScript(ns)
+ ctx.evaluateReader(
+ ns,
+ new InputStreamReader(getClass.getResourceAsStream(HamlScriptResource), utf8),
+ HamlScriptName, 1, null)
+ ns
+ }
+}
View
2 src/main/scala/io/backchat/sbtbrew/RhinoRunner.scala
@@ -4,7 +4,7 @@
//import org.mozilla.javascript.tools.ToolErrorReporter
//import java.io._
//import java.nio.charset.Charset
-//import io.backchat.brewsbt.RhinoUtils
+//import io.backchat.sbtbrew.RhinoUtils
//import org.mozilla.javascript.{RhinoException, JavaScriptException, Context, ScriptableObject}
//
//
View
42 src/main/scala/io/backchat/sbtbrew/ScriptEngine.scala
@@ -4,7 +4,6 @@ import sbt._
import Keys._
import java.nio.charset.Charset
import org.mozilla.javascript._
-import io.backchat.brewsbt.RhinoUtils
import java.io.{IOException, InputStreamReader}
import tools.ToolErrorReporter
import util.control.Exception._
@@ -20,8 +19,7 @@ object ScriptEngine {
}
trait ScriptEngine {
- import util.control.Exception.catching
- import ScriptEngine._
+ import ScriptEngine._
def compile(scriptToCompile: String): Either[String, String]
@@ -34,14 +32,37 @@ trait ScriptEngine {
})(fn)
- protected def createScope(ctx: Context) = {
- val ns = ctx.initStandardObjects()
+ protected def createScope(ctx: Context, emulateShell: Boolean = false) = {
+ val ns = if (emulateShell) ShellEmulation.emulate(ctx.initStandardObjects()) else ctx.initStandardObjects()
ctx.evaluateReader(
ns,
new InputStreamReader(getClass.getResourceAsStream(CommonsScriptResource), utf8), CommonsScriptName, 1, null)
ns
}
+ protected def addJsonScript(localScope: ScriptableObject) =
+ loadScript(JsonScriptResource, JsonScriptName, localScope)
+
+ protected def addClientEnvironment(localScope: ScriptableObject) =
+ loadScript(ClientEnvScriptResource, ClientEnvScriptName, localScope)
+
+ protected def loadScript(path: String, name: String, localScope: ScriptableObject = scope) = withContext { ctx =>
+ ctx.evaluateReader(
+ localScope,
+ new InputStreamReader(getClass.getResourceAsStream(path), utf8), name, 1, null)
+ }
+
+ protected def evalString(script: String, params: (String, Any)*): String = evalString(script, "anonymous script", params:_*)
+
+ protected def evalString(script: String, sourceName: String, params: (String, Any)*): String = withContext { ctx =>
+ val localScope = ctx.newObject(scope)
+ localScope.setParentScope(scope)
+ params foreach {
+ case (k, v) => localScope.put(k, localScope, v)
+ }
+ ctx.evaluateString(localScope, script, sourceName, 0, null).asInstanceOf[String]
+ }
+
def scope: ScriptableObject
protected def withContext[T](f: Context => T): T =
@@ -57,6 +78,17 @@ trait ScriptEngine {
Context.exit()
}
+ protected def addModuleDefinition(script: String) =
+ "(function(define){\n"+
+ "define(function(){return function(vars){\n" +
+ "with(vars||{}) {\n" +
+ "return " + script + "; \n"+
+ "}};\n"+
+ "})" +
+ ";})(typeof define==\"function\"?\n"+
+ "define:\n"+
+ "function(factory){module.exports=factory.apply(this, deps.map(require));});\n"
+
}
View
22 src/sbt-test/brew/haml-single/build.sbt
@@ -0,0 +1,22 @@
+seq(hamlSettings:_*)
+
+sourceDirectory in (Compile, BrewKeys.haml) <<= (sourceDirectory in (Compile, BrewKeys.coffee))
+
+resourceManaged in (Compile, BrewKeys.haml) <<= (resourceManaged in (Compile, BrewKeys.coffee))
+
+InputKey[Unit]("contents") <<= inputTask { (argsTask: TaskKey[Seq[String]]) =>
+ (argsTask, streams) map {
+ (args, out) =>
+ args match {
+ case Seq(given, expected) =>
+ if(IO.read(file(given)).trim.equals(IO.read(file(expected)).trim)) out.log.debug(
+ "Contents match"
+ )
+ else error(
+ "Contents of (%s)\n'%s' does not match (%s)\n'%s'" format(
+ given, IO.read(file(given)), expected, IO.read(file(expected))
+ )
+ )
+ }
+ }
+}
View
8 src/sbt-test/brew/haml-single/fixtures/index.js
@@ -0,0 +1,8 @@
+(function(define){
+define(function(){return function(vars){
+with(vars||{}) {
+return "<div id=\"someotherid\"><div id=\"hello\">asd</div></div>";
+}};
+});})(typeof define=="function"?
+define:
+function(factory){module.exports=factory.apply(this, deps.map(require));});
View
1 src/sbt-test/brew/haml-single/project/plugins.sbt
@@ -0,0 +1 @@
+addSbtPlugin("io.backchat.sbtbrew" % "brew" % "latest.integration")
View
2 src/sbt-test/brew/haml-single/src/main/haml/index.haml
@@ -0,0 +1,2 @@
+#someotherid
+ #hello= "asd"
View
4 src/sbt-test/brew/haml-single/test
@@ -0,0 +1,4 @@
+# should generate javascript
+> haml
+$ exists target/scala-2.9.1/resource_managed/main/js/index.js
+> contents target/scala-2.9.1/resource_managed/main/js/index.js fixtures/index.js

0 comments on commit 510a2b6

Please sign in to comment.
Something went wrong with that request. Please try again.