Validation Toolkit
Introduction
ValidationToolkit
is designed to be a lightweight framework specialised in data validation, such as email format, input length or passwords matching.
At the core of this project are the following principles:
- Separation of concerns
- Availability on all platforms
- Open to extensibility
Separation of concerns
Think of ValidationToolkit
as to an adjustable wrench more than to a Swiss knife.
With this idea in mind, the toolkit is composed from a small set of protocols, structs and classes than can be easily composed to fit your project needs.
All platforms availability
Since validation can take place at many levels, ValidationToolkit
is designed to support iOS, macOS, tvOS, watchOS and native Swift projects, such as server apps.
Open to extensibility
Every project is unique in it’s challenges and it’s great when we can focus on solving them instead of spending our time on boilerplate tasks.
ValidationToolkit
is compact and offers you the foundation you need to build data validation around your project needs. In addition, it includes a set of common validation predicates that most of the projects can benefit of: email validation, required fields, password matching, url validation and many more to come.
Requirements
- iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
- Xcode 8.1+
- Swift 3.0+
Installation
Carthage
You can use Carthage to install ValidationToolkit
by adding it to your Cartfile
:
github "nsagora/validation-toolkit"
Run carthage update
to build the framework and drag the built ValidationToolkit.framework
into your Xcode project.
Setting up Carthage
[Carthage][url-carthage] is a decentralised dependency manager that builds your dependencies and provides you with binary frameworks. You can install [Carthage][url-carthage] with [Homebrew][url-homebrew] using the following command: “`bash $ brew update $ brew install carthage ”`CocoaPods
You can use CocoaPods to install ValidationToolkit
by adding it to your Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
target 'YOUR_TARGET_NAME' do
pod 'ValidationToolkit'
end
Then, run the following command:
$ pod install
Note that this requires CocoaPods version 1.0.0, and your iOS deployment target to be at least 8.0.
Setting up CocoaPods
[CocoaPods][url-cocoapods] is a dependency manager for Cocoa projects. You can install it with the following command: “` $ gem install cocoapods ”`Swift Package Manager
You can use the Swift Package Manager to install ValidationToolkit
by adding it to your Package.swift
file:
import PackageDescription
let package = Package(
name: "YOUR_PROJECT_NAME",
targets: [],
dependencies: [
.Package(url: "https://github.com/nsagora/validation-toolkit", majorVersion: 1),
]
)
Note that the Swift Package Manager is still in early design and development, for more information checkout its GitHub Page.
Manually
To use this library in your project manually you may:
- for Projects, just drag the
Sources
folder into the project tree - for Workspaces, include the whole
ValidationToolkit.xcodeproj
Usage example
For a comprehensive list of examples try the ValidationToolikit.playground
:
- Download the repository locally on your machine
- Open
ValidationToolkit.workspace
- Build
ValidationToolkit iOS
target - Select the
ValidationToolkit
playgrounds from the Project navigator.
Predicates
The Predicate
represents the core protocol
and has the role to evaluate
if an input matches on a given validation condition.
At ValidationToolkit
‘s core we have the following two predicates, which allow developers to compose predicates specific to the project needs.
RegexPredicate
“`swift let predicate = RegexPredicate(expression: ”^[a-z]$“) predicate.evaluate(with: "a”) // returns true predicate.evaluate(with: “5”) // returns false predicate.evaluate(with: “ab”) // returns false “`BlockPredicate
”`swift let pred = BlockPredicateIn addition, the toolkit offers a set of common validation predicates that your project can benefit of:
EmailPredicate
”`swift let predicate = EmailPredicate() predicate.evaluate(with: “hello@”) // returns false predicate.evaluate(with: “hello@nsagora.com”) // returns true predicate.evaluate(with: “héllo@nsagora.com”) // returns true “`URLPredicate
”`swift let predicate = URLPredicate() predicate.evaluate(with: “http://www.url.com”) // returns true predicate.evaluate(with: “http:\www.url.com”) // returns false “`PairMatchingPredicate
”`swift let predicate = PairMatchingPredicate() predicate.evaluate(with: (“swift”, “swift”)) // returns true predicate.evaluate(with: (“swift”, “obj-c”)) // returns false “`On top of that, developers can build more advanced or complex predicates by extending the Predicate
protocol, and/ or by composing or decorating the existing predicates:
Custom Predicate
”`swift public class MinLenghtPredicate: Predicate { public typealias InputType = String private let minLenght:Int public init(minLenght:Int) { self.minLenght = minLenght } public func evaluate(with input: String) -> Bool { return input.characters.count >= minLenght } } let predicate = MinLenghtPredicate(minLenght: 5) predicate.evaluate(with: “alph”) // returns false predicate.evaluate(with: “alpha”) // returns true predicate.evaluate(with: “alphabet”) // returns true “`Constraints
A PredicateConstraint
represents a data type that links a Predicate
to an Error
, in order to provide useful feedback for the end users.
PredicateConstraint
”`swift let predicate = BlockPredicateConstraint Sets
A ConstraintSet
represents a collection of constraints that allows the evaluation to be made on:
- any of the constraints
- all constraints
To provide context, a ConstraintSet
allows us to constraint a piece of data as being required and also as being a valid email.
ConstraintSet
() passwordConstraints.add(predicate: lowerCasePredicate, error: Form.Password.missingLowercase) passwordConstraints.add(predicate: upperCasePredicate, error: Form.Password.missingUpercase) passwordConstraints.add(predicate: digitsPredicate, error: Form.Password.missingDigits) passwordConstraints.add(predicate: specialChars, error: Form.Password.missingSpecialChars) passwordConstraints.add(predicate: minLenght, error: Form.Password.minLenght(8)) let password = "3nGuard!” let result = passwordConstraints.evaluateAll(input: password) switch result { case .valid: print(“Wow, that’s a 💪 password!”) case .invalid(let summary): print(summary.errors.map({$0.localizedDescription})) } // prints “Wow, that’s a 💪 password!” “` From above, we see that once we’ve constructed the `passwordConstraints`, we’re simply calling `evaluateAll(input:)` to get a `Summary` of our evaluation result. This summary can then be handled as we please.Contribute
We would love you for the contribution to ValidationToolkit, check the LICENSE
file for more info.
Meta
This project is developed and maintained by the members of iOS NSAgora, the community of iOS Developers of Iași, Romania.
Distributed under the MIT license. See LICENSE
for more information.
[https://github.com/nsagora/validation-toolkit]
Credits and references
We got inspired from other open source projects and they worth to be mentioned below for reference: