Latest 0.0.9
Homepage https://github.com/vbmania/RxValidator
License MIT
Platforms ios 8.0, watchos 2.0, tvos 9.0, requires ARC
Dependencies RxSwift, RxCocoa
Frameworks UIKit, Foundation
Authors

License
Platform
Swift
Version
Build Status
codecov.io

Easy to Use, Read, Extensible, Flexible Validation Checker.

It can use without Rx.

Requirements

RxValidator is written in Swift 4. Compatible with iOS 8.0+

Installation

CocoaPods

RxValidator is available through CocoaPods. To install
it, simply add the following line to your Podfile:

pod 'RxValidator'

At a Glance

You just use like this:


//without Rx
Validate.to(TargetValue)
    .validate(condition)
        ...
    .validate(condition)
    .asObservable() or .check()

//with Rx
observable
    .validate(condition)
        ...
    .validate(condition)
    .subscribe(...)

Usage

String

“`swift {.line-numbers}

Validate.to("word is not empty")
.validate(StringShouldNotBeEmpty())
.check()
// result -> RxValidatorResult.valid

//multiple condition
Validate.to("[email protected]")
.validate(StringShouldNotBeEmpty())
.validate(StringIsNotOverflowThen(maxLength: 50))
.validate(StringShouldBeMatch("[a-z][email protected][a-z]+.[a-z]+"))
.check()
// result -> RxValidatorResult.valid


### Date
```swift {.line-numbers}

let targetDate: Date //2018-05-05
let sameTargetDate: Date
let afterTargetDate: Date
let beforeTargetDate: Date

Validate.to(Date())
    .validate(.shouldEqualTo(date: sameTargetDate))             //(1)
    .validate(.shouldAfterOrSameThen(date: sameTargetDate))     //(2)
    .validate(.shouldBeforeOrSameThen(date: sameTargetDate))    //(3)
    .validate(.shouldBeforeOrSameThen(date: afterTargetDate))   //(4)
    .validate(.shouldBeforeThen(date: afterTargetDate))         //(5)
    .validate(.shouldAfterOrSameThen(date: beforeTargetDate))   //(6)
    .validate(.shouldAfterThen(date: beforeTargetDate))         //(7)
    .check()

    // check() result

    // valid result  -> RxValidatorResult.valid

    // (1) not valid -> RxValidatorResult.notEqualDate
    // (2) not valid -> RxValidatorResult.notAfterDate
    // (3) not valid -> RxValidatorResult.notBeforeDate
    // (4) not valid -> RxValidatorResult.notBeforeDate
    // (5) not valid -> RxValidatorResult.notBeforeDate
    // (6) not valid -> RxValidatorResult.notAfterDate
    // (7) not valid -> RxValidatorResult.notAfterDate

Int

“`swift {.line-numbers}
Validate.to(2)
.validate(NumberShouldBeEven())
.check()
//.valid

Validate.to(1)
.validate(NumberShouldBeEven())
.check()
//.notEvenNumber


## Working with RxSwift
### String
```swift {.line-numbers}

Validate.to("word is not empty")
    .validate(StringShouldNotBeEmpty())
    .asObservable()
    .subscribe(onNext: { value in
        print(value)
    //print("word is not empty")
    })
    .disposed(by: disposeBag)

Validate.to("word is not empty")
    .validate(StringShouldNotBeEmpty())
    .asObservable()
    .map { $0 + "!!" }
    .bind(to: anotherObservableBinder)
    .disposed(by: disposeBag)

//Multiple condition
Validate.to("[email protected]")
    .validate(StringShouldNotBeEmpty())                         //(1)
    .validate(StringIsNotOverflowThen(maxLength: 50))           //(2)
    .validate(StringShouldBeMatch("[a-z][email protected][a-z]+\.[a-z]+"))    //(3)
    .asObservable()
    .subscribe(onNext: { value in
        print(value)
        //print("[email protected]")
    },
    onError: { error in
        let validError = RxValidatorResult.determine(error: error)
        // (1) validError -> RxValidatorResult.stringIsEmpty
        // (2) validError -> RxValidatorResult.stringIsOverflow
        // (3) validError -> RxValidatorResult.stringIsNotMatch
    })
    .disposed(by: disposeBag)

Int

“`swift {.line-numbers}
Validate.to(2)
.validate(NumberShouldBeEven())
.asObservable()
.subscribe(onNext: { value in
print(value)
//print(2)
})
.disposed(by: disposeBag)

Validate.to(1)
.validate(NumberShouldBeEven())
.asObservable()
.subscribe(onNext: { value in
print(value)
//print(1)
},
onError: { error in
let validError = RxValidatorResult.determine(error: error)
//validError -> RxValidatorResult.notEvenNumber
})
.disposed(by: disposeBag)


### Date
```swift {.line-numbers}

let targetDate: Date //2018-05-05
let sameTargetDate: Date
let afterTargetDate: Date
let beforeTargetDate: Date

