Permalink
Browse files

Started to merge in 210

  • Loading branch information...
2 parents c955de1 + 3e95960 commit 7bebed64f8e5b5bc4a24d8792e09322311f055fc @hjast hjast committed Nov 4, 2012
Showing with 320 additions and 83 deletions.
  1. +13 −10 core/util/src/main/scala/net/liftweb/util/SoftReferenceCache.scala
  2. +6 −6 core/util/src/main/scala/net/liftweb/util/TimeHelpers.scala
  3. +28 −0 core/util/src/test/scala/net/liftweb/util/SoftReferenceCacheSpec.scala
  4. +1 −0 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/MongoRecord.scala
  5. +16 −11 persistence/mongodb-record/src/main/scala/net/liftweb/mongodb/record/field/JObjectField.scala
  6. +9 −0 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/Fixtures.scala
  7. +22 −0 persistence/mongodb-record/src/test/scala/net/liftweb/mongodb/record/MongoFieldSpec.scala
  8. +4 −6 persistence/record/src/main/scala/net/liftweb/record/ProtoUser.scala
  9. +9 −5 persistence/record/src/main/scala/net/liftweb/record/field/DateTimeField.scala
  10. +4 −2 persistence/record/src/main/scala/net/liftweb/record/field/EmailField.scala
  11. +13 −8 persistence/record/src/main/scala/net/liftweb/record/field/PostalCodeField.scala
  12. +65 −2 persistence/record/src/test/scala/net/liftweb/record/FieldSpec.scala
  13. +21 −6 persistence/record/src/test/scala/net/liftweb/record/Fixtures.scala
  14. +3 −2 project/Dependencies.scala
  15. +3 −8 web/webkit/src/main/scala/net/liftweb/http/LiftServlet.scala
  16. +7 −10 web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala
  17. +9 −1 web/webkit/src/main/scala/net/liftweb/http/S.scala
  18. +18 −3 web/webkit/src/main/scala/net/liftweb/http/SHtml.scala
  19. +1 −1 web/webkit/src/main/scala/net/liftweb/http/js/ScriptRenderer.scala
  20. +2 −2 web/webkit/src/main/scala/net/liftweb/sitemap/Menu.scala
  21. +66 −0 web/webkit/src/test/scala/net/liftweb/http/HtmlPropertiesSpec.scala
@@ -119,27 +119,30 @@ class SoftReferenceCache[K, V](cacheSize: Int) {
* @return Box[V]
*/
def apply(key: K): Box[V] = {
- val (doRemove:Boolean, retval:Box[V]) =
+ val result:(Boolean,Box[V]) /* (doRemove, retval) */ =
lock(readLock) {
Box.!!(cache.get(key)) match {
case Full(value) =>
- Box.!!(value.get).map((false, _)) openOr {
+ Box.!!(value.get).map(value => (false, Full(value))) openOr {
(true, Empty)
}
case _ => (false, Empty)
}
}
- if (doRemove) {
- lock(writeLock) {
- val value = cache.get(key)
+ result match {
+ case (doRemove, retval) if doRemove =>
+ lock(writeLock) {
+ val value = cache.get(key)
- if (value != null && value.get == null)
- remove(key)
- }
- }
+ if (value != null && value.get == null)
+ remove(key)
+ }
- retval
+ retval
+ case (_, retval) =>
+ retval
+ }
}
/**
@@ -89,7 +89,7 @@ trait TimeHelpers { self: ControlHelpers =>
class TimeSpan(private val dt: Either[DateTime, Period]) extends ConvertableToDate {
/** @return a Date as the amount of time represented by the TimeSpan after the Epoch date */
- def this(ms: Long) =
+ def this(ms: Long) =
this(if (ms < 52L * 7L * 24L * 60L * 60L * 1000L) Right(new Period(ms))
else Left(new DateTime(ms)))
@@ -102,7 +102,7 @@ trait TimeHelpers { self: ControlHelpers =>
* Convert to a Date
*/
def toDate: Date = date
-
+
/**
* Convert to a JodaTime DateTime
*/
@@ -117,7 +117,7 @@ trait TimeHelpers { self: ControlHelpers =>
case Left(datetime) => datetime.getMillis()
case Right(duration) => duration.toStandardDuration.getMillis()
}
-
+
/** @return a Date as the amount of time represented by the TimeSpan after now */
def later: TimeSpan = dt match {
@@ -397,12 +397,12 @@ trait TimeHelpers { self: ControlHelpers =>
ret
}
- /** @return a date from a string using the internet format. Return the Epoch date if the parse is unsuccesfull */
+ /** @return a Box[date] from a string using the internet format. */
def boxParseInternetDate(dateString: String): Box[Date] = tryo {
internetDateFormatter.parse(dateString)
}
- /** @return a date from a string using the internet format. Return the Epoch date if the parse is unsuccesfull */
+ /** @return a date from a string using the internet format. Return the Epoch date if the parse is unsuccesful */
def parseInternetDate(dateString: String): Date = tryo {
internetDateFormatter.parse(dateString)
} openOr new Date(0L)
@@ -447,6 +447,6 @@ object ConvertableToDate {
implicit def toDate(in: ConvertableToDate): Date = in.toDate
implicit def toDateTime(in: ConvertableToDate): DateTime = in.toDateTime
implicit def toMillis(in: ConvertableToDate): Long = in.millis
-
+
}
@@ -0,0 +1,28 @@
+package net.liftweb.util
+
+import org.specs2.mutable._
+import net.liftweb.common._
+import org.specs2.specification.AroundExample
+
+object SoftReferenceCacheSpec extends Specification {
+
+ sequential
+
+ object cache extends SoftReferenceCache[String, String](1)
+
+ "SoftReferenceCache " should {
+ "Accept additions" in {
+ cache += ("test" -> "test")
+ cache.keys.size() must_== 1
+ }
+ "Allow objects to be retrieved" in {
+ val cached = cache("test")
+ cached must beLike { case Full("test") => ok }
+ }
+ "Properly age out entries" in {
+ cache += ("test2" -> "test2")
+ cache("test") must_== Empty
+ }
+ }
+
+}
@@ -96,6 +96,7 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends BsonRecord[MyType] {
/**
* Mix this into a Record to add an ObjectIdField
*/
+@deprecated("Use one of the MongoPK traits instead", "2.5")
trait MongoId[OwnerType <: MongoRecord[OwnerType]] {
self: OwnerType =>
@@ -19,23 +19,28 @@ package mongodb
package record
package field
-import common.{Box, Empty, Failure, Full}
-import http.js.JE.Str
-import json.JsonAST.{JNothing, JObject, JValue}
-import json.JsonParser
-import net.liftweb.record.{Field, MandatoryTypedField, Record}
+import common._
+import http.js.JE._
+import json._
+import util.Helpers.tryo
+import net.liftweb.record.{Field, FieldHelpers, MandatoryTypedField, Record}
import scala.xml.NodeSeq
class JObjectField[OwnerType <: Record[OwnerType]](rec: OwnerType) extends Field[JObject, OwnerType] with MandatoryTypedField[JObject] {
- def asJs = Str(toString)
-
- def asJValue = (JNothing: JValue) // not implemented
+ def asJs = asJValue match {
+ case JNothing => JsNull
+ case jv => JsRaw(compact(render(jv)))
+ }
- def setFromJValue(jvalue: JValue) = Empty // not implemented
+ def asJValue = valueBox openOr (JNothing: JValue)
- def asXHtml = <div></div>
+ def setFromJValue(jvalue: JValue): Box[JObject] = jvalue match {
+ case JNothing|JNull if optional_? => setBox(Empty)
+ case jo: JObject => setBox(Full(jo))
+ case other => setBox(FieldHelpers.expectedA("JObject", other))
+ }
def defaultValue = JObject(List())
@@ -54,7 +59,7 @@ class JObjectField[OwnerType <: Record[OwnerType]](rec: OwnerType) extends Field
// assume string is json
def setFromString(in: String): Box[JObject] = {
// use lift-json to parse string into a JObject
- Full(set(JsonParser.parse(in).asInstanceOf[JObject]))
+ setBox(tryo(JsonParser.parse(in).asInstanceOf[JObject]))
}
def toForm: Box[NodeSeq] = Empty
@@ -485,3 +485,12 @@ class RefFieldTestRecord private () extends MongoRecord[RefFieldTestRecord] with
object RefFieldTestRecord extends RefFieldTestRecord with MongoMetaRecord[RefFieldTestRecord] {
override def formats = allFormats
}
+
+
+class JObjectFieldTestRecord private () extends Record[JObjectFieldTestRecord] {
+ def meta = JObjectFieldTestRecord
+
+ object mandatoryJObjectField extends JObjectField(this)
+}
+
+object JObjectFieldTestRecord extends JObjectFieldTestRecord with MetaRecord[JObjectFieldTestRecord]
@@ -473,5 +473,27 @@ object MongoFieldSpec extends Specification with MongoTestKit with AroundExample
)
}
}
+
+ "JObjectField" should {
+ val jo: JValue = ("minutes" -> 59)
+ val json: JObject = ("mandatoryJObjectField" -> jo)
+
+ "convert to JValue" in {
+ val rec = JObjectFieldTestRecord.createRecord
+ .mandatoryJObjectField(json)
+
+ rec.mandatoryJObjectField.asJValue must_== json
+
+ }
+ "get set from JValue" in {
+ val fromJson = JObjectFieldTestRecord.fromJValue(json)
+
+ fromJson.isDefined must_== true
+ fromJson foreach { r =>
+ r.asJValue must_== json
+ }
+ success
+ }
+ }
}
@@ -33,8 +33,7 @@ import net.liftweb.record.field._
import net.liftweb.proto.{ProtoUser => GenProtoUser}
/**
- * ProtoUser is a base class that gives you a "User" that has a first name,
- * last name, email, etc.
+ * ProtoUser provides a "User" with a first name, last name, email, etc.
*/
trait ProtoUser[T <: ProtoUser[T]] extends Record[T] {
self: T =>
@@ -177,7 +176,7 @@ trait ProtoUser[T <: ProtoUser[T]] extends Record[T] {
}
/**
- * Mix this trait into the the Mapper singleton for User and you
+ * Mix this trait into the Mapper singleton for User and you
* get a bunch of user functionality including password reset, etc.
*/
trait MetaMegaProtoUser[ModelType <: MegaProtoUser[ModelType]] extends MetaRecord[ModelType] with GenProtoUser {
@@ -203,7 +202,7 @@ trait MetaMegaProtoUser[ModelType <: MegaProtoUser[ModelType]] extends MetaRecor
def displayHtml: NodeSeq = from.displayHtml
/**
- * Does this represent a pointer to a Password field
+ * Does this represent a pointer to a Password field?
*/
def isPasswordField_? : Boolean = from match {
case a: PasswordField[_] => true
@@ -366,7 +365,7 @@ trait MegaProtoUser[T <: MegaProtoUser[T]] extends ProtoUser[T] {
}
/**
- * The has the user been validated.
+ * Whether the user has been validated.
* You can override the behavior
* of this field:
* <pre name="code" class="scala">
@@ -427,4 +426,3 @@ trait MegaProtoUser[T <: MegaProtoUser[T]] extends ProtoUser[T] {
def localeDisplayName = S.?("locale")
}
-
@@ -1,5 +1,5 @@
/*
- * Copyright 2007-2011 WorldWide Conferencing, LLC
+ * Copyright 2007-2012 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.
@@ -22,7 +22,7 @@ import scala.xml._
import net.liftweb.common._
import net.liftweb.http.{S}
import net.liftweb.http.js._
-import net.liftweb.json.JsonAST.JValue
+import net.liftweb.json._
import net.liftweb.util._
import java.util.{Calendar, Date}
import Helpers._
@@ -36,6 +36,10 @@ trait DateTimeTypedField extends TypedField[Calendar] {
cal
}
+ val formats = new DefaultFormats {
+ override def dateFormatter = Helpers.internetDateFormatter
+ }
+
def setFromAny(in : Any): Box[Calendar] = toDate(in).flatMap(d => setBox(Full(dateToCal(d)))) or genericSetFromAny(in)
def setFromString(s: String): Box[Calendar] = s match {
@@ -57,11 +61,11 @@ trait DateTimeTypedField extends TypedField[Calendar] {
case _ => Full(elem)
}
- def asJs = valueBox.map(v => Str(toInternetDate(v.getTime))) openOr JsNull
+ def asJs = valueBox.map(v => Str(formats.dateFormat.format(v.getTime))) openOr JsNull
- def asJValue = asJString(v => toInternetDate(v.getTime))
+ def asJValue = asJString(v => formats.dateFormat.format(v.getTime))
def setFromJValue(jvalue: JValue) = setFromJString(jvalue) {
- v => boxParseInternetDate(v).map(d => {
+ v => formats.dateFormat.parse(v).map(d => {
val cal = Calendar.getInstance
cal.setTime(d)
cal
@@ -34,14 +34,16 @@ object EmailField {
}
trait EmailTypedField extends TypedField[String] {
- private def validateEmail(emailValue: ValueType): List[FieldError] =
+ private def validateEmail(emailValue: ValueType): List[FieldError] = {
toBoxMyType(emailValue) match {
+ case Full(email) if (optional_? && email.isEmpty) => Nil
case Full(email) if EmailField.validEmailAddr_?(email) => Nil
case _ => Text(S.?("invalid.email.address"))
}
+ }
override def validations = validateEmail _ :: Nil
-}
+}
class EmailField[OwnerType <: Record[OwnerType]](rec: OwnerType, maxLength: Int)
extends StringField[OwnerType](rec, maxLength) with EmailTypedField
@@ -29,21 +29,26 @@ import S._
trait PostalCodeTypedField extends StringTypedField {
-
+
protected val country: CountryField[_]
override def setFilter = toUpper _ :: trim _ :: super.setFilter
override def validations = validatePostalCode _ :: Nil
- def validatePostalCode(in: ValueType): List[FieldError] = country.value match {
- case Countries.USA => valRegex(RegexPattern.compile("[0-9]{5}(\\-[0-9]{4})?"), S.?("invalid.zip.code"))(in)
- case Countries.Sweden => valRegex(RegexPattern.compile("[0-9]{3}[ ]?[0-9]{2}"), S.?("invalid.postal.code"))(in)
- case Countries.Australia => valRegex(RegexPattern.compile("(0?|[1-9])[0-9]{3}"), S.?("invalid.postal.code"))(in)
- case Countries.Canada => valRegex(RegexPattern.compile("[A-Z][0-9][A-Z][ ][0-9][A-Z][0-9]"), S.?("invalid.postal.code"))(in)
- case _ => genericCheck(in)
+ def validatePostalCode(in: ValueType): List[FieldError] = {
+ toBoxMyType(in) match {
+ case Full(zip) if (optional_? && zip.isEmpty) => Nil
+ case _ =>
+ country.value match {
+ case Countries.USA => valRegex(RegexPattern.compile("[0-9]{5}(\\-[0-9]{4})?"), S.?("invalid.zip.code"))(in)
+ case Countries.Sweden => valRegex(RegexPattern.compile("[0-9]{3}[ ]?[0-9]{2}"), S.?("invalid.postal.code"))(in)
+ case Countries.Australia => valRegex(RegexPattern.compile("(0?|[1-9])[0-9]{3}"), S.?("invalid.postal.code"))(in)
+ case Countries.Canada => valRegex(RegexPattern.compile("[A-Z][0-9][A-Z][ ][0-9][A-Z][0-9]"), S.?("invalid.postal.code"))(in)
+ case _ => genericCheck(in)
+ }
+ }
}
-
private def genericCheck(zip: ValueType): List[FieldError] = {
toBoxMyType(zip) flatMap {
case null => Full(Text(S.?("invalid.postal.code")))
Oops, something went wrong.

0 comments on commit 7bebed6

Please sign in to comment.