/*
* Copyright 2006-2010 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 util {
import _root_.java.io.{InputStream, ByteArrayOutputStream, ByteArrayInputStream, Reader, File, FileInputStream, BufferedReader, InputStreamReader}
import _root_.scala.xml._
import common._
/**
* This object adds functionality to Scala standard types.
*/
object BasicTypesHelpers extends BasicTypesHelpers with StringHelpers with ControlHelpers
/**
* This trait adds functionality to Scala standard types
*/
trait BasicTypesHelpers { self: StringHelpers with ControlHelpers =>
/**
* Allows an implicit transform from a Boolean to a Boolean2, allowing expressions such as:
* <code>(1 == 2) ? "a" | "b"</code> (This expression will return "b")
* @param b the predicate to be tested by the ternary operator.
*/
implicit def boolean2(b: => Boolean) = new Boolean2(b)
/**
* This decorator class adds a ternary operator to a Boolean value
* @param b the predicate to be tested by the ternary operator.
*/
class Boolean2(b: => Boolean) {
/**
* Ternary operator.
* @returns a BooleanSome containing the specified value
* if the decorated boolean is true, or a BooleanNone otherwise.
*/
def ? [A](first: => A): BooleanOption[A] = {
if (b) BooleanSome(() => first)
else BooleanNone
}
/**
* Class for return values from the Boolean2 ternary operator.
* This class provides the "|" operator that can be used to
* specify a default value (i.e. the RHS of the "or")
*/
sealed abstract class BooleanOption[+A] {
def |[B >: A](default: => B): B
}
/**
* The value returned by the ternary operator if the predicate is true.
*/
case class BooleanSome[+A](x: () => A) extends BooleanOption[A] {
def |[B >: A](default: => B): B = x()
}
/**
* The value returned by the ternary operator if the predicate is false.
*/
case object BooleanNone extends BooleanOption[Nothing] {
def |[B](default: => B): B = default
}
}
/**
* Implicit transformation from a Boolean expression to an OptionalCons object so
* that an element can be added to a list if the expression is true
*/
implicit def toOptiCons(expr: => Boolean): OptionalCons = new OptionalCons(expr)
/**
* promote a partial function such that we can invoke the guard method
* to wrap the guarded partial function with a guard
*/
implicit def pfToGuardable[A](in: PartialFunction[A, _]):
PartialFunctionWrapper[A] =
new PartialFunctionWrapper[A](in)
/**
* Convert any object to an "equivalent" Boolean depending on its value
*/
def toBoolean(in: Any): Boolean = {
in match {
case null => false
case b : Boolean => b
case i: Int => i != 0
case lo: Long => lo != 0
case n : Number => n.intValue != 0
case s : String => {
val sl = s.toLowerCase
if (sl.length == 0) false
else {
if (sl.charAt(0) == 't') true
else if (sl == "yes") true
else toInt(s) != 0
}
}
case None => false
case Empty | Failure(_, _, _) => false
case Full(n) => toBoolean(n)
case Some(n) => toBoolean(n)
case x :: xs => toBoolean(x)
case o => toBoolean(o.toString)
}
}
/**
* A helper that will convert the String to a Boolean if it's
* t, true, yes, 1, f, false, no, or 0
*/
def asBoolean(in: String): Box[Boolean] = AsBoolean.unapply(in)
/**
* A helpful Boolean extractor
*/
object AsBoolean {
def unapply(in: String): Option[Boolean] =
if (null eq in) None else
in.toLowerCase match {
case "t" | "true" | "yes" | "1" => Full(true)
case "f" | "false" | "no" | "0" => Full(false)
case _ => None
}
}
/**
* Safely convert the specified String to an Int.
*/
def asInt(in: String): Box[Int] = tryo{in.trim.toInt}
/**
* A helpful Int extractor
*/
object AsInt {
def unapply(in: String): Option[Int] = asInt(in)
}
/**
* Safely convert the specified String to an Int.
*/
def asDouble(in: String): Box[Double] = tryo{in.trim.toDouble}
/**
* A helpful Int extractor
*/
object AsDouble {
def unapply(in: String): Option[Double] = asDouble(in)
}
/**
* Safely convert the specified String to a Long.
*/
def asLong(in: String): Box[Long] = tryo(in.toLong)
/**
* A helpful Long extractor
*/
object AsLong {
def unapply(in: String): Option[Long] = asLong(in)
}
/**
* Convert any object to an "equivalent" Long depending on its value
*/
def asLong(in: Any): Box[Long] = {
in match {
case null => Empty
case i: Int => Full(i.toLong)
case n: Long => Full(n)
case d: _root_.java.util.Date => Full(d.getTime)
case n : Number => Full(n.longValue)
case (n: Number) :: _ => Full(n.longValue)
case Some(n) => asLong(n)
case Full(n) => asLong(n)
case None | Empty | Failure(_, _, _) => Empty
case s: String => asLong(s)
case x :: xs => asLong(x)
case o => asLong(o.toString)
}
}
/**
* Convert any object to an "equivalent" Int depending on its value
*/
def toInt(in: Any): Int = {
in match {
case null => 0
case n: Int => n
case lo: Long => lo.toInt
case n : Number => n.intValue
case (n: Number) :: _ => n.intValue
case Some(n) => toInt(n)
case Full(n) => toInt(n)
case None | Empty | Failure(_, _, _) => 0
case s: String => parseNumber(s).toInt
case d: _root_.java.util.Date => (d.getTime / 1000L).toInt
case x :: xs => toInt(x)
case o => toInt(o.toString)
}
}
/**
* Convert any object to an "equivalent" Long depending on its value
*/
def toLong(in: Any): Long = {
in match {
case null => 0L
case i: Int => i
case n: Long => n
case d: _root_.java.util.Date => d.getTime
case n : Number => n.longValue
case (n: Number) :: _ => n.longValue
case Some(n) => toLong(n)
case Full(n) => toLong(n)
case None | Empty | Failure(_, _, _) => 0L
case s: String => parseNumber(s)
case x :: xs => toLong(x)
case o => toLong(o.toString)
}
}
/**
* Convert any InputStream to a ByteArrayInputStream
*/
def toByteArrayInputStream(in: InputStream) = {
val ba = new Array[Byte](4096)
val bos = new ByteArrayOutputStream
var len = 0
while (len >= 0) {
len = in.read(ba)
if (len > 0) {
bos.write(ba, 0, len)
}
}
new ByteArrayInputStream(bos.toByteArray)
}
/**
* Compare two arrays of Byte for byte equality.
* @return true if two Byte arrays don't contain the same bytes
*/
def notEq(a: Array[Byte], b: Array[Byte]) = !isEq(a,b)
/**
* Compare two arrays of Byte for byte equality.
* @return true if two Byte arrays contain the same bytes
*/
def isEq(a: Array[Byte], b: Array[Byte]) = {
def eq(a: Array[Byte], b: Array[Byte], pos: Int, len: Int): Boolean = {
if (pos == len) true
else if (a(pos) != b(pos)) false
else eq(a , b, pos + 1, len)
}
a.length == b.length && eq(a, b, 0, a.length)
}
}
/**
* Optional cons that implements the expression: <code>expr ?> value ::: List</code>
* @param expr the predicate to evaluate
*/
final class OptionalCons(expr: => Boolean) {
/**
* Return the specified value in a single-element list if the predicate
* evaluates to true.
*/
def ?>[T](f: => T): List[T] = if (expr) List(f) else Nil
}
/**
* The helper class that facilitates wrapping of one PartialFunction
* around another
*/
final class PartialFunctionWrapper[A](around: PartialFunction[A, _]) {
/**
* Allows you to put a guard around a partial function
* such that the around's isDefinedMethod must return true
* before the other's isDefinedAt method is tested
*/
def guard[B](other: PartialFunction[A, B]): PartialFunction[A,B] =
new PartialFunction[A, B] {
def isDefinedAt(a: A) = around.isDefinedAt(a) && other.isDefinedAt(a)
def apply(a: A): B = other.apply(a)
}
}
}
}