Validate.to(Date())
    .validate(.shouldEqualTo(date: sameTargetDate))             //(1)
    .validate(.shouldAfterOrSameThen(date: sameTargetDate))     //(2)
    .validate(.shouldBeforeOrSameThen(date: sameTargetDate))    //(3)
    .validate(.shouldBeforeOrSameThen(date: afterTargetDate))   //(4)
    .validate(.shouldBeforeThen(date: afterTargetDate))         //(5)
    .validate(.shouldAfterOrSameThen(date: beforeTargetDate))   //(6)
    .validate(.shouldAfterThen(date: beforeTargetDate))         //(7)
    .asObservable()
    .subscribe(onNext: { value in
        print(value) //print("2018-05-05")
    }, onError: { error in
        let validError = RxValidatorResult.determine(error: error)

        // (1) validError -> RxValidatorResult.notEqualDate
        // (2) validError -> RxValidatorResult.notAfterDate
        // (3) validError -> RxValidatorResult.notBeforeDate
        // (4) validError -> RxValidatorResult.notBeforeDate
        // (5) validError -> RxValidatorResult.notBeforeDate
        // (6) validError -> RxValidatorResult.notAfterDate
        // (7) validError -> RxValidatorResult.notAfterDate
    })
    .disposed(by: disposeBag)

Chaining from Observable

“`swift {.line-numbers}

textField.rx.text
.filterNil()
.validate(StringIsAlwaysPass())
.subscribe(onNext: { (text) in
print(text)
})
.disposed(by: disposeBag)

let text = PublishSubject()
text
.validate(StringIsAlwaysPass())
.subscribe(onNext: { (text) in
print(text)
})
.disposed(by: disposeBag)


## Instant Condition Validation
```swift

Validate.to("swift")
    .validate({ $0 == "objc" })
    .check()

Validate.to(7)
    .validate({ $0 > 10 })
    .check()

Validate.to(Date())
    .validate({ !$0.isToday })
    .check()

Validate.to("swift")
    .validate({ $0 == "objc" }, message: "This is not swift")
    .check()

Validate.to(7)
    .validate({ $0 > 10 }, message: "Number is too small.")
    .check()

Validate.to(Date())
    .validate({ !$0.isToday }, message: "It is today!!")
    .check()

ResultType

“`swift {.line-numbers}
enum RxValidatorResult

case notValid
case notValidWithMessage(message: String)
case notValidWithCode(code: Int)

case undefinedError

case stringIsOverflow
case stringIsEmpty
case stringIsNotMatch

case notEvenNumber

case invalidateDateTerm
case notBeforeDate
case notAfterDate
case notEqualDate

## Working with ReactorKit (http://reactorkit.io)
```swift {.line-numbers}
func mutate(action: Action) -> Observable<Mutation> {
....

case let .changeTitle(title):
  return Validate.to(title)
    .validate(StringIsNotOverflowThen(maxLength: TITLE_MAX_LENGTH))
    .asObservable()
    .flatMap { Observable<Mutation>.just(.updateTitle(title: $0)) }
    .catchError({ (error) -> Observable<Mutation> in
        let validError = ValidationTargetErrorType.determine(error: error)
        return Observable<Mutation>.just(.setTitleValidateError(validError, title))
    })

....

Supported Validation Rules

//String
StringShouldNotBeEmpty()
StringIsNotOverflowThen(maxLength: Int)
StringShouldBeMatch("regex string")

//Int
NumberShouldBeEven()

//Date
DateValidatorType.shouldEqualTo(Date)
DateValidatorType.shouldBeforeThen(Date)
DateValidatorType.shouldBeforeOrSameThen(Date)
DateValidatorType.shouldAfterThen(Date)
DateValidatorType.shouldAfterOrSameThen(Date)
DateValidatorType.shouldBeCloseDates(date: Date, termOfDays: Int)

Make custom ValidationRule like this:

//String Type
class MyCustomStringValidationRule: StringValidatorType {
    func validate(_ value: String) throws {
        if {notValidCondition} {
            throw RxValidatorResult.notValidate(code: 999) //'code' must be defined your self.  
        }
    }
}

//Int Type
class MyCustomIntValidationRule: IntValidatorType {
    func validate(_ value: Int) throws {
        if {notValidCondition} {
            throw RxValidatorResult.notValidate(code: 999) //'code' must be defined your self.  
        }
    }
}

I want to be…

  • More Built-in Validation Rules. (Help me. Welcome to PR.)
  • Support More Type (Array, Float, Double, etc)
  • More Flexible Code via Generics.

Latest podspec

{
    "name": "RxValidator",
    "version": "0.0.9",
    "summary": "Simple, Extensable, Flexable Validation Checker",
    "homepage": "https://github.com/vbmania/RxValidator",
    "license": {
        "type": "MIT",
        "file": "LICENSE"
    },
    "authors": {
        "GeumSang Yoo": "[email protected]"
    },
    "source": {
        "git": "https://github.com/vbmania/RxValidator.git",
        "tag": "v0.0.9"
    },
    "source_files": "Sources/**/*.swift",
    "frameworks": [
        "UIKit",
        "Foundation"
    ],
    "requires_arc": true,
    "swift_version": "4.1",
    "dependencies": {
        "RxSwift": [
            ">= 4.1.0"
        ],
        "RxCocoa": [
            ">= 4.1.0"
        ]
    },
    "platforms": {
        "ios": "8.0",
        "watchos": "2.0",
        "tvos": "9.0"
    }
}

Pin It on Pinterest

Share This