/scalate-core/src/main/scala/org/fusesource/scalate/scuery/support/Rule.scala

http://github.com/scalate/scalate · Scala · 117 lines · 70 code · 18 blank · 29 comment · 6 complexity · 97e6c5ce8d48c86b63f347327e9ca52a MD5 · raw file

  1. /**
  2. * Copyright (C) 2009-2011 the original author or authors.
  3. * See the notice.md file distributed with this work for additional
  4. * information regarding copyright ownership.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.fusesource.scalate.scuery.support
  19. import xml.{ Elem, Node, NodeSeq }
  20. import org.fusesource.scalate.scuery.XmlHelper._
  21. import org.fusesource.scalate.util.Log
  22. object Rule extends Log {
  23. /**
  24. * Combines multiple rules to a single rule
  25. */
  26. def apply(a: Rule, b: Rule): Rule = {
  27. if (a.order <= b.order) {
  28. CompositeRule(a, b)
  29. } else {
  30. CompositeRule(b, a)
  31. }
  32. }
  33. def apply(rules: Iterator[Rule]): Rule = apply(rules.toSeq)
  34. def apply(rules: Seq[Rule]): Rule = {
  35. if (rules.size < 2) {
  36. rules(0)
  37. } else {
  38. val list = rules.sortWith(_.order < _.order)
  39. list.tail.foldLeft(list.head)(Rule(_, _))
  40. }
  41. }
  42. }
  43. import Rule._
  44. /**
  45. * Represents manipuluation rules
  46. *
  47. * @version $Revision : 1.1 $
  48. */
  49. trait Rule {
  50. def apply(node: Node): NodeSeq
  51. /**
  52. * Lets do simple rules first (like setting attributes, removing attributes), then changing contents
  53. * then finally completely transforming the node last
  54. */
  55. def order: Int = 0
  56. }
  57. case class CompositeRule(first: Rule, second: Rule) extends Rule {
  58. def apply(node: Node) = {
  59. first(node).flatMap { second(_) }
  60. }
  61. def toList: List[Rule] = toList(first) ::: toList(second)
  62. protected def toList(rule: Rule): List[Rule] = rule match {
  63. case c: CompositeRule => c.toList
  64. case _ => rule :: Nil
  65. }
  66. }
  67. case class ReplaceRule(fn: Node => NodeSeq) extends Rule {
  68. def apply(node: Node) = fn(node)
  69. override def order: Int = 100
  70. }
  71. case class ReplaceContentRule(fn: Node => NodeSeq) extends Rule {
  72. def apply(node: Node) = node match {
  73. case e: Elem =>
  74. val contents = fn(e)
  75. debug("Replacing content = " + contents)
  76. replaceContent(e, contents)
  77. case n => n
  78. }
  79. }
  80. case class SetAttributeRule(name: String, fn: (Node) => String) extends Rule {
  81. def apply(node: Node) = node match {
  82. case e: Elem =>
  83. val value = fn(e)
  84. debug("Setting attribute %s to %s", name, value)
  85. setAttribute(e, name, value)
  86. case n => n
  87. }
  88. override def order = -1
  89. }
  90. case class SetSelectiveAttributeRule(name: String, fn: (Node) => String) extends Rule {
  91. def apply(node: Node) = node match {
  92. case e: Elem =>
  93. val value = fn(e)
  94. debug("Selectively setting attribute %s to %s", name, value)
  95. if (e.attribute(name).isDefined) setAttribute(e, name, value) else e
  96. case n => n
  97. }
  98. override def order = -1
  99. }