Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

util: #> and replaceWith use new CanBind type class

  • Loading branch information...
commit 2b1d349bca29604cb1079e67df9ac8bea68316a8 1 parent fdf9caa
@nafg nafg authored
View
6 core/util/src/main/scala/net/liftweb/util/BindHelpers.scala
@@ -692,7 +692,8 @@ trait BindHelpers {
* Remove all the <head> tags, just leaving the child tags
*/
def stripHead(in: NodeSeq): NodeSeq = {
- ("head" #> ((ns: NodeSeq) => ns.asInstanceOf[Elem].child))(in)
+ "head" #> ((ns: NodeSeq) => ns.asInstanceOf[Elem].child) apply in
+ /*
import scala.xml.transform._
val rewrite = new RewriteRule {
@@ -703,6 +704,7 @@ trait BindHelpers {
}
(new RuleTransformer(rewrite)).transform(in)
+ */
}
/**
@@ -710,7 +712,7 @@ trait BindHelpers {
* nodeseq.
*/
def replaceIdNode(in: NodeSeq, id: String, replacement: NodeSeq): NodeSeq = {
- (("#"+id) #> replacement)(in)
+ ("#"+id) #> replacement apply in
/*
import scala.xml.transform._
View
140 core/util/src/main/scala/net/liftweb/util/CssBinding.scala
@@ -25,59 +25,71 @@ import scala.collection.mutable.ListBuffer
/**
- * An intermediate class used to promote a String or a CssSelector to
- * something that can be associated with a value to apply to the selector
+ * A type class that creates CssSel instances for a value of some type
+ * @param apply a function stringSelector => css => x => cssSel. stringSelector and css are the arguments for CssBindImpl's constructor
*/
-final class ToCssBindPromoter(stringSelector: Box[String], css: Box[CssSelector]) {
+class CanBind[-T](val apply: Box[String] => Box[CssSelector] => T => CssSel)
+object CanBind {
/**
* Inserts a String constant according to the CssSelector rules
*/
- def #>(str: String): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] =
- List(if (null eq str) NodeSeq.Empty else Text(str))
- }
-
+ implicit val string = new CanBind[String](stringSelector => css => str =>
+ new CssBindImpl(stringSelector, css) {
+ def calculate(in: NodeSeq): Seq[NodeSeq] =
+ List(if (null eq str) NodeSeq.Empty else Text(str))
+ }
+ )
/**
* Inserts a NodeSeq constant according to the CssSelector rules
*/
- def #>(ns: NodeSeq): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(ns)
- }
+ implicit val nodeSeq = new CanBind[NodeSeq](stringSelector => css => ns =>
+ new CssBindImpl(stringSelector, css) {
+ def calculate(in: NodeSeq): Seq[NodeSeq] = List(ns)
+ }
+ )
/**
* A function that transforms the content according to the CssSelector rules
*/
- def #>(nsFunc: NodeSeq => NodeSeq): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(nsFunc(in))
- }
+ implicit val nodeSeqFunc = new CanBind[NodeSeq=>NodeSeq](stringSelector => css => nsFunc =>
+ new CssBindImpl(stringSelector, css) {
+ def calculate(in: NodeSeq): Seq[NodeSeq] = List(nsFunc(in))
+ }
+ )
/**
* Inserts a Bindable constant according to the CssSelector rules.
* Mapper and Record fields implement Bindable.
*/
- def #>(bindable: Bindable): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(bindable.asHtml)
- }
+ implicit val bindable = new CanBind[Bindable](stringSelector => css => bindable =>
+ new CssBindImpl(stringSelector, css) {
+ def calculate(in: NodeSeq): Seq[NodeSeq] = List(bindable.asHtml)
+ }
+ )
/**
* Inserts a StringPromotable constant according to the CssSelector rules.
* StringPromotable includes Int, Long, Boolean, and Symbol
*/
- def #>(strPromo: StringPromotable): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] =
- List(Text(strPromo.toString))
- }
+ implicit def stringPromotable[T<%StringPromotable] = new CanBind[T](stringSelector => css => strPromo =>
+ new CssBindImpl(stringSelector, css) {
+ def calculate(in: NodeSeq): Seq[NodeSeq] =
+ List(Text(strPromo.toString))
+ }
+ )
/**
* Applies the N constants according to the CssSelector rules.
* This allows for Seq[String], Seq[NodeSeq], Box[String],
* Box[NodeSeq], Option[String], Option[NodeSeq]
*/
- def #>(itrConst: IterableConst): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = itrConst.constList(in)
- }
+ implicit def iterableConst[T<%IterableConst] = new CanBind[T](stringSelector => css => itrConst =>
+ new CssBindImpl(stringSelector, css) {
+ def calculate(in: NodeSeq): Seq[NodeSeq] = itrConst.constList(in)
+ }
+ )
/**
* Apply the function and then apply the results account the the CssSelector
@@ -87,73 +99,26 @@ final class ToCssBindPromoter(stringSelector: Box[String], css: Box[CssSelector]
* NodeSeq => Box[NodeSeq], NodeSeq => Option[String],
* NodeSeq =>Option[NodeSeq]
*/
- def #>(itrFunc: IterableFunc): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = itrFunc(in)
- }
-
- /**
- * Inserts a String constant according to the CssSelector rules
- */
- def replaceWith(str: String): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] =
- List(if (null eq str) NodeSeq.Empty else Text(str))
- }
-
- /**
- * Inserts a NodeSeq constant according to the CssSelector rules
- */
- def replaceWith(ns: NodeSeq): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(ns)
- }
-
- /**
- * A function that transforms the content according to the CssSelector rules
- */
- def replaceWith(nsFunc: NodeSeq => NodeSeq): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(nsFunc(in))
- }
-
- /**
- * Inserts a Bindable constant according to the CssSelector rules.
- * Mapper and Record fields implement Bindable.
- */
- def replaceWith(bindable: Bindable): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = List(bindable.asHtml)
- }
-
- /**
- * Inserts a StringPromotable constant according to the CssSelector rules.
- * StringPromotable includes Int, Long, Boolean, and Symbol
- */
- def replaceWith(strPromo: StringPromotable): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = strPromo.toString match {
- case null => NodeSeq.Empty
- case str => List(Text(str))
+ implicit def iterableFunc[T<%IterableFunc] = new CanBind[T](stringSelector => css => itrFunc =>
+ new CssBindImpl(stringSelector, css) {
+ def calculate(in: NodeSeq): Seq[NodeSeq] = itrFunc(in)
}
- }
+ )
+}
- /**
- * Applies the N constants according to the CssSelector rules.
- * This allows for Seq[String], Seq[NodeSeq], Box[String],
- * Box[NodeSeq], Option[String], Option[NodeSeq]
- */
- def replaceWith(itrConst: IterableConst): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = itrConst.constList(in)
- }
- /**
- * Apply the function and then apply the results account the the CssSelector
- * rules.
- * This allows for NodeSeq => Seq[String], NodeSeq =>Seq[NodeSeq],
- * NodeSeq => Box[String],
- * NodeSeq => Box[NodeSeq], NodeSeq => Option[String],
- * NodeSeq =>Option[NodeSeq]
- */
- def replaceWith(itrFunc: IterableFunc): CssSel = new CssBindImpl(stringSelector, css) {
- def calculate(in: NodeSeq): Seq[NodeSeq] = itrFunc(in)
- }
+/**
+ * An intermediate class used to promote a String or a CssSelector to
+ * something that can be associated with a value to apply to the selector
+ * @param stringSelector the unparsed css selector string
+ * @param css the parsed CssSelector object
+ */
+final class ToCssBindPromoter(stringSelector: Box[String], css: Box[CssSelector]) {
+ def #>[T](v: T)(implicit canBind: CanBind[T]): CssSel = canBind.apply(stringSelector)(css)(v)
+ def replaceWith[T: CanBind](v: T): CssSel = #>[T](v)
}
+
/**
* A trait that has some helpful implicit conversions from
* Iterable[NodeSeq], Seq[String], Box[String], and Option[String]
@@ -999,8 +964,7 @@ sealed trait CssBind extends CssSel {
def stringSelector: Box[String]
def css: Box[CssSelector]
- override def toString(): String = "CssBind("+stringSelector+", "+
- css+")"
+ override def toString(): String = "CssBind("+stringSelector+", "+css+")"
def apply(in: NodeSeq): NodeSeq = css match {
case Full(c) => selectorMap(in)
View
32 core/util/src/test/scala/net/liftweb/util/BindHelpersSpec.scala
@@ -354,7 +354,7 @@ object CssBindHelpersSpec extends Specification {
}
"substitute a String by id" in {
- ("#foo" #> "hello")(<b><span id="foo"/></b>) must ==/ (<b>hello</b>)
+ ("#foo" #> "hello") apply (<b><span id="foo"/></b>) must ==/ (<b>hello</b>)
}
@@ -430,11 +430,11 @@ object CssBindHelpersSpec extends Specification {
}
"substitute a String by id" in {
- ("#foo" replaceWith "hello")(<b><span id="foo"/></b>) must ==/ (<b>hello</b>)
+ ("#foo" replaceWith "hello") apply (<b><span id="foo"/></b>) must ==/ (<b>hello</b>)
}
"Select a node" in {
- ("#foo ^^" #> "hello")(<div><span id="foo"/></div>) must ==/ (<span id="foo"/>)
+ ("#foo ^^" #> "hello") apply (<div><span id="foo"/></div>) must ==/ (<span id="foo"/>)
}
"Another nested select" in {
@@ -559,19 +559,19 @@ object CssBindHelpersSpec extends Specification {
"option transform on *" in {
val opt: Option[String] = None
- val res = ("* *" #> opt.map(ignore => "Dog"))(<top>cat</top>)
+ val res = ("* *" #> opt.map(ignore => "Dog")) apply (<top>cat</top>)
res.head must_== <top></top>
}
"append attribute to a class with spaces" in {
val stuff = List("a", "b")
- val res = ("* [class+]" #> stuff)(<top class="q">cat</top>)
+ val res = ("* [class+]" #> stuff) apply (<top class="q">cat</top>)
(res \ "@class").text must_== "q a b"
}
"append attribute to an href" in {
val stuff = List("&a=b", "&b=d")
- val res = ("* [href+]" #> stuff)(<top href="q?z=r">cat</top>)
+ val res = ("* [href+]" #> stuff) apply (<top href="q?z=r">cat</top>)
(res \ "@href").text must_== "q?z=r&a=b&b=d"
}
@@ -614,47 +614,47 @@ object CssBindHelpersSpec extends Specification {
"option transform on *" in {
val opt: Option[Int] = Full(44)
- val res = ("* *" #> opt.map(ignore => "Dog"))(<top>cat</top>)
+ val res = "* *" #> opt.map(ignore => "Dog") apply <top>cat</top>
res must ==/ (<top>Dog</top>)
}
"option transform on *" in {
val opt: Box[String] = Empty
- val res = ("* *" #> opt.map(ignore => "Dog"))(<top>cat</top>)
+ val res = "* *" #> opt.map(ignore => "Dog") apply <top>cat</top>
res.head must_== <top></top>
}
"option transform on *" in {
val opt: Box[Int] = Some(44)
- val res = ("* *" #> opt.map(ignore => "Dog"))(<top>cat</top>)
+ val res = "* *" #> opt.map(ignore => "Dog") apply <top>cat</top>
res must ==/ (<top>Dog</top>)
}
"transform on *" in {
- val res = ("* *" #> "Dog")(<top>cat</top>)
+ val res = "* *" #> "Dog" apply <top>cat</top>
res must ==/ (<top>Dog</top>)
}
"transform child content on *+" in {
- val res = ("* *+" #> "moose")(<a>I like </a>)
+ val res = "* *+" #> "moose" apply <a>I like </a>
res.text must_== "I like moose"
}
"transform child content on -*" in {
- val res = ("* -*" #> "moose")(<a> I like</a>)
+ val res = "* -*" #> "moose" apply <a> I like</a>
res.text must_== "moose I like"
}
"transform on li" in {
- val res = ("li *" #> List("Woof", "Bark") & ClearClearable)(
- <ul><li>meow</li><li class="clearable">a</li><li class="clearable">a</li></ul>)
+ val res = "li *" #> List("Woof", "Bark") & ClearClearable apply
+ <ul><li>meow</li><li class="clearable">a</li><li class="clearable">a</li></ul>
res must ==/ (<ul><li>Woof</li><li>Bark</li></ul>)
}
"substitute multiple Strings by id" in {
- (("#foo" replaceWith "hello") &
- ("#baz" replaceWith "bye"))(<b><div id="baz">Hello</div><span id="foo"/></b>) must ==/ (<b>{Text("bye")}{Text("hello")}</b>)
+ ("#foo" replaceWith "hello") &
+ ("#baz" replaceWith "bye") apply <b><div id="baz">Hello</div><span id="foo"/></b> must ==/ (<b>{Text("bye")}{Text("hello")}</b>)
}
"substitute multiple Strings with a List by id" in {
Please sign in to comment.
Something went wrong with that request. Please try again.