updating readme
This commit is contained in:
parent
e2d88eeca0
commit
1288c10568
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<playground version='3.0' sdk='iphonesimulator'>
|
||||
<sections>
|
||||
<code source-file-name='section-1.swift'/>
|
||||
</sections>
|
||||
<timeline fileName='timeline.xctimeline'/>
|
||||
</playground>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Playground - noun: a place where people can play
|
||||
|
||||
import UIKit
|
||||
|
||||
var str = "Hello, playground"
|
||||
|
||||
var errors[String:Int] = ["This":1, "Is": 2, "A": 3, "Test": 4]
|
||||
|
||||
println(errors.values)
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Timeline
|
||||
version = "3.0">
|
||||
<TimelineItems>
|
||||
</TimelineItems>
|
||||
</Timeline>
|
||||
202
README.md
202
README.md
|
|
@ -1,4 +1,202 @@
|
|||
swift-validator
|
||||
Swift-validator
|
||||
===============
|
||||
|
||||
A rule-based validation library for Swift
|
||||
Swift Validator is a rule-based validation library for Swift.
|
||||
|
||||
Core Concepts
|
||||
|
||||
* ```UITextField``` and ```ValidationRule``` go into the ```Validator```, ```UITextFields``` and ```ValidationErrors``` come out of ```Validator```
|
||||
* ```UITextField``` is registered to ```Validator```
|
||||
* ```Validator``` evaluates ```ValidationRules``` sequentially and stops evaluating when a ```ValidationRule``` fails.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Initialize the ```Validator``` by setting a delegate to a View Controller or other object.
|
||||
|
||||
```swift
|
||||
|
||||
// ViewController.swift
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
var validator = Validator(delegate: self)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Register the fields that you want to validate
|
||||
|
||||
```swift
|
||||
|
||||
var fields:[String] = ["FullName", "Email", "Phone"]
|
||||
|
||||
// Validation Rules are evaluated from left to right. The first rule is ValidationRuleType.Required the second is ValidationRuleType.FullName.
|
||||
validator.registerField(fields[0], textField:nameTextField, rules: [.Required, .FullName])
|
||||
validator.registerField(fields[1], textField:emailTextField, rules: [.Required, .Email])
|
||||
validator.registerField(fields[2], textField:phoneTextField, rules: [.Required, .PhoneNumber])
|
||||
|
||||
```
|
||||
|
||||
Validate Individual Field
|
||||
|
||||
```swift
|
||||
|
||||
func validator.validateFieldBy(fields[0], delegate:self)
|
||||
|
||||
// ValidationFieldDelegate methods
|
||||
func validationFieldSuccess(key:String, validField:UITextField){
|
||||
validField.backgroundColor = UIColor.greenColor()
|
||||
}
|
||||
|
||||
func validationFieldFailure(key:String, error:ValidationError){
|
||||
println(error.error.description)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Validate All Fields
|
||||
|
||||
```swift
|
||||
|
||||
validator.validateAllBy(fields, delegate:self)
|
||||
|
||||
// ValidationDelegate methods
|
||||
|
||||
func validationWasSuccessful(){
|
||||
// submit the form
|
||||
}
|
||||
|
||||
func validationFailed(key:String, errors[String:ValidationError]){
|
||||
// turn the fields to red
|
||||
for error in errors.values {
|
||||
error.textField.backgroundColor = UIColor.redColor()
|
||||
println("error -> \(error.error.description)")
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Custom Validation
|
||||
|
||||
We will create a ```SSNValidation``` class to show how to create your own Validation. A United States Social Security Number (or SSN) is a field that consists of XXX-XX-XXXX.
|
||||
|
||||
Create a class that implements the Validation protocol
|
||||
|
||||
```swift
|
||||
|
||||
class SSNValidation: Validation {
|
||||
let SSN_REGEX = "^\\d{3}-\\d{2}-\\d{4}$"
|
||||
|
||||
func validate(value: String) -> (Bool, ValidationErrorType) {
|
||||
if let ssnTest = NSPredicate(format: "SELF MATCHES %@", SSN_REGEX) {
|
||||
if ssnTest.evaluateWithObject(value) {
|
||||
return (true, .NoError)
|
||||
}
|
||||
return (false, .SocialSecurity) // We will create this later ValidationErrorTYpe
|
||||
}
|
||||
return (false, .SocialSecurity)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Add the ```.SocialSecurity``` ValidationRuleType
|
||||
|
||||
```swift
|
||||
|
||||
enum ValidationRuleType {
|
||||
case Required,
|
||||
Email,
|
||||
Password,
|
||||
MinLength,
|
||||
MaxLength,
|
||||
ZipCode,
|
||||
PhoneNumber,
|
||||
FullName,
|
||||
SocialSecurity // Added to the Rule Types
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Add the ```.SocialSecurity``` ValidationErrorType and description()
|
||||
|
||||
```swift
|
||||
|
||||
enum ValidationErrorType {
|
||||
case Required,
|
||||
Email,
|
||||
Password,
|
||||
MinLength,
|
||||
MaxLength,
|
||||
ZipCode,
|
||||
PhoneNumber,
|
||||
FullName,
|
||||
SocialSecurity, // Added to the Error Types
|
||||
NoError
|
||||
|
||||
func description() -> String {
|
||||
switch self {
|
||||
case .Required:
|
||||
return "Required field"
|
||||
case .Email:
|
||||
return "Must be a valid email"
|
||||
case .MaxLength:
|
||||
return "This field should be less than"
|
||||
case .ZipCode:
|
||||
return "5 digit zipcode"
|
||||
case .PhoneNumber:
|
||||
return "10 digit phone number"
|
||||
case .Password:
|
||||
return "Must be at least 8 characters"
|
||||
case .FullName:
|
||||
return "Provide a first & last name"
|
||||
// Adding the desired error message
|
||||
case .SocialSecurity:
|
||||
return "SSN is XXX-XX-XXXX"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
Register the Validation with the ValidationFactory
|
||||
|
||||
```swift
|
||||
|
||||
class ValidationFactory {
|
||||
class func validationForRule(rule:ValidationRuleType) -> Validation {
|
||||
switch rule {
|
||||
case .Required:
|
||||
return RequiredValidation()
|
||||
case .Email:
|
||||
return EmailValidation()
|
||||
case .MinLength:
|
||||
return MinLengthValidation()
|
||||
case .MaxLength:
|
||||
return MaxLengthValidation()
|
||||
case .PhoneNumber:
|
||||
return PhoneNumberValidation()
|
||||
case .ZipCode:
|
||||
return ZipCodeValidation()
|
||||
case .FullName:
|
||||
return FullNameValidation()
|
||||
// Add Validation to allow Factory to create one on the fly for you
|
||||
case .SocialSecurity:
|
||||
return SSNValidation()
|
||||
default:
|
||||
return RequiredValidation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,21 @@
|
|||
62D1AE241A1E6D4400E4DFF8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 62D1AE231A1E6D4400E4DFF8 /* Images.xcassets */; };
|
||||
62D1AE271A1E6D4400E4DFF8 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62D1AE251A1E6D4400E4DFF8 /* LaunchScreen.xib */; };
|
||||
62D1AE331A1E6D4500E4DFF8 /* ValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE321A1E6D4500E4DFF8 /* ValidatorTests.swift */; };
|
||||
62D1AE3E1A1E6FEF00E4DFF8 /* FullNameValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE3D1A1E6FEF00E4DFF8 /* FullNameValidation.swift */; };
|
||||
62D1AE491A1E6FF800E4DFF8 /* EmailValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE3F1A1E6FF800E4DFF8 /* EmailValidation.swift */; };
|
||||
62D1AE4A1A1E6FF800E4DFF8 /* MaxLengthValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE401A1E6FF800E4DFF8 /* MaxLengthValidation.swift */; };
|
||||
62D1AE4B1A1E6FF800E4DFF8 /* MinLengthValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE411A1E6FF800E4DFF8 /* MinLengthValidation.swift */; };
|
||||
62D1AE4C1A1E6FF800E4DFF8 /* PhoneNumberValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE421A1E6FF800E4DFF8 /* PhoneNumberValidation.swift */; };
|
||||
62D1AE4D1A1E6FF800E4DFF8 /* RequiredValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE431A1E6FF800E4DFF8 /* RequiredValidation.swift */; };
|
||||
62D1AE4E1A1E6FF800E4DFF8 /* Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE441A1E6FF800E4DFF8 /* Validation.swift */; };
|
||||
62D1AE4F1A1E6FF800E4DFF8 /* ValidationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE451A1E6FF800E4DFF8 /* ValidationError.swift */; };
|
||||
62D1AE501A1E6FF800E4DFF8 /* ValidationErrorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE461A1E6FF800E4DFF8 /* ValidationErrorType.swift */; };
|
||||
62D1AE511A1E6FF800E4DFF8 /* ValidationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE471A1E6FF800E4DFF8 /* ValidationFactory.swift */; };
|
||||
62D1AE521A1E6FF800E4DFF8 /* ValidationRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE481A1E6FF800E4DFF8 /* ValidationRule.swift */; };
|
||||
62D1AE571A1E700200E4DFF8 /* ValidationRuleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE531A1E700200E4DFF8 /* ValidationRuleType.swift */; };
|
||||
62D1AE581A1E700200E4DFF8 /* Validator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE541A1E700200E4DFF8 /* Validator.swift */; };
|
||||
62D1AE591A1E700200E4DFF8 /* ZipCodeValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE551A1E700200E4DFF8 /* ZipCodeValidation.swift */; };
|
||||
62D1AE5A1A1E700200E4DFF8 /* PasswordValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62D1AE561A1E700200E4DFF8 /* PasswordValidation.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
|
@ -36,6 +51,22 @@
|
|||
62D1AE2C1A1E6D4500E4DFF8 /* ValidatorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ValidatorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
62D1AE311A1E6D4500E4DFF8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
62D1AE321A1E6D4500E4DFF8 /* ValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorTests.swift; sourceTree = "<group>"; };
|
||||
62D1AE3D1A1E6FEF00E4DFF8 /* FullNameValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullNameValidation.swift; sourceTree = "<group>"; };
|
||||
62D1AE3F1A1E6FF800E4DFF8 /* EmailValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmailValidation.swift; sourceTree = "<group>"; };
|
||||
62D1AE401A1E6FF800E4DFF8 /* MaxLengthValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaxLengthValidation.swift; sourceTree = "<group>"; };
|
||||
62D1AE411A1E6FF800E4DFF8 /* MinLengthValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinLengthValidation.swift; sourceTree = "<group>"; };
|
||||
62D1AE421A1E6FF800E4DFF8 /* PhoneNumberValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumberValidation.swift; sourceTree = "<group>"; };
|
||||
62D1AE431A1E6FF800E4DFF8 /* RequiredValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequiredValidation.swift; sourceTree = "<group>"; };
|
||||
62D1AE441A1E6FF800E4DFF8 /* Validation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Validation.swift; sourceTree = "<group>"; };
|
||||
62D1AE451A1E6FF800E4DFF8 /* ValidationError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationError.swift; sourceTree = "<group>"; };
|
||||
62D1AE461A1E6FF800E4DFF8 /* ValidationErrorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationErrorType.swift; sourceTree = "<group>"; };
|
||||
62D1AE471A1E6FF800E4DFF8 /* ValidationFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationFactory.swift; sourceTree = "<group>"; };
|
||||
62D1AE481A1E6FF800E4DFF8 /* ValidationRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationRule.swift; sourceTree = "<group>"; };
|
||||
62D1AE531A1E700200E4DFF8 /* ValidationRuleType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationRuleType.swift; sourceTree = "<group>"; };
|
||||
62D1AE541A1E700200E4DFF8 /* Validator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Validator.swift; sourceTree = "<group>"; };
|
||||
62D1AE551A1E700200E4DFF8 /* ZipCodeValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipCodeValidation.swift; sourceTree = "<group>"; };
|
||||
62D1AE561A1E700200E4DFF8 /* PasswordValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordValidation.swift; sourceTree = "<group>"; };
|
||||
62D1AE5C1A1E78EE00E4DFF8 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -59,6 +90,7 @@
|
|||
62D1AE0E1A1E6D4400E4DFF8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
62D1AE5C1A1E78EE00E4DFF8 /* MyPlayground.playground */,
|
||||
62D1AE191A1E6D4400E4DFF8 /* Validator */,
|
||||
62D1AE2F1A1E6D4500E4DFF8 /* ValidatorTests */,
|
||||
62D1AE181A1E6D4400E4DFF8 /* Products */,
|
||||
|
|
@ -77,6 +109,7 @@
|
|||
62D1AE191A1E6D4400E4DFF8 /* Validator */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
62D1AE3C1A1E6FAF00E4DFF8 /* lib */,
|
||||
62D1AE1C1A1E6D4400E4DFF8 /* AppDelegate.swift */,
|
||||
62D1AE1E1A1E6D4400E4DFF8 /* ViewController.swift */,
|
||||
62D1AE201A1E6D4400E4DFF8 /* Main.storyboard */,
|
||||
|
|
@ -112,6 +145,36 @@
|
|||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
62D1AE3C1A1E6FAF00E4DFF8 /* lib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
62D1AE5B1A1E701B00E4DFF8 /* Validations */,
|
||||
62D1AE531A1E700200E4DFF8 /* ValidationRuleType.swift */,
|
||||
62D1AE541A1E700200E4DFF8 /* Validator.swift */,
|
||||
62D1AE451A1E6FF800E4DFF8 /* ValidationError.swift */,
|
||||
62D1AE461A1E6FF800E4DFF8 /* ValidationErrorType.swift */,
|
||||
62D1AE471A1E6FF800E4DFF8 /* ValidationFactory.swift */,
|
||||
62D1AE481A1E6FF800E4DFF8 /* ValidationRule.swift */,
|
||||
);
|
||||
name = lib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
62D1AE5B1A1E701B00E4DFF8 /* Validations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
62D1AE441A1E6FF800E4DFF8 /* Validation.swift */,
|
||||
62D1AE3D1A1E6FEF00E4DFF8 /* FullNameValidation.swift */,
|
||||
62D1AE421A1E6FF800E4DFF8 /* PhoneNumberValidation.swift */,
|
||||
62D1AE431A1E6FF800E4DFF8 /* RequiredValidation.swift */,
|
||||
62D1AE3F1A1E6FF800E4DFF8 /* EmailValidation.swift */,
|
||||
62D1AE411A1E6FF800E4DFF8 /* MinLengthValidation.swift */,
|
||||
62D1AE401A1E6FF800E4DFF8 /* MaxLengthValidation.swift */,
|
||||
62D1AE561A1E700200E4DFF8 /* PasswordValidation.swift */,
|
||||
62D1AE551A1E700200E4DFF8 /* ZipCodeValidation.swift */,
|
||||
);
|
||||
name = Validations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
|
@ -212,8 +275,23 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
62D1AE4C1A1E6FF800E4DFF8 /* PhoneNumberValidation.swift in Sources */,
|
||||
62D1AE5A1A1E700200E4DFF8 /* PasswordValidation.swift in Sources */,
|
||||
62D1AE4F1A1E6FF800E4DFF8 /* ValidationError.swift in Sources */,
|
||||
62D1AE3E1A1E6FEF00E4DFF8 /* FullNameValidation.swift in Sources */,
|
||||
62D1AE4B1A1E6FF800E4DFF8 /* MinLengthValidation.swift in Sources */,
|
||||
62D1AE1F1A1E6D4400E4DFF8 /* ViewController.swift in Sources */,
|
||||
62D1AE4E1A1E6FF800E4DFF8 /* Validation.swift in Sources */,
|
||||
62D1AE1D1A1E6D4400E4DFF8 /* AppDelegate.swift in Sources */,
|
||||
62D1AE581A1E700200E4DFF8 /* Validator.swift in Sources */,
|
||||
62D1AE501A1E6FF800E4DFF8 /* ValidationErrorType.swift in Sources */,
|
||||
62D1AE491A1E6FF800E4DFF8 /* EmailValidation.swift in Sources */,
|
||||
62D1AE511A1E6FF800E4DFF8 /* ValidationFactory.swift in Sources */,
|
||||
62D1AE591A1E700200E4DFF8 /* ZipCodeValidation.swift in Sources */,
|
||||
62D1AE571A1E700200E4DFF8 /* ValidationRuleType.swift in Sources */,
|
||||
62D1AE521A1E6FF800E4DFF8 /* ValidationRule.swift in Sources */,
|
||||
62D1AE4A1A1E6FF800E4DFF8 /* MaxLengthValidation.swift in Sources */,
|
||||
62D1AE4D1A1E6FF800E4DFF8 /* RequiredValidation.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
|
||||
<false/>
|
||||
<key>IDESourceControlProjectIdentifier</key>
|
||||
<string>41CB4003-1551-4C4C-B53F-78A56D1DFBE5</string>
|
||||
<key>IDESourceControlProjectName</key>
|
||||
<string>Validator</string>
|
||||
<key>IDESourceControlProjectOriginsDictionary</key>
|
||||
<dict>
|
||||
<key>44BA2A1DF8B8E3EE0CCBE8F37625F38B9979A032</key>
|
||||
<string>github.com:jpotts18/swift-validator.git</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectPath</key>
|
||||
<string>Validator.xcodeproj</string>
|
||||
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
||||
<dict>
|
||||
<key>44BA2A1DF8B8E3EE0CCBE8F37625F38B9979A032</key>
|
||||
<string>../..</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectURL</key>
|
||||
<string>github.com:jpotts18/swift-validator.git</string>
|
||||
<key>IDESourceControlProjectVersion</key>
|
||||
<integer>111</integer>
|
||||
<key>IDESourceControlProjectWCCIdentifier</key>
|
||||
<string>44BA2A1DF8B8E3EE0CCBE8F37625F38B9979A032</string>
|
||||
<key>IDESourceControlProjectWCConfigurations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>44BA2A1DF8B8E3EE0CCBE8F37625F38B9979A032</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>Validator</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// EmailValidation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class EmailValidation: Validation {
|
||||
|
||||
let EMAIL_REGEX = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}"
|
||||
|
||||
func validate(value:String) -> (Bool, ValidationErrorType) {
|
||||
|
||||
if let emailTest = NSPredicate(format: "SELF MATCHES %@", EMAIL_REGEX) {
|
||||
if emailTest.evaluateWithObject(value) {
|
||||
return (true, .NoError)
|
||||
} else {
|
||||
return (false,.Email)
|
||||
}
|
||||
}
|
||||
return (false, .Email)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// FullNameValidation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/19/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
class FullNameValidation : Validation {
|
||||
|
||||
func validate(value:String) -> (Bool, ValidationErrorType) {
|
||||
|
||||
var nameArray:[String] = split(value) { $0 == " " }
|
||||
if nameArray.count == 2 {
|
||||
return (true, .NoError)
|
||||
}
|
||||
return (false, .FullName)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// MaxLengthValidation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class MaxLengthValidation: Validation {
|
||||
let DEFAULT_MAX_LENGTH = 25
|
||||
|
||||
func validate(value: String) -> (Bool, ValidationErrorType) {
|
||||
if countElements(value) > DEFAULT_MAX_LENGTH {
|
||||
return (false, .MaxLength)
|
||||
}
|
||||
return (true, .NoError)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// MinLengthValidation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class MinLengthValidation: Validation {
|
||||
let DEFAULT_MIN_LENGTH = 3
|
||||
|
||||
func validate(value: String) -> (Bool, ValidationErrorType) {
|
||||
if countElements(value) < DEFAULT_MIN_LENGTH {
|
||||
return (false, .MinLength)
|
||||
}
|
||||
return (true, .NoError)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// PasswordValidation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/13/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class PasswordValidation : Validation {
|
||||
|
||||
// 8 characters. one uppercase
|
||||
var PASSWORD_REGEX = "^(?=.*?[A-Z]).{8,}$"
|
||||
|
||||
func validate(value: String) -> (Bool, ValidationErrorType) {
|
||||
if let passwordTes = NSPredicate(format: "SELF MATCHES %@", PASSWORD_REGEX) {
|
||||
if passwordTes.evaluateWithObject(value) {
|
||||
return (true, .NoError)
|
||||
}
|
||||
return (false, .Password)
|
||||
}
|
||||
return (false, .Password)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// PhoneValidation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class PhoneNumberValidation: Validation {
|
||||
let PHONE_REGEX = "^\\d{3}-\\d{3}-\\d{4}$"
|
||||
|
||||
func validate(value: String) -> (Bool, ValidationErrorType) {
|
||||
if let phoneTest = NSPredicate(format: "SELF MATCHES %@", PHONE_REGEX) {
|
||||
if phoneTest.evaluateWithObject(value) {
|
||||
return (true, .NoError)
|
||||
}
|
||||
return (false, .PhoneNumber)
|
||||
}
|
||||
return (false, .PhoneNumber)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// RequiredValidation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class RequiredValidation: Validation {
|
||||
|
||||
func validate(value:String) -> (Bool, ValidationErrorType) {
|
||||
if value.isEmpty {
|
||||
return (false, .Required)
|
||||
}
|
||||
return (true, .NoError)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// Validation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol Validation {
|
||||
func validate(value:String) -> (Bool, ValidationErrorType)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// File.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ValidationError {
|
||||
let textField:UITextField
|
||||
let error:ValidationErrorType
|
||||
|
||||
init(textField:UITextField, error:ValidationErrorType){
|
||||
self.textField = textField
|
||||
self.error = error
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// ValidationErrorType.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ValidationErrorType {
|
||||
case Required,
|
||||
Email,
|
||||
Password,
|
||||
MinLength,
|
||||
MaxLength,
|
||||
ZipCode,
|
||||
PhoneNumber,
|
||||
FullName,
|
||||
NoError
|
||||
|
||||
func description() -> String {
|
||||
switch self {
|
||||
case .Required:
|
||||
return "Required field"
|
||||
case .Email:
|
||||
return "Must be a valid email"
|
||||
case .MaxLength:
|
||||
return "This field should be less than"
|
||||
case .ZipCode:
|
||||
return "5 digit zipcode"
|
||||
case .PhoneNumber:
|
||||
return "10 digit phone number"
|
||||
case .Password:
|
||||
return "Must be at least 8 characters"
|
||||
case .FullName:
|
||||
return "Provide a first & last name"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Validations.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ValidationFactory {
|
||||
class func validationForRule(rule:ValidationRuleType) -> Validation {
|
||||
switch rule {
|
||||
case .Required:
|
||||
return RequiredValidation()
|
||||
case .Email:
|
||||
return EmailValidation()
|
||||
case .MinLength:
|
||||
return MinLengthValidation()
|
||||
case .MaxLength:
|
||||
return MaxLengthValidation()
|
||||
case .PhoneNumber:
|
||||
return PhoneNumberValidation()
|
||||
case .ZipCode:
|
||||
return ZipCodeValidation()
|
||||
case .FullName:
|
||||
return FullNameValidation()
|
||||
default:
|
||||
return RequiredValidation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ValidationRule.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ValidationRule {
|
||||
let textField:UITextField
|
||||
var rules:[ValidationRuleType] = []
|
||||
|
||||
init(textField:UITextField, rules:[ValidationRuleType]){
|
||||
self.textField = textField
|
||||
self.rules = rules
|
||||
}
|
||||
|
||||
func validateField() -> ValidationError? {
|
||||
for rule in rules {
|
||||
var validation = ValidationFactory.validationForRule(rule)
|
||||
var attempt:(isValid:Bool, error:ValidationErrorType) = validation.validate(textField.text)
|
||||
if !attempt.isValid {
|
||||
return ValidationError(textField: textField, error: attempt.error)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// ValidationRuleType.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ValidationRuleType {
|
||||
case Required,
|
||||
Email,
|
||||
Password,
|
||||
MinLength,
|
||||
MaxLength,
|
||||
ZipCode,
|
||||
PhoneNumber,
|
||||
FullName
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Validator.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/10/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol ValidationDelegate {
|
||||
func validationWasSuccessful()
|
||||
func validationFailed(errors:[String:ValidationError])
|
||||
}
|
||||
|
||||
protocol ValidationFieldDelegate {
|
||||
func validationFieldFailed(key:String, error:ValidationError)
|
||||
func validationFieldSuccess(key:String, validField:UITextField)
|
||||
}
|
||||
|
||||
class Validator {
|
||||
var validationRules:[String:ValidationRule] = [:]
|
||||
var validationErrors:[String:ValidationError] = [:]
|
||||
let delegate:ValidationDelegate
|
||||
|
||||
init(delegate:ValidationDelegate){
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
func registerField(key:String, textField:UITextField, rules:[ValidationRuleType]) {
|
||||
validationRules[key] = ValidationRule(textField: textField, rules: rules)
|
||||
}
|
||||
|
||||
func validateFieldByKey(key:String, delegate:ValidationFieldDelegate) {
|
||||
if let currentRule:ValidationRule = validationRules[key] {
|
||||
if var error:ValidationError = currentRule.validateField() {
|
||||
delegate.validationFieldFailed(key, error:error)
|
||||
} else {
|
||||
delegate.validationFieldSuccess(key, validField:currentRule.textField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validateAllBy(keys:[String], delegate:ValidationDelegate){
|
||||
|
||||
for key in keys {
|
||||
if let currentRule:ValidationRule = validationRules[key] {
|
||||
if var error:ValidationError = currentRule.validateField() {
|
||||
validationErrors[key] = error
|
||||
} else {
|
||||
validationErrors.removeValueForKey(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if validationErrors.isEmpty {
|
||||
delegate.validationWasSuccessful()
|
||||
} else {
|
||||
delegate.validationFailed(validationErrors)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,11 +13,15 @@ class ViewController: UIViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
|
||||
var validator = Validator(delegate: self)
|
||||
}
|
||||
|
||||
override func didReceiveMemoryWarning() {
|
||||
super.didReceiveMemoryWarning()
|
||||
// Dispose of any resources that can be recreated.
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// ZipCodeValidation.swift
|
||||
// Pingo
|
||||
//
|
||||
// Created by Jeff Potter on 11/11/14.
|
||||
// Copyright (c) 2014 Byron Mackay. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class ZipCodeValidation: Validation {
|
||||
let ZIP_REGEX = "\\d{5}"
|
||||
|
||||
func validate(value: String) -> (Bool, ValidationErrorType) {
|
||||
if let zipTest = NSPredicate(format: "SELF MATCHES %@", ZIP_REGEX) {
|
||||
if zipTest.evaluateWithObject(value) {
|
||||
return (true, .NoError)
|
||||
}
|
||||
return (false, .ZipCode)
|
||||
}
|
||||
return (false, .ZipCode)
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue