Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial research spike for JRuby/Lift integration

  • Loading branch information...
commit 07a39d24e6b6444c5e76d84302fb3739ba30e856 0 parents
David Pollak authored January 27, 2011

Showing 29 changed files with 813 additions and 0 deletions. Show diff stats Hide diff stats

  1. 56  .gitignore
  2. 9  project/build.properties
  3. 25  project/build/LiftProject.scala
  4. 1  sbt
  5. BIN  sbt-launcher.jar
  6. 2  sbt.bat
  7. 0  src/main/resources/.keep
  8. 8  src/main/resources/Zoro.rb
  9. 0  src/main/resources/props/default.props
  10. 82  src/main/scala/bootstrap/liftweb/Boot.scala
  11. 0  src/main/scala/code/comet/.keep
  12. 57  src/main/scala/code/lib/DependencyFactory.scala
  13. 78  src/main/scala/code/lib/JRuby.scala
  14. 38  src/main/scala/code/model/User.scala
  15. 10  src/main/scala/code/snippet/Frog.scala
  16. 25  src/main/scala/code/snippet/HelloWorld.scala
  17. 0  src/main/scala/code/view/.keep
  18. 21  src/main/webapp/WEB-INF/web.xml
  19. BIN  src/main/webapp/images/ajax-loader.gif
  20. 20  src/main/webapp/index.html
  21. 5  src/main/webapp/static/index.html
  22. 85  src/main/webapp/templates-hidden/default.html
  23. 57  src/main/webapp/templates-hidden/wizard-all.html
  24. 0  src/test/resources/.keep
  25. 15  src/test/scala/LiftConsole.scala
  26. 33  src/test/scala/RunWebApp.scala
  27. 76  src/test/scala/code/AppTest.scala
  28. 64  src/test/scala/code/XmlSourceSpecs.scala
  29. 46  src/test/scala/code/snippet/HelloWorldTest.scala
56  .gitignore
... ...
@@ -0,0 +1,56 @@
  1
+# use glob syntax.
  2
+syntax: glob
  3
+*.ser
  4
+*.class
  5
+*~
  6
+*.bak
  7
+*.off
  8
+*.old
  9
+.DS_Store
  10
+
  11
+# logs
  12
+derby.log
  13
+
  14
+# eclipse conf file
  15
+.settings
  16
+.classpath
  17
+.project
  18
+.manager
  19
+.externalToolBuilders
  20
+
  21
+# ensime/emacs conf files
  22
+.ensime
  23
+.scala_dependencies
  24
+
  25
+# building
  26
+target
  27
+null
  28
+tmp*
  29
+dist
  30
+test-output
  31
+
  32
+# sbt
  33
+target
  34
+lib_managed
  35
+src_managed
  36
+project/boot
  37
+
  38
+# other scm
  39
+.svn
  40
+.CVS
  41
+.hg*
  42
+
  43
+# switch to regexp syntax.
  44
+#  syntax: regexp
  45
+#  ^\.pc/
  46
+
  47
+# IntelliJ
  48
+*.iml
  49
+*.ipr
  50
+*.iws
  51
+.idea
  52
+
  53
+# Pax Runner (for easy OSGi launching)
  54
+runner
  55
+
  56
+*.db
9  project/build.properties
... ...
@@ -0,0 +1,9 @@
  1
+#Project properties
  2
+#Fri Apr 23 11:24:20 PDT 2010
  3
+project.organization=Lift
  4
+project.name=Lift SBT Template
  5
+sbt.version=0.7.4
  6
+project.version=0.1
  7
+def.scala.version=2.7.7
  8
+build.scala.versions=2.8.1
  9
+project.initialize=false
25  project/build/LiftProject.scala
... ...
@@ -0,0 +1,25 @@
  1
+import sbt._
  2
+
  3
