alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Lift Framework example source code file (Bindings.scala)

This example Lift Framework source code file (Bindings.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Lift Framework tags/keywords

binder, binder, binding, binding, bindings, databinding, databinding, full, list, nodeseq, nodeseq, t, text, unable

The Lift Framework Bindings.scala source code

/*
 * Copyright 2006-2009 WorldWide Conferencing, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 */

package net.liftweb
package http 

import common.{Box,Full,Empty,Failure}
import util.Props
import scala.xml.{NodeSeq, Text}

/**
 * A collection of types and implicit transformations used to allow composition
 * of page elements based upon the types of rendered objects.
 *
 * In Lift, a "snippet" is a function from NodeSeq => NodeSeq, where the argument
 * to the function is a template, and the result is a fragment of a page to be 
 * rendered. Of course, this is a bit of an abbreviation; the snippet function
 * also has an argument which is the application state made available from S.
 * A DataBinding[T] is very similar in this respect; it is a function from some
 * piece of information of type T to a function from NodeSeq => NodeSeq. Since
 * DataBinding is strongly typed with respect to the type of information being
 * rendered, DataBinding instances are ideal for the rendering of objects that
 * is used to build up snippets. For example:
 * 
 * <pre>
 * import net.liftweb.http.Bindings._

 * case class MyClass(str: String, i: Int, other: MyOtherClass)
 * case class MyOtherClass(foo: String)
 *
 * trait MyClassBinding extends DataBinding[MyClass] {
 *   implicit val otherBinding: DataBinding[MyOtherClass]
 *
 *   override def apply(entity: MyClass) = (xhtml: NodeSeq) => {
 *     val otherTemplate = chooseTemplate("myclass", "other", xhtml)
 *     bind(
 *       "myclass", xhtml, 
 *       "str" -> Text("#" + entity.str + "#"),
 *       "i" -> Text(entity.i.toString),
 *       "other" -> entity.other.bind(otherTemplate)
 *     )
 *   }
 *
 * }
 * 
 * object myOtherClassBinding extends DataBinding[MyOtherClass] {
 *   override def apply(other: MyOtherClass) = (xhtml: NodeSeq) => {
 *     bind("other", xhtml, "foo" -> Text("%" + other.foo + "%"))
 *   }
 * }
 *
 * object MyClassConcreteBinding extends MyClassBinding {
 *   override val otherBinding = myOtherClassBinding
 * }
 * </pre>
 *
 * In this example, two classes and their associated bindings are constructed;
 * the first binding for MyClass is abstract, needing a specific instance of
 * DataBinding[MyOtherClass] to enable the implicit conversion needed to render
 * the contained MyOtherClass instance. A subtemplate is selected, and the
 * call to other.bind both necessitates the implicit conversion to a Bindings.Binder
 * instance and applies the appropriate formatting. You can see how this
 * usage keeps the concerns of the view and the model nicely separated, while
 * allowing composition over object graphs.
 *
 * Please see the tests, as well as <a href="http://logji.blogspot.com/2009/09/composable-bindings-in-lift.html">this blog post for additional details.
 */
object Bindings {
    type Binding = NodeSeq => NodeSeq

    type DataBinding[T] = T => NodeSeq => NodeSeq

    /**
     * Implicitly convert the specified object to a binder for that object if a DataBinding for
     * that object's type is available in implicit scope. This essentially adds a bind() method 
     * to an object if an appropriate implicit DataBinding is available.
     */
    implicit def binder[T](t: T)(implicit binding: DataBinding[T]): Binder = Binder(binding(t))

    /**
     * Wrap the specified Binding (a function from NodeSeq => NodeSeq) in a Binder so that
     * it can be applied using Binder's bind methods.
     */
    implicit def binder(binding: Binding): Binder = Binder(binding)

    /**
     * A decorator for a binding function that allows it to be called as bind() rather than apply().
     * This class also provides facilities for binding to a specific template
     */
    case class Binder(val binding: Binding) {
        /**
         * Apply this binder's binding function to the specified NodeSeq.
         */
        def bind(xhtml: NodeSeq): NodeSeq = binding.apply(xhtml)

        /**
         * Apply this binder's binding function to the specified templated
         * looked up using Templates.apply
         */
        def bind(templatePath: List[String]): NodeSeq = {
            Templates(templatePath) map binding match {
                case Full(xhtml) => xhtml
                case Failure(msg, ex, _) if Props.mode == Props.RunModes.Development => Text(ex.map(_.getMessage).openOr(msg))
                case Empty if Props.mode == Props.RunModes.Development => Text("Unable to find template with path " + templatePath.mkString("/", "/", ""))
                case _ => NodeSeq.Empty
            }
        }
    }

    /**
     * Bind any input value to the empty NodeSeq.
     */
    object EmptyBinding extends Binding {
        override def apply(xhtml : NodeSeq) : NodeSeq = NodeSeq.Empty
    }
}

Other Lift Framework examples (source code examples)

Here is a short list of links related to this Lift Framework Bindings.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.