From 82c39b5eddabe3703e40e0f8965ac628bca08399 Mon Sep 17 00:00:00 2001 From: Adam Waite Date: Sat, 29 Oct 2016 21:27:07 +0100 Subject: [PATCH] First few files --- Validator/Validator/ValidationResult.swift | 82 +++++++++++++++++++-- Validator/Validator/ValidationRule.swift | 28 +++++++ Validator/Validator/ValidationRuleSet.swift | 34 +++++++++ Validator/Validator/Validator.swift | 43 +++++++++-- 4 files changed, 173 insertions(+), 14 deletions(-) diff --git a/Validator/Validator/ValidationResult.swift b/Validator/Validator/ValidationResult.swift index 221dbd3..03ebd89 100644 --- a/Validator/Validator/ValidationResult.swift +++ b/Validator/Validator/ValidationResult.swift @@ -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) } } diff --git a/Validator/Validator/ValidationRule.swift b/Validator/Validator/ValidationRule.swift index 8622bf1..ed7a9f7 100644 --- a/Validator/Validator/ValidationRule.swift +++ b/Validator/Validator/ValidationRule.swift @@ -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 } } diff --git a/Validator/Validator/ValidationRuleSet.swift b/Validator/Validator/ValidationRuleSet.swift index d0855ca..0f858e4 100644 --- a/Validator/Validator/ValidationRuleSet.swift +++ b/Validator/Validator/ValidationRuleSet.swift @@ -28,18 +28,52 @@ */ import Foundation +/** + + The `ValidationRuleSet` struct contains multiple validation rules with the same + associated type (`InputType`). + + */ public struct ValidationRuleSet { + /** + + 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(rules: [R]) where R.InputType == InputType { self.rules = rules.map(AnyValidationRule.init) } + /** + + An array of type erased validation rules. + + */ internal var rules = [AnyValidationRule]() + + /** + + Appends a validation rule to the set. + + - Parameters: + - rule: Validation rule to be appended. + + */ public mutating func add(rule: R) where R.InputType == InputType { let anyRule = AnyValidationRule(base: rule) rules.append(anyRule) diff --git a/Validator/Validator/Validator.swift b/Validator/Validator/Validator.swift index 2e6eecc..9535f1d 100644 --- a/Validator/Validator/Validator.swift +++ b/Validator/Validator/Validator.swift @@ -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(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(input: R.InputType?, rule: R) -> ValidationResult { + var ruleSet = ValidationRuleSet() - 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(input i: T?, rules rs: ValidationRuleSet) -> 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(input: T?, rules: ValidationRuleSet) -> ValidationResult { + let errors = rules.rules.filter { !$0.validateInput(input: input) }.map { $0.failureError } return errors.isEmpty ? ValidationResult.valid : ValidationResult.invalid(errors) }