Permalink
Browse files

Initial research spike for JRuby/Lift integration

  • Loading branch information...
dpp committed Jan 28, 2011
0 parents commit 07a39d24e6b6444c5e76d84302fb3739ba30e856
@@ -0,0 +1,56 @@
+# use glob syntax.
+syntax: glob
+*.ser
+*.class
+*~
+*.bak
+*.off
+*.old
+.DS_Store
+
+# logs
+derby.log
+
+# eclipse conf file
+.settings
+.classpath
+.project
+.manager
+.externalToolBuilders
+
+# ensime/emacs conf files
+.ensime
+.scala_dependencies
+
+# building
+target
+null
+tmp*
+dist
+test-output
+
+# sbt
+target
+lib_managed
+src_managed
+project/boot
+
+# other scm
+.svn
+.CVS
+.hg*
+
+# switch to regexp syntax.
+# syntax: regexp
+# ^\.pc/
+
+# IntelliJ
+*.iml
+*.ipr
+*.iws
+.idea
+
+# Pax Runner (for easy OSGi launching)
+runner
+
+*.db
@@ -0,0 +1,9 @@
+#Project properties
+#Fri Apr 23 11:24:20 PDT 2010
+project.organization=Lift
+project.name=Lift SBT Template
+sbt.version=0.7.4
+project.version=0.1
+def.scala.version=2.7.7
+build.scala.versions=2.8.1
+project.initialize=false
@@ -0,0 +1,25 @@
+import sbt._
+
+class LiftProject(info: ProjectInfo) extends DefaultWebProject(info) {
+ val liftVersion = "2.3-SNAPSHOT"
+
+ // uncomment the following if you want to use the snapshot repo
+ // val scalatoolsSnapshot = ScalaToolsSnapshots
+
+ val m2 = "m2" at "file:///home/dpp/.m2/repository"
+
+ // If you're using JRebel for Lift development, uncomment
+ // this line
+ override def scanDirectories = Nil
+
+ override def libraryDependencies = Set(
+ "net.liftweb" %% "lift-webkit" % liftVersion % "compile->default",
+ "net.liftweb" %% "lift-mapper" % liftVersion % "compile->default",
+ "org.jruby" % "jruby-complete" % "1.6.0.RC1",
+ "org.mortbay.jetty" % "jetty" % "6.1.22" % "test->default",
+ "junit" % "junit" % "4.5" % "test->default",
+ "ch.qos.logback" % "logback-classic" % "0.9.26",
+ "org.scala-tools.testing" %% "specs" % "1.6.6" % "test->default",
+ "com.h2database" % "h2" % "1.2.138"
+ ) ++ super.libraryDependencies
+}
1 sbt
@@ -0,0 +1 @@
+java -Xmx512M -Xss2M -XX:+CMSClassUnloadingEnabled -jar `dirname $0`/sbt-launcher.jar "$@"
Binary file not shown.
@@ -0,0 +1,2 @@
+set SCRIPT_DIR=%~dp0
+java -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -jar "%SCRIPT_DIR%\sbt-launcher.jar" %*
No changes.
@@ -0,0 +1,8 @@
+class Zoro
+ def yo
+ {
+ "span *" => Time.now.to_s,
+ "#foo" => "holy cow, that works"
+ }
+ end
+end
No changes.
@@ -0,0 +1,82 @@
+package bootstrap.liftweb
+
+import net.liftweb._
+import util._
+import Helpers._
+
+import common._
+import http._
+import sitemap._
+import Loc._
+import mapper._
+
+import code.model._
+import code.lib._
+
+
+/**
+ * A class that's instantiated early and run. It allows the application
+ * to modify lift's environment
+ */
+class Boot {
+ def boot {
+ if (!DB.jndiJdbcConnAvailable_?) {
+ val vendor =
+ new StandardDBVendor(Props.get("db.driver") openOr "org.h2.Driver",
+ Props.get("db.url") openOr
+ "jdbc:h2:lift_proto.db;AUTO_SERVER=TRUE",
+ Props.get("db.user"), Props.get("db.password"))
+
+ LiftRules.unloadHooks.append(vendor.closeAllConnections_! _)
+
+ DB.defineConnectionManager(DefaultConnectionIdentifier, vendor)
+ }
+
+ // Use Lift's Mapper ORM to populate the database
+ // you don't need to use Mapper to use Lift... use
+ // any ORM you want
+ Schemifier.schemify(true, Schemifier.infoF _, User)
+
+ // where to search snippet
+ LiftRules.addToPackages("code")
+
+ // Build SiteMap
+ def sitemap = SiteMap(
+ Menu.i("Home") / "index" >> User.AddUserMenusAfter, // the simple way to declare a menu
+
+ // more complex because this menu allows anything in the
+ // /static path to be visible
+ Menu(Loc("Static", Link(List("static"), true, "/static/index"),
+ "Static Content")))
+
+ def sitemapMutators = User.sitemapMutator
+
+ // set the sitemap. Note if you don't want access control for
+ // each page, just comment this line out.
+ LiftRules.setSiteMapFunc(() => sitemapMutators(sitemap))
+
+ //Show the spinny image when an Ajax call starts
+ LiftRules.ajaxStart =
+ Full(() => LiftRules.jsArtifacts.show("ajax-loader").cmd)
+
+ // Make the spinny image go away when it ends
+ LiftRules.ajaxEnd =
+ Full(() => LiftRules.jsArtifacts.hide("ajax-loader").cmd)
+
+ // Force the request to be UTF-8
+ LiftRules.early.append(_.setCharacterEncoding("UTF-8"))
+
+ // What is the function to test if a user is logged in?
+ LiftRules.loggedInTest = Full(() => User.loggedIn_?)
+
+ // Use HTML5 for rendering
+ LiftRules.htmlProperties.default.set((r: Req) =>
+ new Html5Properties(r.userAgent))
+
+ JRuby.init()
+
+ // Make a transaction span the whole HTTP request
+ S.addAround(DB.buildLoanWrapper)
+ }
+
+}
No changes.
@@ -0,0 +1,57 @@
+package code {
+package lib {
+
+import net.liftweb._
+import http._
+import util._
+import common._
+import _root_.java.util.Date
+
+/**
+ * A factory for generating new instances of Date. You can create
+ * factories for each kind of thing you want to vend in your application.
+ * An example is a payment gateway. You can change the default implementation,
+ * or override the default implementation on a session, request or current call
+ * stack basis.
+ */
+object DependencyFactory extends Factory {
+ implicit object time extends FactoryMaker(Helpers.now _)
+
+ /**
+ * objects in Scala are lazily created. The init()
+ * method creates a List of all the objects. This
+ * results in all the objects getting initialized and
+ * registering their types with the dependency injector
+ */
+ private def init() {
+ List(time)
+ }
+ init()
+}
+
+/*
+/**
+ * Examples of changing the implementation
+ */
+sealed abstract class Changer {
+ def changeDefaultImplementation() {
+ DependencyFactory.time.default.set(() => new Date())
+ }
+
+ def changeSessionImplementation() {
+ DependencyFactory.time.session.set(() => new Date())
+ }
+
+ def changeRequestImplementation() {
+ DependencyFactory.time.request.set(() => new Date())
+ }
+
+ def changeJustForCall(d: Date) {
+ DependencyFactory.time.doWith(d) {
+ // perform some calculations here
+ }
+ }
+}
+*/
+}
+}
@@ -0,0 +1,78 @@
+package code
+package lib
+
+import net.liftweb._
+import http._
+import util._
+import Helpers._
+
+import org.jruby.embed._
+import org.jruby._
+import org.jruby.runtime.builtin._
+
+import scala.xml.NodeSeq
+
+
+case class JRubyCallable(inst: IRubyObject, meth: String) extends Function1[NodeSeq, NodeSeq] {
+ import JRuby._
+
+ import scala.collection.JavaConversions._
+
+ def apply(in: NodeSeq): NodeSeq = {
+ inst.callMethod(context, meth) match {
+ case rh: RubyHash => {
+ val lst: List[CssBindFunc] =
+ for {
+ (k, v) <- rh.toList
+ } yield k.toString #> v.toString
+
+ lst match {
+ case Nil => NodeSeq.Empty
+ case xs => xs.reduceLeft(_ & _)(in)
+ }
+ }
+ }
+ }
+}
+
+object JRuby {
+ lazy val jruby = new ScriptingContainer(LocalContextScope.THREADSAFE)
+ def runtime = jruby.getProvider().getRuntime()
+ def context = runtime.getCurrentContext()
+
+ def init() {
+ LiftRules.snippets.append {
+ case JRuby(toCall) => toCall
+ }
+ }
+
+ def unapply(in: List[String]): Option[JRubyCallable] = in match {
+ case Nil => None
+ case x :: xs => {
+ for {
+ parsed <- tryo(LiftRules.doWithResource("/"+x+".rb") {
+ is =>
+ jruby.parse(is, x+".rb").run()
+ })
+
+ clz <- tryo(runtime.fastGetClass(x))
+
+ methName = xs.headOption getOrElse "render"
+
+ inst <- tryo(clz.newInstance(context, Array(), null)) if {
+ val ret = inst.callMethod(context, "respond_to?",
+ runtime.
+ fastNewSymbol(methName)).
+ toJava(classOf[Boolean])
+
+ ret match {
+ case b: _root_.java.lang.Boolean => b.booleanValue()
+ case _ => false
+ }
+ }
+ } yield {
+ JRubyCallable(inst, methName)
+ }
+ }
+ }
+}
@@ -0,0 +1,38 @@
+package code {
+package model {
+
+import _root_.net.liftweb.mapper._
+import _root_.net.liftweb.util._
+import _root_.net.liftweb.common._
+
+/**
+ * The singleton that has methods for accessing the database
+ */
+object User extends User with MetaMegaProtoUser[User] {
+ override def dbTableName = "users" // define the DB table name
+ override def screenWrap = Full(<lift:surround with="default" at="content">
+ <lift:bind /></lift:surround>)
+ // define the order fields will appear in forms and output
+ override def fieldOrder = List(id, firstName, lastName, email,
+ locale, timezone, password, textArea)
+
+ // comment this line out to require email validations
+ override def skipEmailValidation = true
+}
+
+/**
+ * An O-R mapped "User" class that includes first name, last name, password and we add a "Personal Essay" to it
+ */
+class User extends MegaProtoUser[User] {
+ def getSingleton = User // what's the "meta" server
+
+ // define an additional field for a personal essay
+ object textArea extends MappedTextarea(this, 2048) {
+ override def textareaRows = 10
+ override def textareaCols = 50
+ override def displayName = "Personal Essay"
+ }
+}
+
+}
+}
@@ -0,0 +1,10 @@
+package code
+package snippet
+
+import net.liftweb._
+import util.Helpers._
+
+object Frog {
+ def render = "span *" #> (1 to 10).map(i => now.toString) &
+ "#foo *" #> "bar"
+}
Oops, something went wrong.

0 comments on commit 07a39d2

Please sign in to comment.