+class LiftProject(info: ProjectInfo) extends DefaultWebProject(info) {
  4
+  val liftVersion = "2.3-SNAPSHOT"
  5
+
  6
+  // uncomment the following if you want to use the snapshot repo
  7
+  // val scalatoolsSnapshot = ScalaToolsSnapshots
  8
+
  9
+  val m2 = "m2" at "file:///home/dpp/.m2/repository"
  10
+
  11
+  // If you're using JRebel for Lift development, uncomment
  12
+  // this line
  13
+  override def scanDirectories = Nil
  14
+
  15
+  override def libraryDependencies = Set(
  16
+    "net.liftweb" %% "lift-webkit" % liftVersion % "compile->default",
  17
+    "net.liftweb" %% "lift-mapper" % liftVersion % "compile->default",
  18
+    "org.jruby" % "jruby-complete" % "1.6.0.RC1",
  19
+    "org.mortbay.jetty" % "jetty" % "6.1.22" % "test->default",
  20
+    "junit" % "junit" % "4.5" % "test->default",
  21
+    "ch.qos.logback" % "logback-classic" % "0.9.26",
  22
+    "org.scala-tools.testing" %% "specs" % "1.6.6" % "test->default",
  23
+    "com.h2database" % "h2" % "1.2.138"
  24
+  ) ++ super.libraryDependencies
  25
+}
1  sbt
... ...
@@ -0,0 +1 @@
  1
+java -Xmx512M -Xss2M -XX:+CMSClassUnloadingEnabled -jar `dirname $0`/sbt-launcher.jar "$@"
BIN  sbt-launcher.jar
Binary file not shown
2  sbt.bat
... ...
@@ -0,0 +1,2 @@
  1
+set SCRIPT_DIR=%~dp0
  2
+java -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -jar "%SCRIPT_DIR%\sbt-launcher.jar" %*
0  src/main/resources/.keep
No changes.
8  src/main/resources/Zoro.rb
... ...
@@ -0,0 +1,8 @@
  1
+class Zoro
  2
+  def yo
  3
+    {
  4
+      "span *" => Time.now.to_s,
  5
+      "#foo" => "holy cow, that works"
  6
+    }
  7
+  end
  8
+end
0  src/main/resources/props/default.props
No changes.
82  src/main/scala/bootstrap/liftweb/Boot.scala
... ...
@@ -0,0 +1,82 @@
  1
+package bootstrap.liftweb
  2
+
  3
+import net.liftweb._
  4
+import util._
  5
+import Helpers._
  6
+
  7
+import common._
  8
+import http._
  9
+import sitemap._
  10
+import Loc._
  11
+import mapper._
  12
+
  13
+import code.model._
  14
+import code.lib._
  15
+
  16
+
  17
+/**
  18
+ * A class that's instantiated early and run.  It allows the application
  19
+ * to modify lift's environment
  20
+ */
  21
+class Boot {
  22
+  def boot {
  23
+    if (!DB.jndiJdbcConnAvailable_?) {
  24
+      val vendor = 
  25
+	new StandardDBVendor(Props.get("db.driver") openOr "org.h2.Driver",
  26
+			     Props.get("db.url") openOr 
  27
+			     "jdbc:h2:lift_proto.db;AUTO_SERVER=TRUE",
  28
+			     Props.get("db.user"), Props.get("db.password"))
  29
+
  30
+      LiftRules.unloadHooks.append(vendor.closeAllConnections_! _)
  31
+
  32
+      DB.defineConnectionManager(DefaultConnectionIdentifier, vendor)
  33
+    }
  34
+
  35
+    // Use Lift's Mapper ORM to populate the database
  36
+    // you don't need to use Mapper to use Lift... use
  37
+    // any ORM you want
  38
+    Schemifier.schemify(true, Schemifier.infoF _, User)
  39
+
  40
+    // where to search snippet
  41
+    LiftRules.addToPackages("code")
  42
+
  43
+    // Build SiteMap
  44
+    def sitemap = SiteMap(
  45
+      Menu.i("Home") / "index" >> User.AddUserMenusAfter, // the simple way to declare a menu
  46
+
  47
+      // more complex because this menu allows anything in the
  48
+      // /static path to be visible
  49
+      Menu(Loc("Static", Link(List("static"), true, "/static/index"), 
  50
+	       "Static Content")))
  51
+
  52
+    def sitemapMutators = User.sitemapMutator
  53
+
  54
+    // set the sitemap.  Note if you don't want access control for
  55
+    // each page, just comment this line out.
  56
+    LiftRules.setSiteMapFunc(() => sitemapMutators(sitemap))
  57
+
  58
+    //Show the spinny image when an Ajax call starts
  59
+    LiftRules.ajaxStart =
  60
+      Full(() => LiftRules.jsArtifacts.show("ajax-loader").cmd)
  61
+    
  62
+    // Make the spinny image go away when it ends
  63
+    LiftRules.ajaxEnd =
  64
+      Full(() => LiftRules.jsArtifacts.hide("ajax-loader").cmd)
  65
+
  66
+    // Force the request to be UTF-8
  67
+    LiftRules.early.append(_.setCharacterEncoding("UTF-8"))
  68
+
  69
+    // What is the function to test if a user is logged in?
  70
+    LiftRules.loggedInTest = Full(() => User.loggedIn_?)
  71
+
  72
+    // Use HTML5 for rendering
  73
+    LiftRules.htmlProperties.default.set((r: Req) =>
  74
+      new Html5Properties(r.userAgent))    
  75
+
  76
+    JRuby.init()
  77
+
  78
+    // Make a transaction span the whole HTTP request
  79
+    S.addAround(DB.buildLoanWrapper)
  80
+  }
  81
+
  82
+}
0  src/main/scala/code/comet/.keep
No changes.
57  src/main/scala/code/lib/DependencyFactory.scala
... ...
@@ -0,0 +1,57 @@
  1
+package code {
  2
+package lib {
  3
+
  4
+import net.liftweb._
  5
+import http._
  6
+import util._
  7
+import common._
  8
+import _root_.java.util.Date
  9
+
  10
+/**
  11
+ * A factory for generating new instances of Date.  You can create
  12
+ * factories for each kind of thing you want to vend in your application.
  13
+ * An example is a payment gateway.  You can change the default implementation,
  14
+ * or override the default implementation on a session, request or current call
  15
+ * stack basis.
  16
+ */
  17
+object DependencyFactory extends Factory {
  18
+  implicit object time extends FactoryMaker(Helpers.now _)
  19
+
  20
+  /**
  21
+   * objects in Scala are lazily created.  The init()
  22
+   * method creates a List of all the objects.  This
  23
+   * results in all the objects getting initialized and
  24
+   * registering their types with the dependency injector
  25
+   */
  26
+  private def init() {
  27
+    List(time)
  28
+  }
  29
+  init()
  30
+}
  31
+
  32
+/*
  33
+/**
  34
+ * Examples of changing the implementation
  35
+ */
  36
+sealed abstract class Changer {
  37
+  def changeDefaultImplementation() {
  38
+    DependencyFactory.time.default.set(() => new Date())
  39
+  }
  40
+
  41
+  def changeSessionImplementation() {
  42
+    DependencyFactory.time.session.set(() => new Date())
  43
+  }
  44
+
  45
+  def changeRequestImplementation() {
  46
+    DependencyFactory.time.request.set(() => new Date())
  47
+  }
  48
+
  49
+  def changeJustForCall(d: Date) {
  50
+    DependencyFactory.time.doWith(d) {
  51
+      // perform some calculations here
  52
+    }
  53
+  }
  54
+}
  55
+*/
  56
+}
  57
+}
78  src/main/scala/code/lib/JRuby.scala
... ...
@@ -0,0 +1,78 @@
  1
+package code
  2
+package lib
  3
+
  4
+import net.liftweb._
  5
+import http._
  6
+import util._
  7
+import Helpers._
  8
+
  9
+import org.jruby.embed._
  10
+import org.jruby._
  11
+import org.jruby.runtime.builtin._
  12
+
  13
+import scala.xml.NodeSeq
  14
+
  15
+
  16
+case class JRubyCallable(inst: IRubyObject, meth: String) extends Function1[NodeSeq, NodeSeq] {
  17
+  import JRuby._
  18
+
  19
+  import scala.collection.JavaConversions._
  20
+
  21
+  def apply(in: NodeSeq): NodeSeq = {
  22
+    inst.callMethod(context, meth) match {
  23
+      case rh: RubyHash => {
  24
+        val lst: List[CssBindFunc] = 
  25
+          for {
  26
+            (k, v) <- rh.toList
  27
+          } yield k.toString #> v.toString
  28
+        
  29
+        lst match {
  30
+          case Nil => NodeSeq.Empty
  31
+          case xs => xs.reduceLeft(_ & _)(in)
  32
+        }
  33
+      }
  34
+    }
  35
+  }
  36
+}
  37
+
  38
+object JRuby {
  39
+  lazy val jruby = new ScriptingContainer(LocalContextScope.THREADSAFE)
  40
+  def runtime = jruby.getProvider().getRuntime()
  41
+  def context = runtime.getCurrentContext()
  42
+
  43
+  def init() {
  44
+    LiftRules.snippets.append {
  45
+      case JRuby(toCall) => toCall
  46
+    }
  47
+  }
  48
+  
  49
+  def unapply(in: List[String]): Option[JRubyCallable] = in match {
  50
+    case Nil => None
  51
+    case x :: xs => {
  52
+      for {
  53
+        parsed <- tryo(LiftRules.doWithResource("/"+x+".rb") {
  54
+          is =>
  55
+            jruby.parse(is, x+".rb").run()
  56
+        })
  57
+        
  58
+        clz <- tryo(runtime.fastGetClass(x))
  59
+        
  60
+        methName = xs.headOption getOrElse "render"
  61
+        
  62
+        inst <- tryo(clz.newInstance(context, Array(), null)) if {
  63
+          val ret = inst.callMethod(context, "respond_to?", 
  64
+                                    runtime.
  65
+                                    fastNewSymbol(methName)).
  66
+          toJava(classOf[Boolean])
  67
+          
  68
+          ret match {
  69
+            case b: _root_.java.lang.Boolean => b.booleanValue()
  70
+            case _ => false
  71
+          }
  72
+        }
  73
+      } yield {
  74
+        JRubyCallable(inst, methName)
  75
+      }
  76
+    }
  77
+  }
  78
+}
38  src/main/scala/code/model/User.scala
... ...
@@ -0,0 +1,38 @@
  1
+package code {
  2
+package model {
  3
+
  4
+import _root_.net.liftweb.mapper._
  5
+import _root_.net.liftweb.util._
  6
+import _root_.net.liftweb.common._
  7
+
  8
+/**
  9
+ * The singleton that has methods for accessing the database
  10
+ */
  11
+object User extends User with MetaMegaProtoUser[User] {
  12
+  override def dbTableName = "users" // define the DB table name
  13
+  override def screenWrap = Full(<lift:surround with="default" at="content">
  14
+			       <lift:bind /></lift:surround>)
  15
+  // define the order fields will appear in forms and output
  16
+  override def fieldOrder = List(id, firstName, lastName, email,
  17
+  locale, timezone, password, textArea)
  18
+
  19
+  // comment this line out to require email validations
  20
+  override def skipEmailValidation = true
  21
+}
  22
+
  23
+/**
  24
+ * An O-R mapped "User" class that includes first name, last name, password and we add a "Personal Essay" to it
  25
+ */
  26
+class User extends MegaProtoUser[User] {
  27
+  def getSingleton = User // what's the "meta" server
  28
+
  29
+  // define an additional field for a personal essay
  30
+  object textArea extends MappedTextarea(this, 2048) {
  31
+    override def textareaRows  = 10
  32
+    override def textareaCols = 50
  33
+    override def displayName = "Personal Essay"
  34
+  }
  35
+}
  36
+
  37
+}
  38
+}
10  src/main/scala/code/snippet/Frog.scala
... ...
@@ -0,0 +1,10 @@
  1
+package code
  2
+package snippet
  3
+
  4
+import net.liftweb._
  5
+import util.Helpers._
  6
+
  7
+object Frog {
  8
+  def render = "span *" #> (1 to 10).map(i => now.toString) &
  9
+  "#foo *" #> "bar"
  10
+}
25  src/main/scala/code/snippet/HelloWorld.scala
... ...
@@ -0,0 +1,25 @@
  1
+package code {
  2
+package snippet {
  3
+
  4
+import _root_.scala.xml.{NodeSeq, Text}
  5
+import _root_.net.liftweb.util._
  6
+import _root_.net.liftweb.common._
  7
+import _root_.java.util.Date
  8
+import code.lib._
  9
+import Helpers._
  10
+
  11
+class HelloWorld {
  12
+  lazy val date: Box[Date] = DependencyFactory.inject[Date] // inject the date
  13
+
  14
+  // replace the contents of the element with id "time" with the date
  15
+  def howdy = "#time *" #> date.map(_.toString)
  16
+
  17
+  /*
  18
+   lazy val date: Date = DependencyFactory.time.vend // create the date via factory
  19
+
  20
+   def howdy = "#time *" #> date.toString
  21
+   */
  22
+}
  23
+
  24
+}
  25
+}
0  src/main/scala/code/view/.keep
No changes.
21  src/main/webapp/WEB-INF/web.xml
... ...
@@ -0,0 +1,21 @@
  1
+<?xml version="1.0" encoding="ISO-8859-1"?>
  2
+
  3
+<!DOCTYPE web-app
  4
+PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  5
+"http://java.sun.com/dtd/web-app_2_3.dtd">
  6
+
  7
+<web-app>
  8
+<filter>
  9
+  <filter-name>LiftFilter</filter-name>
  10
+  <display-name>Lift Filter</display-name>
  11
+  <description>The Filter that intercepts lift calls</description>
  12
+  <filter-class>net.liftweb.http.LiftFilter</filter-class>
  13
+</filter>
  14
+  	
  15
+
  16
+<filter-mapping>
  17
+  <filter-name>LiftFilter</filter-name>
  18
+  <url-pattern>/*</url-pattern>
  19
+</filter-mapping>
  20
+
  21
+</web-app>
BIN  src/main/webapp/images/ajax-loader.gif
20  src/main/webapp/index.html
... ...
@@ -0,0 +1,20 @@
  1
+<!DOCTYPE html>
  2
+<html>
  3
+  <head>
  4
+    <meta content="text/html; charset=UTF-8" http-equiv="content-type" />
  5
+    <title>Home</title>
  6
+  </head>
  7
+  <body class="lift:content_id=main">
  8
+    <div id="main" class="lift:surround?with=default;at=content">
  9
+      <h2>Welcome to your project!</h2>
  10
+      <p>
  11
+	<span class="lift:helloWorld.howdy">
  12
+	  Welcome to your Lift app at <span id="time">Time goes here</span>
  13
+	</span>
  14
+      </p>
  15
+
  16
+      <div lift="Zoro.yo">Hello the time is <span>now</span> <b id="foo">baz</b></div>
  17
+    </div>
  18
+  </body>
  19
+</html>
  20
+
5  src/main/webapp/static/index.html
... ...
@@ -0,0 +1,5 @@
  1
+<div id="main" class="lift:surround?with=default;at=content">
  2
+  Static content... everything you put in the /static
  3
+  directory will be served without additions to SiteMap
  4
+</div>
  5
+
85  src/main/webapp/templates-hidden/default.html
... ...
@@ -0,0 +1,85 @@
  1
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:lift="http://liftweb.net/">
  2
+  <head>
  3
+    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  4
+    <meta name="description" content="" />
  5
+    <meta name="keywords" content="" />
  6
+    <title class="lift:Menu.title">App: </title>
  7
+    <style class="lift:CSS.blueprint"></style>
  8
+    <style class="lift:CSS.fancyType"></style>
  9
+    <script id="jquery" src="/classpath/jquery.js" type="text/javascript"></script>
  10
+    <script id="json" src="/classpath/json.js" type="text/javascript"></script>
  11
+    <style type="text/css">
  12
+/* <![CDATA[ */
  13
+.edit_error_class {
  14
+  display: block;
  15
+  color: red;
  16
+}
  17
+
  18
+.sidebar ul {
  19
+	margin:0;
  20
+	padding:0;
  21
+	border-bottom:1px solid #ccc;
  22
+}
  23
+	 
  24
+
  25
+.sidebar ul li {
  26
+	margin:0;
  27
+	padding:0;
  28
+	list-style:none;
  29
+	border:1px solid #ccc;
  30
+	border-bottom:none;
  31
+}
  32
+
  33
+.sidebar ul li a {
  34
+	display:block;
  35
+	padding:3px;
  36
+	text-indent:30px;
  37
+	text-decoration:none;
  38
+}
  39
+
  40
+.sidebar ul li span {
  41
+	display:block;
  42
+	padding:3px;
  43
+	text-indent:30px;
  44
+	text-decoration:none;
  45
+}
  46
+
  47
+.sidebar ul li a:hover {
  48
+	background-color: #eee;
  49
+}
  50
+
  51
+
  52
+  /* ]]> */
  53
+  </style>
  54
+  </head>
  55
+  <body>
  56
+    <div class="container">
  57
+      <div class="column span-12 last" style="text-align: right">
  58
+        <h1 class="alt">app<img alt="" id="ajax-loader" style="display:none; margin-bottom: 0px; margin-left: 5px" src="/images/ajax-loader.gif"></h1>
  59
+      </div>
  60
+
  61
+      <hr>
  62
+
  63
+      <div class="column span-6 colborder sidebar">
  64
+        <hr class="space" >
  65
+
  66
+	<span class="lift:Menu.builder"></span>
  67
+
  68
+        <div class="lift:Msgs?showAll=true"></div>
  69
+        <hr class="space" />
  70
+      </div>
  71
+
  72
+      <div class="column span-17 last">
  73
+        <div id="content">The main content will get bound here</div>
  74
+      </div>
  75
+
  76
+      <hr />
  77
+      <div class="column span-23 last" style="text-align: center">
  78
+        <h4 class="alt">
  79
+          <a href="http://www.liftweb.net"><i>Lift</i></a> 
  80
+	  is Copyright 2007-2010 WorldWide Conferencing, LLC.
  81
+	  Distributed under an Apache 2.0 License.</h4>
  82
+      </div>
  83
+    </div>
  84
+  </body>
  85
+</html>
57  src/main/webapp/templates-hidden/wizard-all.html
... ...
@@ -0,0 +1,57 @@
  1
+<div>
  2
+  <wizard:screen_info><div>Page <wizard:screen_number></wizard:screen_number> of <wizard:total_screens></wizard:total_screens></div></wizard:screen_info>
  3
+  <wizard:wizard_top> <div> <wizard:bind></wizard:bind> </div> </wizard:wizard_top>
  4
+  <wizard:screen_top> <div> <wizard:bind></wizard:bind> </div> </wizard:screen_top>
  5
+  <wizard:errors> <div> <ul> <wizard:item> <li> <wizard:bind></wizard:bind> </li> </wizard:item> </ul> </div> </wizard:errors>
  6
+  <div>
  7
+    <wizard:fields>
  8
+      <table>
  9
+	<tbody>
  10
+            <tr lift:bind="wizard:line">
  11
+              <td>
  12
+		<wizard:label>
  13
+		  <label wizard:for="">
  14
+		    <wizard:bind></wizard:bind>
  15
+		  </label>
  16
+		</wizard:label>
  17
+		<wizard:help>
  18
+		  <span>
  19
+		    <wizard:bind></wizard:bind>
  20
+		  </span>
  21
+		</wizard:help>
  22
+		<wizard:field_errors>
  23
+		  <ul>
  24
+		    <wizard:error>
  25
+		      <li>
  26
+			<wizard:bind></wizard:bind>
  27
+		      </li>
  28
+		    </wizard:error> 
  29
+		  </ul>
  30
+		</wizard:field_errors>
  31
+              </td>
  32
+              <td>
  33
+		<wizard:form></wizard:form>
  34
+	      </td>
  35
+            </tr>
  36
+	</tbody>
  37
+      </table>
  38
+    </wizard:fields>
  39
+  </div>
  40
+  <div>
  41
+    <table>
  42
+      <tr> 
  43
+	<td>
  44
+	  <wizard:prev></wizard:prev> 
  45
+	</td>
  46
+	<td>
  47
+	  <wizard:cancel></wizard:cancel>
  48
+	</td>
  49
+	<td>
  50
+	  <wizard:next></wizard:next>
  51
+	</td>
  52
+      </tr>
  53
+    </table>
  54
+  </div>
  55
+  <wizard:screen_bottom> <div> <wizard:bind></wizard:bind> </div> </wizard:screen_bottom>
  56
+  <wizard:wizard_bottom> <div> <wizard:bind></wizard:bind> </div> </wizard:wizard_bottom>
  57
+</div>
0  src/test/resources/.keep
No changes.
15  src/test/scala/LiftConsole.scala
... ...
@@ -0,0 +1,15 @@
  1
+import _root_.bootstrap.liftweb.Boot
  2
+import _root_.scala.tools.nsc.MainGenericRunner
  3
+
  4
+object LiftConsole {
  5
+  def main(args : Array[String]) {
  6
+    // Instantiate your project's Boot file
  7
+    val b = new Boot()
  8
+    // Boot your project
  9
+    b.boot
  10
+    // Now run the MainGenericRunner to get your repl
  11
+    MainGenericRunner.main(args)
  12
+    // After the repl exits, then exit the scala script
  13
+    exit(0)
  14
+  }
  15
+}
33  src/test/scala/RunWebApp.scala
... ...
@@ -0,0 +1,33 @@
  1
