GitXplorerGitXplorer
a

Typical

public
3 stars
0 forks
0 issues

Commits

List of commits on branch master.
Unverified
2bdc34cd49195e432bbe12e411cb875c8f122e2f

Check Xcode 13

aatetlaw committed 3 years ago
Unverified
0a915839d33236328749d061180d0fb25e7dddc0

Xcode 11, Swift 5

aatetlaw committed 5 years ago
Unverified
42fa9ec0194ccf4cb2b12a983432e3d5269dc3c0

Update .gitignore, project file and tests

aatetlaw committed 6 years ago
Unverified
c7f651bbc69a8d36d48f97e84b9e0043f1908e35

Merge branch 'master' of github.com:atetlaw/Typical

aatetlaw committed 6 years ago
Unverified
beecf265a4089cb8444d48284b9f0c2a401aa6a0

Update for Xcode 10

aatetlaw committed 6 years ago
Unverified
cdb0639a8dfaeaf59b27b8856b2d593fe8709c12

Update README.md

aatetlaw committed 8 years ago

README

The README file for this repository.

Typical

Typical is a Swift micro-framework for wrapping the closure (Subject) -> Bool into a composable form.

Introduction

A closure with the form (Subject) -> Bool is very useful for matching purposes, where Subject is the type you want to test. Typical is a protocol that adds operators and Collection methods so you can join multiple closures together, with custom matching logic, and create a single instance that is also in the form of (Subject) -> Bool.

public protocol Typical {
    associatedtype Subject
    func test(_ subject: Subject) -> Bool
    init(_ predicate: @escaping (Subject) -> Bool)
}

Example

If you want to match instances of Int with several test conditions that you can define in the form of (Int) -> Bool:

{ $0 == 8 }
{ $0 > 5 }
{ $0 < 15 }

First create a type that can store the closure in a variable and implement Typical:

struct TypicalInt: Typical {
    typealias Subject = Int
    private var closure: (Int) -> Bool
    init(_ test: @escaping (Int) -> Bool) {
        closure = test
    }
    func test(_ s: Int) -> Bool {
        return closure(s)
    }
}

Now you can create 3 instances of your struct:

let isEqualTo8 = TypicalInt { $0 == 8 }
let isGreaterThan5 = TypicalInt { $0 > 5 }
let isLessThan15 = TypicalInt { $0 < 15 }

Since the struct implements Typical we can join them all together to make 1 struct that combines the logic of all the matches. Here we match the int if it's greater than 5, less than 15, but not equal to 8:

let selectTheRightInt = isGreaterThan5 && isLessThan15 && !isEqualTo8

Now we can test integers by using selectTheRightInt.test(6) (returns true). Which is handy if you have an array of Int values:

let ints = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
ints.filter(selectTheRightInt.test)

This will return [6,7,9,10,11,12,13,14].

The framework also has a handy class, to make implementing Typical easy:

public final class Matching<T>: Typical {
    public typealias Subject = T
    private var predicate: (T) -> Bool
    public init(_ test: @escaping (T) -> Bool) {
        predicate = test
    }
    public func test(_ s: T) -> Bool {
        return predicate(s)
    }
}

So instead of my custom struct I could have just used:

typealias TypicalInt = Matching<Int>

Typical includes the &&, ||, and ! operators, as well as a withAll and withAny property on collections of Typical instances. There are also static methods withAll and withAny that take a variable list of Typical instances, as well as a pick method for ternary operator-style logic.

Why?

It came about because I wanted to have reusable matching logic in unit tests. I was testing instances of URLRequest and created a bunch of operators to test the hostname, scheme, path, querystring etc. I've inlcuded some examples in the unit tests.

It was also bit of fun, since I was trying to learn Swift generics. I also think Swift micro-frameworks are pretty cool, and I wanted to write one! In reality it's a silly little protocol with limited functionalty, but who knows, someone else might find it useful too.