All Projects → fgeistert → Validated

fgeistert / Validated

Licence: MIT license
A rule-based validation framework

Programming Languages

swift
15916 projects
objective c
16641 projects - #2 most used programming language

Projects that are alternatives of or similar to Validated

Bettersegmentedcontrol
An easy to use, customizable replacement for UISegmentedControl & UISwitch.
Stars: ✭ 1,782 (+5648.39%)
Mutual labels:  carthage, swift-package-manager
Cdmarkdownkit
An extensive Swift framework providing simple and customizable markdown parsing.
Stars: ✭ 158 (+409.68%)
Mutual labels:  carthage, swift-package-manager
Natrium
A pre-build (Swift) script to alter your Xcode project at pre-build-time per environment, build configuration and target.
Stars: ✭ 131 (+322.58%)
Mutual labels:  carthage, swift-package-manager
Alamofire
Elegant HTTP Networking in Swift
Stars: ✭ 36,896 (+118919.35%)
Mutual labels:  carthage, swift-package-manager
Carting
🚘 A simple tool for updating Carthage script phase
Stars: ✭ 182 (+487.1%)
Mutual labels:  carthage, swift-package-manager
Randomkit
Random data generation in Swift
Stars: ✭ 1,458 (+4603.23%)
Mutual labels:  carthage, swift-package-manager
Ducttape
📦 KeyPath dynamicMemberLookup based syntax sugar for Swift.
Stars: ✭ 138 (+345.16%)
Mutual labels:  carthage, swift-package-manager
Freedom
The Freedom to Open URLs in Third-Party Browsers on iOS with Custom UIActivity Subclasses.
Stars: ✭ 85 (+174.19%)
Mutual labels:  carthage, swift-package-manager
L10n Swift
Localization of the application with ability to change language "on the fly" and support for plural form in any language.
Stars: ✭ 177 (+470.97%)
Mutual labels:  carthage, swift-package-manager
Multipeer
📱📲 A wrapper for the MultipeerConnectivity framework for automatic offline data transmission between devices
Stars: ✭ 170 (+448.39%)
Mutual labels:  carthage, swift-package-manager
Swifterswift
A handy collection of more than 500 native Swift extensions to boost your productivity.
Stars: ✭ 10,706 (+34435.48%)
Mutual labels:  carthage, swift-package-manager
Amplitude Ios
Native iOS/tvOS/macOS SDK
Stars: ✭ 216 (+596.77%)
Mutual labels:  carthage, swift-package-manager
Buckets Swift
Swift Collection Data Structures Library
Stars: ✭ 106 (+241.94%)
Mutual labels:  carthage, swift-package-manager
Skeletonview
☠️ An elegant way to show users that something is happening and also prepare them to which contents they are awaiting
Stars: ✭ 10,804 (+34751.61%)
Mutual labels:  carthage, swift-package-manager
Xmlmapper
A simple way to map XML to Objects written in Swift
Stars: ✭ 90 (+190.32%)
Mutual labels:  carthage, swift-package-manager
Coregpx
A library for parsing and creation of GPX location files. Purely Swift.
Stars: ✭ 132 (+325.81%)
Mutual labels:  carthage, swift-package-manager
Spasibo
🙏 Support your favourite open source projects
Stars: ✭ 78 (+151.61%)
Mutual labels:  carthage, swift-package-manager
Swiftlinkpreview
It makes a preview from an URL, grabbing all the information such as title, relevant texts and images.
Stars: ✭ 1,216 (+3822.58%)
Mutual labels:  carthage, swift-package-manager
Kvkcalendar
A most fully customization calendar and timeline library for iOS 📅
Stars: ✭ 160 (+416.13%)
Mutual labels:  carthage, swift-package-manager
Aksidemenu
Beautiful iOS side menu library with parallax effect. Written in Swift
Stars: ✭ 216 (+596.77%)
Mutual labels:  carthage, swift-package-manager

Validated

Swift 5.2 SPM Compatible Carthage compatible

A rule-based validation framework.

Key Features

  • rule-based
  • easily extensible
  • type-safe
  • well tested
  • combine support
  • input formatting
  • optional validation

About this project

The basic idea is to separate the validation logic from the rest of your project. Validated self-encapsulates all validation logic into reusable rules. All rules are type-safe and tested. Additionally it features input formatting. Fields can also be marked as optional.

Usage

The project includes an Example project.

Getting started

Using Validated is very simple and straight-forward.

Example with Property Wrapper

@Validated(rules: [.notEmpty, .isEmail], formatters: [.trimmed, .lowercased])
var email: String?

Manual validation and formatting

// validation
let validation = ValidationResult.validate("[email protected]", with: [.notEmpty, .isEmail])
XCTAssertTrue(validation.isValid) // true

// formatting
let newValue = ValidationResult.format("  abc   ", with: [.trimmed, .uppercased])
XCTAssertEqual(newValue, "ABC") // true

Core Components

Result

The ValidationResult is an Enum that has two states:

case valid(_ value: Value?)
case notValid

.valid has an associated value, that will return the validated value, if there is one. This is optional, because the strategy can be .optional.

The ValidationResult also has two computed properties: isValid which returns a Bool and value which returns the optional value.

Additionally, ValidationResult houses the .validate(..) and .format(..) functions to manually invoke a validation and formatting of an input value.

Note: ValidationResult also conforms to the Equatable protocol.

Rule

A rule is defined with a closure, that receives a Value and returns a Bool. The Value is not optional.

Right now there are 42 rules included in the standard package.

Example
extension ValidationRule where Value: StringProtocol {
    static var notEmpty: Self {
        return ValidationRule {
            return !$0.isEmpty
        }
    }
}

Note: return keywords can be ommitted, to make a rule even more lightweight.

Formatter

A formatter is similar to a rule. It is defined as a closure, that receives a Value and returns a Value. Neither are optional.

Right now there are 7 formatters included in the standard package.

Example
extension ValidationFormatter where Value == String {    
    static var uppercased: Self {
        return ValidationFormatter {
            return $0.uppercased()
        }
    }
}

Note: return keywords can be ommitted, to make a formatter even more lightweight.

Strategy

In some situations we only want to validate fields that actually contain something. To deal with this kind of situation Validated has two modes, that are reflected in ValidationStrategy.

The two modes are:

case required
case optional

If you are using a @Validated object, you can simply pass the strategy to the property wrapper like this:

@Validated(rule: .isURL, formatters: [.trimmed, .lowercased], strategy: .optional)
var website: String?

Note: By default, @Validated uses the .required strategy.

Validated

The main usage of this framework is bundled within the @Validated property wrapper. It takes care of all the validating, formatting and contains the strategy logic. Additionally it contains optional Combine support.

Defining it, is very straight-forward:

@Validated(rules: [.notEmpty, .isEmail], formatters: [.trimmed, .lowercased])
var email: String?

Note: Formatting will be done, before the rules are checked. Therefore, it will validate the formatted values.

Initialization

@Validated can be initialized in many ways:

  • one ValidationRule or an Array of ValidationRules
  • zero, one or an Array of ValidationFormatters
  • a ValidationStrategy. By default, if none provided, it uses the .required strategy.
Combine

@Validated also contains some Combine extensions. They will only take affect, if Combine can be imported. Basically, there are two publishers:

  • validationPublisher -> publishes a ValidationResult for every change to the value.
  • valuePublisher -> publishes a formatted value, whenever a .valid ValidationResult occurs.

Note: Even though Combine is supported, you can still use it without it. Validated is usable from iOS9+.

Projected Value

The projected value returns the validationPublisher(). It publishes a ValidationResult every time you make a change to the properties' value.

Example
$email
    .sink { [weak self] (result) in
        switch result {
        case .valid(let value):
            self?.passwordValidLabel.text = ""
            print("new password: valid -> \(value ?? "nil")")
        case .notValid:
            self?.passwordValidLabel.text = ""
            print("new password: notValid")
        }
    }
    .store(in: &cancellables)

Note: Make sure you connect your TextField to your @Validated object. This can be done by binding your TextField values to the property with Combine or using the NotificationCenter. Examples of how this can be done are included in the Example project.

Customization

Validated was designed to make it easily extensible. Therefore making your own rules and formatters is encouraged. If you think that you created a rule or a formatter that would fit into the standard library, feel free to create a pull request.

Note: Every Rule and Formatter should be tested.

Making your own Rule

Here is an example of how you could make your own rule called isAwesome.

extension ValidationRule where Value == String {
    static var isAwesome: Self {
        return ValidationRule {
            return $0 == "Awesome"
        }
    }
}

This could also be written like this:

extension ValidationRule {
    static var isAwesome<String>: Self {
        ValidationRule { $0 == "Awesome" }
    }
}

Note: You can also have static functions that take additional input to validate.

Making your own Formatter

Here is an example of how you could make your own formatter called replacedAWithB, that replaces every occurance of A with a B.

extension ValidationFormatter where Value == String {
    static var replacedAWithB: Self {
        return ValidationFormatter {
            return $0.replacingOccurrences(of: "A", with: "B")
        }
    }
}

This could also be written like this:

extension ValidationFormatter {
    static var replacedAWithB<String>: Self {
        ValidationFormatter { $0.replacingOccurrences(of: "A", with: "B") }
    }
}

Naming Conventions

There are certain naming conventions that should be followed to guarantee simple code and improve readability.

ValidationRule

Every ValidationRule should be named in the present tense and should be treated in the third person. They should also be as short as possible while also being as expressive as possible.

Examples:

  • notEmpty
  • contains
  • startsWith
  • isNumber
  • isEmail

ValidationFormatter

Every ValidationFormatter should be named in the simple past tense (e.g. trimmed or uppercased). The reason behind this is, that formatters are applied inside the @Validated object, before it is returned when accessing the value. Therefore, the formatters have already been applied and the text is now trimmed or uppercased.

Installation

Swift Package Manager (Recommended)

Add the following dependency to your Package.swift file:

.package(url: "https://github.com/fgeistert/Validated.git", from: "1.0.2")

Cartage

Add the following line to your Cartfile.

github "fgeistert/Validated" ~> 1.0.2

Then run carthage update.

Manually

Just drag and drop the .swift files from the Validated folder into your project.

Version Compatibility

Validated is built with Swift 5.2. It supports iOS9+.

Contributing

  • Open an issue
  • Fork it
  • Create new branch
  • Commit all your changes to your branch
  • Create a pull request

Contact

You can check out my website or follow me on twitter.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].