+import _root_.org.mortbay.jetty.Connector
  2
+import _root_.org.mortbay.jetty.Server
  3
+import _root_.org.mortbay.jetty.webapp.WebAppContext
  4
+import org.mortbay.jetty.nio._
  5
+
  6
+object RunWebApp extends Application {
  7
+  val server = new Server
  8
+  val scc = new SelectChannelConnector
  9
+  scc.setPort(8080)
  10
+  server.setConnectors(Array(scc))
  11
+
  12
+  val context = new WebAppContext()
  13
+  context.setServer(server)
  14
+  context.setContextPath("/")
  15
+  context.setWar("src/main/webapp")
  16
+
  17
+  server.addHandler(context)
  18
+
  19
+  try {
  20
+    println(">>> STARTING EMBEDDED JETTY SERVER, PRESS ANY KEY TO STOP")
  21
+    server.start()
  22
+    while (System.in.available() == 0) {
  23
+      Thread.sleep(5000)
  24
+    }
  25
+    server.stop()
  26
+    server.join()
  27
+  } catch {
  28
+    case exc : Exception => {
  29
+      exc.printStackTrace()
  30
+      System.exit(100)
  31
+    }
  32
+  }
  33
+}
76  src/test/scala/code/AppTest.scala
... ...
@@ -0,0 +1,76 @@
  1
+package code
  2
+
  3
+import _root_.java.io.File
  4
+import _root_.junit.framework._
  5
+import Assert._
  6
+import _root_.scala.xml.XML
  7
+import _root_.net.liftweb.util._
  8
+import _root_.net.liftweb.common._
  9
+
  10
+object AppTest {
  11
+  def suite: Test = {
  12
+    val suite = new TestSuite(classOf[AppTest])
  13
+    suite
  14
+  }
  15
+
  16
+  def main(args : Array[String]) {
  17
+    _root_.junit.textui.TestRunner.run(suite)
  18
+  }
  19
+}
  20
+
  21
+/**
  22
+ * Unit test for simple App.
  23
+ */
  24
+class AppTest extends TestCase("app") {
  25
+
  26
+  /**
  27
+   * Rigourous Tests :-)
  28
+   */
  29
+  def testOK() = assertTrue(true)
  30
+  // def testKO() = assertTrue(false);
  31
+
  32
+  /**
  33
+   * Tests to make sure the project's XML files are well-formed.
  34
+   *
  35
+   * Finds every *.html and *.xml file in src/main/webapp (and its
  36
+   * subdirectories) and tests to make sure they are well-formed.
  37
+   */
  38
+  def testXml() = {
  39
+    var failed: List[File] = Nil
  40
+
  41
+    def handledXml(file: String) =
  42
+      file.endsWith(".xml")
  43
+
  44
+    def handledXHtml(file: String) =
  45
+      file.endsWith(".html") || file.endsWith(".htm") || file.endsWith(".xhtml")
  46
+
  47
+    def wellFormed(file: File) {
  48
+      if (file.isDirectory)
  49
+        for (f <- file.listFiles) wellFormed(f)
  50
+
  51
+      if (file.isFile && handledXml(file.getName)) {
  52
+        try {
  53
+          XML.loadFile(file)
  54
+        } catch {
  55
+          case e: _root_.org.xml.sax.SAXParseException => failed = file :: failed
  56
+        }
  57
+      }
  58
+      if (file.isFile && handledXHtml(file.getName)) {
  59
+        PCDataXmlParser(new _root_.java.io.FileInputStream(file.getAbsolutePath)) match {
  60
+          case Full(_) => // file is ok
  61
+          case _ => failed = file :: failed
  62
+        }
  63
+      }
  64
+    }
  65
+
  66
+    wellFormed(new File("src/main/webapp"))
  67
+
  68
+    val numFails = failed.size
  69
+    if (numFails > 0) {
  70
+      val fileStr = if (numFails == 1) "file" else "files"
  71
+      val msg = "Malformed XML in " + numFails + " " + fileStr + ": " + failed.mkString(", ")
  72
+      println(msg)
  73
+      fail(msg)
  74
+    }
  75
+  }
  76
+}
64  src/test/scala/code/XmlSourceSpecs.scala
... ...
@@ -0,0 +1,64 @@
  1
+package code
  2
+
  3
+import java.io.File
  4
+
  5
+import scala.xml.XML
  6
+
  7
+import org.specs.Specification
  8
+import org.specs.runner.JUnit4
  9
+
  10
+import net.liftweb.common.Full
  11
+import net.liftweb.util.PCDataXmlParser
  12
+
  13
+class XmlSourceSpecsTest extends JUnit4(XmlSourceSpecs)
  14
+
  15
+object XmlSourceSpecs extends Specification {
  16
+
  17
+  "XML Sources" should {
  18
+    "be well-formed" in {
  19
+      /**
  20
+       * Tests to make sure the project's XML files are well-formed.
  21
+       *
  22
+       * Finds every *.html and *.xml file in src/main/webapp (and its
  23
+       * subdirectories) and tests to make sure they are well-formed.
  24
+       */
  25
+      var failed: List[File] = Nil
  26
+      
  27
+      def handledXml(file: String) =
  28
+	file.endsWith(".xml")
  29
+      
  30
+      def handledXHtml(file: String) =
  31
+	file.endsWith(".html") || file.endsWith(".htm") || file.endsWith(".xhtml")
  32
+      
  33
+      def wellFormed(file: File) {
  34
+	if (file.isDirectory)
  35
+	  for (f <- file.listFiles) wellFormed(f)
  36
+        
  37
+	if (file.isFile && handledXml(file.getName)) {
  38
+	  try {
  39
+	    XML.loadFile(file)
  40
+	  } catch {
  41
+	    case e: _root_.org.xml.sax.SAXParseException => failed = file :: failed
  42
+	  }
  43
+	}
  44
+	if (file.isFile && handledXHtml(file.getName)) {
  45
+	  PCDataXmlParser(new java.io.FileInputStream(file.getAbsolutePath)) match {
  46
+	    case Full(_) => // file is ok
  47
+	      case _ => failed = file :: failed
  48
+	  }
  49
+	}
  50
+      }
  51
+      
  52
+      wellFormed(new File("src/main/webapp"))
  53
+      
  54
+      val numFails = failed.size
  55
+      if (numFails > 0) {
  56
+	val fileStr = if (numFails == 1) "file" else "files"
  57
+	val msg = "Malformed XML in " + numFails + " " + fileStr + ": " + failed.mkString(", ")
  58
+	fail(msg)
  59
+      }
  60
+      
  61
+      numFails must_== 0
  62
+    }
  63
+  }
  64
+}
46  src/test/scala/code/snippet/HelloWorldTest.scala
... ...
@@ -0,0 +1,46 @@
  1
+package code {
  2
+package snippet {
  3
+
  4
+import org.specs._
  5
+import org.specs.runner.JUnit4
  6
+import org.specs.runner.ConsoleRunner
  7
+import net.liftweb._
  8
+import http._
  9
+import net.liftweb.util._
  10
+import net.liftweb.common._
  11
+import org.specs.matcher._
  12
+import org.specs.specification._
  13
+import Helpers._
  14
+import lib._
  15
+
  16
+
  17
+class HelloWorldTestSpecsAsTest extends JUnit4(HelloWorldTestSpecs)
  18
+object HelloWorldTestSpecsRunner extends ConsoleRunner(HelloWorldTestSpecs)
  19
+
  20
+object HelloWorldTestSpecs extends Specification {
  21
+  val session = new LiftSession("", randomString(20), Empty)
  22
+  val stableTime = now
  23
+
  24
+  override def executeExpectations(ex: Examples, t: =>Any): Any = {
  25
+    S.initIfUninitted(session) {
  26
+      DependencyFactory.time.doWith(stableTime) {
  27
+        super.executeExpectations(ex, t)
  28
+      }
  29
+    }
  30
+  }
  31
+
  32
+  "HelloWorld Snippet" should {
  33
+    "Put the time in the node" in {
  34
+      val hello = new HelloWorld
  35
+      Thread.sleep(1000) // make sure the time changes
  36
+
  37
+      val str = hello.howdy(<span>Welcome to your Lift app at <span id="time">Time goes here</span></span>).toString
  38
+
  39
+      str.indexOf(stableTime.toString) must be >= 0
  40
+      str.indexOf("Hello at") must be >= 0
  41
+    }
  42
+  }
  43
+}
  44
+
  45
+}
  46
+}

0 notes on commit 07a39d2

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