Skip to content

Instantly share code, notes, and snippets.

@to4iki
Created December 6, 2016 18:54
Show Gist options
  • Save to4iki/a16ce321fbf7a0346ad77c62e630b48f to your computer and use it in GitHub Desktop.
Save to4iki/a16ce321fbf7a0346ad77c62e630b48f to your computer and use it in GitHub Desktop.
composite validator
import Foundation
// MARK: - EmailValidationError
enum EmailValidationError: Error {
case empty
case invalidFormat
}
// MARK: - PasswordValidationError
enum PasswordValidationError: Error {
case empty
case tooShort
case noUppercaseLetter
case noLowercaseLetter
case noNumber
}
// MARK: - Validators
struct EmptyStringValidator: Validator {
private let invalidError: Error
init(invalidError: Error) {
self.invalidError = invalidError
}
func validate(_ value: String) -> ValidationResult {
if value.isEmpty {
return .invalid(errors: [invalidError])
} else {
return .valid
}
}
}
struct EmailFormatValidator: Validator {
func validate(_ value: String) -> ValidationResult {
let magicEmailRegexStolenFromTheInternet = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
let emailTest = NSPredicate(format:"SELF MATCHES %@", magicEmailRegexStolenFromTheInternet)
if emailTest.evaluate(with: value) {
return .valid
} else {
return .invalid(errors: [EmailValidationError.invalidFormat])
}
}
}
struct PasswordLengthValidator: Validator {
func validate(_ value: String) -> ValidationResult {
if value.characters.count >= 8 {
return .valid
} else {
return .invalid(errors: [PasswordValidationError.tooShort])
}
}
}
struct UppercaseLetterValidator: Validator {
func validate(_ value: String) -> ValidationResult {
let uppercaseLetterRegex = ".*[A-Z]+.*"
let uppercaseLetterTest = NSPredicate(format:"SELF MATCHES %@", uppercaseLetterRegex)
if uppercaseLetterTest.evaluate(with: value) {
return .valid
} else {
return .invalid(errors: [PasswordValidationError.noUppercaseLetter])
}
}
}
// MARK: - ValidatorFactory
struct ValidatorFactory {
static let sharedInstance = ValidatorFactory()
private init() {}
func emailValidator() -> Validator {
return CompositeValidator(validators: emptyEmailStringValidator(), EmailFormatValidator())
}
func passwordValidator() -> Validator {
return CompositeValidator(validators: emptyPasswordStringValidator(), passwordStrengthValidator())
}
private func emptyEmailStringValidator() -> Validator {
return EmptyStringValidator(invalidError: EmailValidationError.empty)
}
private func emptyPasswordStringValidator() -> Validator {
return EmptyStringValidator(invalidError: PasswordValidationError.empty)
}
private func passwordStrengthValidator() -> Validator {
return CompositeValidator(validators: PasswordLengthValidator(), UppercaseLetterValidator())
}
}
// MARK: - Exectute
let emailValidator = ValidatorFactory.sharedInstance.emailValidator()
print(emailValidator.validate(""))
print(emailValidator.validate("invalidEmail@"))
print(emailValidator.validate("validEmail@validDomain.com"))
let passwordValidator = ValidatorFactory.sharedInstance.passwordValidator()
print(passwordValidator.validate(""))
print(passwordValidator.validate("psS$"))
print(passwordValidator.validate("paSSw0rd"))
import Foundation
// MARK: - ValidationResult
public enum ValidationResult {
case valid
case invalid(errors: [Error])
}
// MARK: - Validator
public protocol Validator {
func validate(_ value: String) -> ValidationResult
}
// MARK: - CompositeValidator
public struct CompositeValidator: Validator {
private let validators: [Validator]
public init(validators: Validator...) {
self.validators = validators
}
public func validate(_ value: String) -> ValidationResult {
return validators.reduce(.valid) { (acc, validator) -> ValidationResult in
switch validator.validate(value) {
case .valid:
return acc
case .invalid(let errors):
switch acc {
case .valid:
return .invalid(errors: errors)
case .invalid(errors: let accErrors):
return .invalid(errors: accErrors + errors)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment