Skip to content
This repository has been archived by the owner on Jul 21, 2020. It is now read-only.

Commit

Permalink
First few files
Browse files Browse the repository at this point in the history
  • Loading branch information
adamwaite committed Oct 29, 2016
1 parent bfb8b24 commit 82c39b5
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 14 deletions.
82 changes: 74 additions & 8 deletions Validator/Validator/ValidationResult.swift
Expand Up @@ -29,30 +29,96 @@

import Foundation

/**
The ValidationResult enum desribes the result of a validation. It may take one
of two forms: valid (a passed validation), or invalid (a failed validation).
*/
public enum ValidationResult {

/**
A successful validation (an input satisfies the condition in a rule).
*/
case valid
case invalid([ValidationErrorType])

/**
A failed validation (an input does not satisfy the condition in a rule).
The .invalid case has an associated collection of validation errors.
*/
case invalid([ValidationErrorType])

/**
True if the result is valid
*/
public var isValid: Bool { return self == .valid }

public func merge(result: ValidationResult) -> ValidationResult {

/**
Merges the receiving validation rule with another.
```
.valid.merge(.valid) // = .valid
.valid.merge(.invalid([err])) // = .invalid([err])
.invalid([err1]).merge(.invalid([err2]) // = .invalid([err1, err2])
```
- Parameters:
- result: The result to merge into the receiver.
- Returns:
Merged validation result.
*/
public func merge(with result: ValidationResult) -> ValidationResult {
switch self {
case .valid: return result
case .invalid(let errorMessages):
switch result {
case .valid: return self
case .invalid(let errorMessagesAnother): return .invalid([errorMessages, errorMessagesAnother].flatMap { $0 })
case .valid:
return self
case .invalid(let errorMessagesAnother):
return .invalid([errorMessages, errorMessagesAnother].flatMap { $0 })
}
}
}

public func mergeWithMany(results: [ValidationResult]) -> ValidationResult {
return results.reduce(self) { return $0.merge(result: $1) }
/**
Merges the receiving validation rule with multiple others.
- Parameters:
- results: The results to merge the receiver.
- Returns:
Merged validation result.
*/
public func merge(with results: [ValidationResult]) -> ValidationResult {
return results.reduce(self) { return $0.merge(with: $1) }
}

public static func combine(results: [ValidationResult]) -> ValidationResult {
return ValidationResult.valid.mergeWithMany(results: results)
/**
Merges multiple validation rules together.
- Parameters:
- results: The results to merge.
- Returns:
Merged validation result.
*/
public static func merge(results: [ValidationResult]) -> ValidationResult {
return ValidationResult.valid.merge(with: results)
}
}

Expand Down
28 changes: 28 additions & 0 deletions Validator/Validator/ValidationRule.swift
Expand Up @@ -29,12 +29,40 @@

import Foundation

/**
A type conforming to `ValidationRule` describes how to validate an input of an
associated type, and an error should the validation fail.
*/
public protocol ValidationRule {

/**
The type of input on which the validation is performed, e.g. `String`
*/
associatedtype InputType

/**
The validateInput method validates the associated type against a condition,
returning true if the validation passes.
- Parameters:
- input: The input to be validated.
- Returns:
true if valid.
*/
func validateInput(input: InputType?) -> Bool

/**
An error to to be contained in a failed validation result.
*/
var failureError: ValidationErrorType { get }

}
Expand Down
34 changes: 34 additions & 0 deletions Validator/Validator/ValidationRuleSet.swift
Expand Up @@ -28,18 +28,52 @@
*/
import Foundation

/**
The `ValidationRuleSet` struct contains multiple validation rules with the same
associated type (`InputType`).
*/
public struct ValidationRuleSet<InputType> {

/**
Initialises an empty validation rule set.
*/
public init() {

}

/**
Initialises a `ValidationRuleSet` with a set of validation rules.
- Parameters:
- rules: An array of `ValidationRule`s where the associated type matches
the `InputType` of the rule set under initialization.
*/
public init<R: ValidationRule>(rules: [R]) where R.InputType == InputType {
self.rules = rules.map(AnyValidationRule.init)
}

/**
An array of type erased validation rules.
*/
internal var rules = [AnyValidationRule<InputType>]()


/**
Appends a validation rule to the set.
- Parameters:
- rule: Validation rule to be appended.
*/
public mutating func add<R: ValidationRule>(rule: R) where R.InputType == InputType {
let anyRule = AnyValidationRule(base: rule)
rules.append(anyRule)
Expand Down
43 changes: 37 additions & 6 deletions Validator/Validator/Validator.swift
Expand Up @@ -29,16 +29,47 @@

import Foundation

/**
`Validator` provides a set of static functions to validate a given input
against a validation rule, or multiple validation rules.
*/
public struct Validator {

public static func validate<R: ValidationRule>(input i: R.InputType?, rule r: R) -> ValidationResult {

/**
Validates a given input against a validation rule.
- Parameters:
- input: The input to be validated.
- rule: The validation rule.
- Returns:
A validation result.
*/
public static func validate<R: ValidationRule>(input: R.InputType?, rule: R) -> ValidationResult {

var ruleSet = ValidationRuleSet<R.InputType>()
ruleSet.add(rule: r)
return Validator.validate(input: i, rules: ruleSet)
ruleSet.add(rule: rule)
return Validator.validate(input: input, rules: ruleSet)
}

public static func validate<T>(input i: T?, rules rs: ValidationRuleSet<T>) -> ValidationResult {
let errors = rs.rules.filter { !$0.validateInput(input: i) }.map { $0.failureError }
/**
Validates a given input against mutiple validation rules in a set.
- Parameters:
- input: The input to be validated.
- rules: Multiple validation rules in a set.
- Returns:
A validation result.
*/
public static func validate<T>(input: T?, rules: ValidationRuleSet<T>) -> ValidationResult {
let errors = rules.rules.filter { !$0.validateInput(input: input) }.map { $0.failureError }
return errors.isEmpty ? ValidationResult.valid : ValidationResult.invalid(errors)
}

Expand Down

0 comments on commit 82c39b5

Please sign in to comment.