diff --git a/MyPlayground.playground/contents.xcplayground b/MyPlayground.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/MyPlayground.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MyPlayground.playground/section-1.swift b/MyPlayground.playground/section-1.swift
new file mode 100644
index 0000000..b31d259
--- /dev/null
+++ b/MyPlayground.playground/section-1.swift
@@ -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)
+
diff --git a/MyPlayground.playground/timeline.xctimeline b/MyPlayground.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/MyPlayground.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/README.md b/README.md
index ebc6753..525a59b 100644
--- a/README.md
+++ b/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()
+ }
+ }
+}
+
+```
+
+
+
+
+
+
diff --git a/Validator.xcodeproj/project.pbxproj b/Validator.xcodeproj/project.pbxproj
index 2625ab2..45990de 100644
--- a/Validator.xcodeproj/project.pbxproj
+++ b/Validator.xcodeproj/project.pbxproj
@@ -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 = ""; };
62D1AE321A1E6D4500E4DFF8 /* ValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorTests.swift; sourceTree = ""; };
+ 62D1AE3D1A1E6FEF00E4DFF8 /* FullNameValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullNameValidation.swift; sourceTree = ""; };
+ 62D1AE3F1A1E6FF800E4DFF8 /* EmailValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmailValidation.swift; sourceTree = ""; };
+ 62D1AE401A1E6FF800E4DFF8 /* MaxLengthValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaxLengthValidation.swift; sourceTree = ""; };
+ 62D1AE411A1E6FF800E4DFF8 /* MinLengthValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinLengthValidation.swift; sourceTree = ""; };
+ 62D1AE421A1E6FF800E4DFF8 /* PhoneNumberValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumberValidation.swift; sourceTree = ""; };
+ 62D1AE431A1E6FF800E4DFF8 /* RequiredValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequiredValidation.swift; sourceTree = ""; };
+ 62D1AE441A1E6FF800E4DFF8 /* Validation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Validation.swift; sourceTree = ""; };
+ 62D1AE451A1E6FF800E4DFF8 /* ValidationError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationError.swift; sourceTree = ""; };
+ 62D1AE461A1E6FF800E4DFF8 /* ValidationErrorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationErrorType.swift; sourceTree = ""; };
+ 62D1AE471A1E6FF800E4DFF8 /* ValidationFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationFactory.swift; sourceTree = ""; };
+ 62D1AE481A1E6FF800E4DFF8 /* ValidationRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationRule.swift; sourceTree = ""; };
+ 62D1AE531A1E700200E4DFF8 /* ValidationRuleType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationRuleType.swift; sourceTree = ""; };
+ 62D1AE541A1E700200E4DFF8 /* Validator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Validator.swift; sourceTree = ""; };
+ 62D1AE551A1E700200E4DFF8 /* ZipCodeValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZipCodeValidation.swift; sourceTree = ""; };
+ 62D1AE561A1E700200E4DFF8 /* PasswordValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordValidation.swift; sourceTree = ""; };
+ 62D1AE5C1A1E78EE00E4DFF8 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = ""; };
/* 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 = "";
};
+ 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 = "";
+ };
+ 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 = "";
+ };
/* 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;
};
diff --git a/Validator.xcodeproj/project.xcworkspace/xcshareddata/Validator.xccheckout b/Validator.xcodeproj/project.xcworkspace/xcshareddata/Validator.xccheckout
new file mode 100644
index 0000000..ed01e81
--- /dev/null
+++ b/Validator.xcodeproj/project.xcworkspace/xcshareddata/Validator.xccheckout
@@ -0,0 +1,41 @@
+
+
+
+
+ IDESourceControlProjectFavoriteDictionaryKey
+
+ IDESourceControlProjectIdentifier
+ 41CB4003-1551-4C4C-B53F-78A56D1DFBE5
+ IDESourceControlProjectName
+ Validator
+ IDESourceControlProjectOriginsDictionary
+
+ 44BA2A1DF8B8E3EE0CCBE8F37625F38B9979A032
+ github.com:jpotts18/swift-validator.git
+
+ IDESourceControlProjectPath
+ Validator.xcodeproj
+ IDESourceControlProjectRelativeInstallPathDictionary
+
+ 44BA2A1DF8B8E3EE0CCBE8F37625F38B9979A032
+ ../..
+
+ IDESourceControlProjectURL
+ github.com:jpotts18/swift-validator.git
+ IDESourceControlProjectVersion
+ 111
+ IDESourceControlProjectWCCIdentifier
+ 44BA2A1DF8B8E3EE0CCBE8F37625F38B9979A032
+ IDESourceControlProjectWCConfigurations
+
+
+ IDESourceControlRepositoryExtensionIdentifierKey
+ public.vcs.git
+ IDESourceControlWCCIdentifierKey
+ 44BA2A1DF8B8E3EE0CCBE8F37625F38B9979A032
+ IDESourceControlWCCName
+ Validator
+
+
+
+
diff --git a/Validator.xcodeproj/project.xcworkspace/xcuserdata/jpotts18.xcuserdatad/UserInterfaceState.xcuserstate b/Validator.xcodeproj/project.xcworkspace/xcuserdata/jpotts18.xcuserdatad/UserInterfaceState.xcuserstate
index 633be68..5b4eb6e 100644
Binary files a/Validator.xcodeproj/project.xcworkspace/xcuserdata/jpotts18.xcuserdatad/UserInterfaceState.xcuserstate and b/Validator.xcodeproj/project.xcworkspace/xcuserdata/jpotts18.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/Validator/EmailValidation.swift b/Validator/EmailValidation.swift
new file mode 100644
index 0000000..4711f4d
--- /dev/null
+++ b/Validator/EmailValidation.swift
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/Validator/FullNameValidation.swift b/Validator/FullNameValidation.swift
new file mode 100644
index 0000000..9e78993
--- /dev/null
+++ b/Validator/FullNameValidation.swift
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/Validator/MaxLengthValidation.swift b/Validator/MaxLengthValidation.swift
new file mode 100644
index 0000000..bf9139f
--- /dev/null
+++ b/Validator/MaxLengthValidation.swift
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/Validator/MinLengthValidation.swift b/Validator/MinLengthValidation.swift
new file mode 100644
index 0000000..ce4078e
--- /dev/null
+++ b/Validator/MinLengthValidation.swift
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/Validator/PasswordValidation.swift b/Validator/PasswordValidation.swift
new file mode 100644
index 0000000..1583dcc
--- /dev/null
+++ b/Validator/PasswordValidation.swift
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/Validator/PhoneNumberValidation.swift b/Validator/PhoneNumberValidation.swift
new file mode 100644
index 0000000..7f56ca8
--- /dev/null
+++ b/Validator/PhoneNumberValidation.swift
@@ -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)
+ }
+
+}
diff --git a/Validator/RequiredValidation.swift b/Validator/RequiredValidation.swift
new file mode 100644
index 0000000..0570d69
--- /dev/null
+++ b/Validator/RequiredValidation.swift
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/Validator/Validation.swift b/Validator/Validation.swift
new file mode 100644
index 0000000..c7b5c45
--- /dev/null
+++ b/Validator/Validation.swift
@@ -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)
+}
\ No newline at end of file
diff --git a/Validator/ValidationError.swift b/Validator/ValidationError.swift
new file mode 100644
index 0000000..1b19384
--- /dev/null
+++ b/Validator/ValidationError.swift
@@ -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
+ }
+
+}
\ No newline at end of file
diff --git a/Validator/ValidationErrorType.swift b/Validator/ValidationErrorType.swift
new file mode 100644
index 0000000..f612776
--- /dev/null
+++ b/Validator/ValidationErrorType.swift
@@ -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 ""
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Validator/ValidationFactory.swift b/Validator/ValidationFactory.swift
new file mode 100644
index 0000000..fa73f4e
--- /dev/null
+++ b/Validator/ValidationFactory.swift
@@ -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()
+ }
+ }
+}
diff --git a/Validator/ValidationRule.swift b/Validator/ValidationRule.swift
new file mode 100644
index 0000000..bf108cd
--- /dev/null
+++ b/Validator/ValidationRule.swift
@@ -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
+ }
+
+}
\ No newline at end of file
diff --git a/Validator/ValidationRuleType.swift b/Validator/ValidationRuleType.swift
new file mode 100644
index 0000000..d9dcd62
--- /dev/null
+++ b/Validator/ValidationRuleType.swift
@@ -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
+}
\ No newline at end of file
diff --git a/Validator/Validator.swift b/Validator/Validator.swift
new file mode 100644
index 0000000..78f4ae3
--- /dev/null
+++ b/Validator/Validator.swift
@@ -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)
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Validator/ViewController.swift b/Validator/ViewController.swift
index 8e2d68d..a757aa0 100644
--- a/Validator/ViewController.swift
+++ b/Validator/ViewController.swift
@@ -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.
+
+
}
diff --git a/Validator/ZipCodeValidation.swift b/Validator/ZipCodeValidation.swift
new file mode 100644
index 0000000..af62b54
--- /dev/null
+++ b/Validator/ZipCodeValidation.swift
@@ -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)
+ }
+
+}
\ No newline at end of file