Skip to content

klein-thibault/TextFieldValidation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 

Repository files navigation

UITextField Validation

This repository is based of the blog post I wrote about UITextField validation using functionnal programming.

extension UITextField {

    func validateField(_ functions: [(String) -> Bool]) -> Bool {
        return functions.map { f in f(self.text ?? "") }.reduce(true) { $0 && $1 }
    }
    
}

extension String {
    func evaluate(with condition: String) -> Bool {
        guard let range = range(of: condition, options: .regularExpression, range: nil, locale: nil) else {
            return false
        }

        return range.lowerBound == startIndex && range.upperBound == endIndex
    }
}

func isPhoneNumberValid(text: String) -> Bool {
    let regexp = "^[0-9]{10}$"
    return text.evaluate(with: regexp)
}

func isZipCodeValid(text: String) -> Bool {
    let regexp = "^[0-9]{5}$"
    return text.evaluate(with: regexp)
}

func isStateValid(text: String) -> Bool {
    let regexp = "^[A-Z]{2}$"
    return text.evaluate(with: regexp)
}

func isCVCValid(text: String) -> Bool {
    let regexp = "^[0-9]{3,4}$"
    return text.evaluate(with: regexp)
}

func isEmailValid(text: String) -> Bool {
    let regexp = "[A-Z0-9a-z._]+@([\\w\\d]+[\\.\\w\\d]*)"
    return text.evaluate(with: regexp)
}

let cvcTextField = UITextField()
cvcTextField.text = "123"
cvcTextField.validateField([isCVCValid])

let emailTextField = UITextField()
emailTextField.text = "thibault@gmail.com"
emailTextField.validateField([isEmailValid])

protocol Validatable {
    associatedtype T

    func validate(_ functions: [T]) -> Bool
}

protocol Evaluatable {
    associatedtype T

    func evaluate(with condition: T) -> Bool
}

extension UITextField: Validatable {
    func validate(_ functions: [(String) -> Bool]) -> Bool {
        return functions.map { f in f(self.text ?? "") }.reduce(true) { $0 && $1 }
    }
}

extension String: Evaluatable {
    func evaluate(with condition: String) -> Bool {
        guard let range = range(of: condition, options: .regularExpression, range: nil, locale: nil) else {
            return false
        }

        return range.lowerBound == startIndex && range.upperBound == endIndex
    }
}

struct User {
    let firstName: String
    let lastName: String
    let age: Int
}

extension User: Validatable {
    func validate(_ functions: [(User) -> Bool]) -> Bool {
        return functions.map { f in f(self) }.reduce(true) { $0 && $1 }
    }
}

func isUserNameValid(user: User) -> Bool {
    let regexp = "[A-Za-z]+"
    return user.firstName.evaluate(with: regexp) && user.lastName.evaluate(with: regexp)
}

func isUserAdult(user: User) -> Bool {
    return user.age >= 18
}

let user = User(firstName: "Thibault", lastName: "Klein", age: 25)
XCTAssertTrue(user.validate([isUserNameValid, isUserAdult]))

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages