GRValidation 是 Swift 2 的验证工具集。
它允许您验证简单的值和复杂模型,当验证超出简单领域时,它也不会让您失望。
2015年8月25日:GRValidation 0.2.0 发布 - 发布说明。关注 Twitter 上的 @groue 获取发布公告和使用提示。
目前缺少的功能
GRValidation 区分了 值验证 和 模型验证。
精确地说,值验证 抛出错误,如“12 应该大于 18”,负责以下操作:
模型验证则相反,抛出错误,如“年龄应该大于 18”。它在值验证之上构建并提供
ValidationType 是一种协议,用于检查类型为 TestedType 的值,并最终返回类型为 ValidType 的值,或者在抛出 ValidationError
public protocol ValidationType {
typealias TestedType
typealias ValidType
func validate(value: TestedType) throws -> ValidType
}
例如
// Positive integer
let v = ValidationRange(minimum: 0)
try v.validate(1) // OK: 1
try v.validate(nil) // ValidationError: nil should be greater than or equal to 0.
try v.validate(-1) // ValidationError: -1 should be greater than or equal to 0.
返回的值可能与输入不同
enum Color : Int {
case Red
case White
case Rose
}
let v = ValidationRawValue<Color>()
try v.validate(0) // OK: Color.Red
try v.validate(3) // ValidationError: 3 is an invalid Color.
validate() 方法可能抛出 ValidationError
let positiveInt = ValidationRange(minimum: 0)
try positiveInt.validate(-1) // Throws a ValidationError
您还可以使用 ~=
运算符或通过模式匹配执行简单的布尔检查
positiveInt ~= 10 // true
positiveInt ~= -1 // false
switch int {
case positiveInt:
// int passes validation
...
}
验证类型 | TestedType | ValidType | |
---|---|---|---|
验证 | T | T | 所有值都通过。 |
ValidationFailure | T | T | 所有值都失败。 |
ValidationNil | T? | T? | 检查输入是否为 nil。 |
ValidationNotNil | T? | T | 检查输入是否不为 nil。 |
ValidationTrim | String? | String? | 所有字符串都通过。非 nil 字符串将被修剪。 |
ValidationStringLength | String? | String | 检查字符串不为 nil 且长度在特定范围内。 |
ValidationRegularExpression | String? | String | 检查字符串不为 nil 并匹配正则表达式。 |
ValidationCollectionNotEmpty | CollectionType? | CollectionType | 检查集合不为 nil 且不为空。 |
ValidationCollectionEmpty | CollectionType? | CollectionType? | 检查集合为 nil 或为空。 |
ValidationEqual | T? where T:Equatable | T | 检查值不为 nil 且等于引用值。 |
ValidationNotEqual | T? where T:Equatable | T? | 检查值是 nil 或不等于引用值。 |
ValidationElementOf | T? where T:Equatable | T | 检查值不为 nil 并且是引用集合的成员。 |
ValidationNotElementOf | T? where T:Equatable | T? | 检查值是 nil 或不是引用集合的成员。 |
ValidationRawValue | T.RawValue? where T: RawRepresentable | T | 检查值不为 nil 并且是类型 T 的有效原始值。 |
ValidationRange | T? where T: ForwardIndexType, T: Comparable | T | 检查值不为 nil 并且在特定范围内。 |
基本值验证可以链式连接,或使用布尔运算符组合
v1 >>> v2
连接两个验证。返回 v2 返回的值。
// Checks that a string matches a regular expression, after trimming:
let v = ValidationTrim() >>> ValidationRegularExpression(pattern: "^[0-9]+$")
try v.validate(" 123 ") // "123"
try v.validate("foo") // ValidationError
v1 || v2
检查值通过至少一个验证。返回第一个通过验证的值返回的值,或者在输出类型不匹配时返回输入值。
// Checks that an Int is not nil and equal to 1 or 2:
let v = ValidationEqual(1) || ValidationEqual(2)
try v.validate(1) // 1
try v.validate(2) // 2
try v.validate(3) // ValidationError
v1 && v2
检查值通过两个验证。返回 v2 返回的值。
// Checks that an Int is nil, or not 1, and not 2:
let v = ValidationNotEqual(1) && ValidationNotEqual(2)
try v.validate(1) // ValidationError
try v.validate(2) // ValidationError
try v.validate(3) // 3
!v1
反转验证。返回输入值,或者抛出一个通用的“is invalid.”错误。
// Checks that an Int is not 1.
let v = !ValidationEqual(1)
try v.validate(1) // ValidationError
try v.validate(2) // 2
The Validable 协议提供了帮助验证模型的方法。
让我们从一个简单的模型开始
struct Person: Validable {
var name: String?
func validate() throws {
// Name should not be nil or empty.
try validate(property: "name", with: name >>> ValidationStringLength(minimum: 1))
}
}
let person = Person(name: "Arthur")
try person.validate() // OK
let person = Person(name: nil)
try person.validate()
// Invalid Person(name: nil): name should not be empty.
请随意,不要犹豫构建更复杂的验证
struct Person : Validable {
var name: String?
var age: Int?
var email: String?
var phoneNumber: String?
mutating func validate() throws {
// ValidationPlan doesn't fail on the first validation error. Instead,
// it gathers all of them, and eventually throws a single ValidationError.
try ValidationPlan()
.append {
// Name should not be empty after whitespace trimming:
let nameValidation = ValidationTrim() >>> ValidationStringLength(minimum: 1)
name = try validate(
property: "name",
with: name >>> nameValidation)
}
.append {
// Age should be nil, or positive:
let ageValidation = ValidationNil() || ValidationRange(minimum: 0)
try validate(
property: "age",
with: age >>> ageValidation)
}
.append {
// Email should be nil, or contain @ after whitespace trimming:
let emailValidation = ValidationNil() || (ValidationTrim() >>> ValidationRegularExpression(pattern:"@"))
email = try validate(
property: "email",
with: email >>> emailValidation)
}
.append {
// Phone number should be nil, or be a valid phone number.
// ValidationPhoneNumber applies international formatting.
let phoneNumberValidation = ValidationNil() || (ValidationTrim() >>> ValidationPhoneNumber(format: .International))
phoneNumber = try validate(
property: "phoneNumber",
with: phoneNumber >>> phoneNumberValidation)
}
.append {
// An email or a phone number is required.
try validate(
properties: ["email", "phoneNumber"],
message: "Please provide an email or a phone number.",
with: email >>> ValidationNotNil() || phoneNumber >>> ValidationNotNil())
}
.validate()
}
}
var person = Person(name: " Arthur ", age: 35, email: nil, phoneNumber: "0123456789 ")
try person.validate() // OK
person.name // "Arthur" (trimmed)
person.phoneNumber // "+33 1 23 45 67 89" (trimmed & formatted)
var person = Person(name: nil, age: nil, email: "[email protected]", phoneNumber: nil)
try person.validate()
// Invalid Person: name should not be empty.
var person = Person(name: "Arthur", age: -1, email: "[email protected]", phoneNumber: nil)
try person.validate()
// Invalid Person: age should be greater than or equal to 0.
var person = Person(name: "Arthur", age: 35, email: nil, phoneNumber: nil)
try person.validate()
// Invalid Person: Please provide an email or a phone number.
var person = Person(name: "Arthur", age: 35, email: "foo", phoneNumber: nil)
try person.validate()
// Invalid Person: email is invalid.