Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Example/LithoOperators.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
64A6CEB62656E92C00586211 /* TupleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A6CEB52656E92C00586211 /* TupleTests.swift */; };
980FCB7E25800FEF00C5798E /* ConditionalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 980FCB7D25800FEF00C5798E /* ConditionalTests.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -52,6 +53,7 @@
607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
607FACE51AFB9204008FA782 /* LithoOperators_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LithoOperators_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
64A6CEB52656E92C00586211 /* TupleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TupleTests.swift; sourceTree = "<group>"; };
980FCB7D25800FEF00C5798E /* ConditionalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionalTests.swift; sourceTree = "<group>"; };
AB7EAE1E3A677B659E95750C /* LithoOperators.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LithoOperators.podspec; path = ../LithoOperators.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
AD16122D9FD783847B990AAD /* Pods-LithoOperators_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LithoOperators_Example.debug.xcconfig"; path = "Target Support Files/Pods-LithoOperators_Example/Pods-LithoOperators_Example.debug.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -142,6 +144,7 @@
49B5962224E43C3A00CE1E42 /* LiftTests.swift */,
49B5962024E43BC100CE1E42 /* OptionalsTests.swift */,
980FCB7D25800FEF00C5798E /* ConditionalTests.swift */,
64A6CEB52656E92C00586211 /* TupleTests.swift */,
607FACE91AFB9204008FA782 /* Supporting Files */,
);
path = Tests;
Expand Down Expand Up @@ -361,6 +364,7 @@
files = (
49B5962324E43C3A00CE1E42 /* LiftTests.swift in Sources */,
49B5961F24E43B9000CE1E42 /* ArrayTests.swift in Sources */,
64A6CEB62656E92C00586211 /* TupleTests.swift in Sources */,
980FCB7E25800FEF00C5798E /* ConditionalTests.swift in Sources */,
49B5962124E43BC100CE1E42 /* OptionalsTests.swift in Sources */,
49B5962524E43C5B00CE1E42 /* HigherOrderTests.swift in Sources */,
Expand Down
59 changes: 0 additions & 59 deletions Example/Tests/ArrayTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,65 +86,6 @@ class ArrayTests: XCTestCase {
XCTAssert(newArray.count == 2)
}

func testFzip2Args() {
let getCount: ([String]) -> Int = { $0.count }
let getCountAndFirst: ([String]) -> (Int, String?) = fzip(getCount, firstElement)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
}

func testFzip3Args() {
let getCount: ([String]) -> Int = { $0.count }
let getWordCountOfFirst: ([String]) -> Int? = { firstElement($0)?.count }
let getCountAndFirst: ([String]) -> (Int, String?, Int?) = fzip(getCount, firstElement, getWordCountOfFirst)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
XCTAssertEqual(countAndFirst.2!, 14)
}

func testFzip4Args() {
let getCount: ([String]) -> Int = { $0.count }
let getWordCountOfFirst: ([String]) -> Int? = { firstElement($0)?.count }
let getWordCountOfSecond: ([String]) -> Int = { $0[1].count }
let getCountAndFirst: ([String]) -> (Int, String?, Int?, Int) = fzip(getCount, firstElement, getWordCountOfFirst, getWordCountOfSecond)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
XCTAssertEqual(countAndFirst.2!, 14)
XCTAssertEqual(countAndFirst.3, 11)
}

func testFzip5Args() {
let getCount: ([String]) -> Int = { $0.count }
let getWordCountOfFirst: ([String]) -> Int? = { firstElement($0)?.count }
let getWordCountOfSecond: ([String]) -> Int = { $0[1].count }
let second: ([String]) -> String = { $0[1] }
let getCountAndFirst: ([String]) -> (Int, String?, Int?, Int, String) = fzip(getCount, firstElement, getWordCountOfFirst, getWordCountOfSecond, second)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
XCTAssertEqual(countAndFirst.2!, 14)
XCTAssertEqual(countAndFirst.3, 11)
XCTAssertEqual(countAndFirst.4, "Thryv, Inc.")
}

func testFzip6Args() {
let getCount: ([String]) -> Int = { $0.count }
let getWordCountOfFirst: ([String]) -> Int? = { firstElement($0)?.count }
let getWordCountOfSecond: ([String]) -> Int = { $0[1].count }
let second: ([String]) -> String = { $0[1] }
let getCountAndFirst: ([String]) -> (Int, String?, Int?, Int, String, String?) = fzip(getCount, firstElement, getWordCountOfFirst, getWordCountOfSecond, second, firstElement)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
XCTAssertEqual(countAndFirst.2!, 14)
XCTAssertEqual(countAndFirst.3, 11)
XCTAssertEqual(countAndFirst.4, "Thryv, Inc.")
XCTAssertEqual(countAndFirst.5!, "LithoByte, Co.")
}

func testSortBy() {
struct IntHolder {
var int: Int
Expand Down
2 changes: 1 addition & 1 deletion Example/Tests/LiftTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class LiftTests: XCTestCase {
struct User {
var name: String
}
var user = User(name: "Calvin")
let user = User(name: "Calvin")
let screemName: (WritableKeyPath<User, String>) -> (User) -> User = {
((^$0) { $0 + "!" })
}
Expand Down
130 changes: 130 additions & 0 deletions Example/Tests/TupleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//
// TupleTests.swift
// LithoOperators_Tests
//
// Created by Calvin Collins on 5/20/21.
// Copyright © 2021 CocoaPods. All rights reserved.
//

import XCTest
import Prelude
@testable import LithoOperators

class TupleTests: XCTestCase {
let stringArray = [lithobyte, thryv]
let coArray = [Company(name: lithobyte), Company(name: thryv)]

func testFzip2Args() {
let getCount: ([String]) -> Int = { $0.count }
let getCountAndFirst: ([String]) -> (Int, String?) = fzip(getCount, firstElement)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
}

func testFzip3Args() {
let getCount: ([String]) -> Int = { $0.count }
let getWordCountOfFirst: ([String]) -> Int? = { firstElement($0)?.count }
let getCountAndFirst: ([String]) -> (Int, String?, Int?) = fzip(getCount, firstElement, getWordCountOfFirst)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
XCTAssertEqual(countAndFirst.2!, 14)
}

func testFzip4Args() {
let getCount: ([String]) -> Int = { $0.count }
let getWordCountOfFirst: ([String]) -> Int? = { firstElement($0)?.count }
let getWordCountOfSecond: ([String]) -> Int = { $0[1].count }
let getCountAndFirst: ([String]) -> (Int, String?, Int?, Int) = fzip(getCount, firstElement, getWordCountOfFirst, getWordCountOfSecond)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
XCTAssertEqual(countAndFirst.2!, 14)
XCTAssertEqual(countAndFirst.3, 11)
}

func testFzip5Args() {
let getCount: ([String]) -> Int = { $0.count }
let getWordCountOfFirst: ([String]) -> Int? = { firstElement($0)?.count }
let getWordCountOfSecond: ([String]) -> Int = { $0[1].count }
let second: ([String]) -> String = { $0[1] }
let getCountAndFirst: ([String]) -> (Int, String?, Int?, Int, String) = fzip(getCount, firstElement, getWordCountOfFirst, getWordCountOfSecond, second)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
XCTAssertEqual(countAndFirst.2!, 14)
XCTAssertEqual(countAndFirst.3, 11)
XCTAssertEqual(countAndFirst.4, "Thryv, Inc.")
}

func testFzip6Args() {
let getCount: ([String]) -> Int = { $0.count }
let getWordCountOfFirst: ([String]) -> Int? = { firstElement($0)?.count }
let getWordCountOfSecond: ([String]) -> Int = { $0[1].count }
let second: ([String]) -> String = { $0[1] }
let getCountAndFirst: ([String]) -> (Int, String?, Int?, Int, String, String?) = fzip(getCount, firstElement, getWordCountOfFirst, getWordCountOfSecond, second, firstElement)
let countAndFirst = getCountAndFirst(stringArray)
XCTAssertEqual(countAndFirst.0, 2)
XCTAssertEqual(countAndFirst.1!, "LithoByte, Co.")
XCTAssertEqual(countAndFirst.2!, 14)
XCTAssertEqual(countAndFirst.3, 11)
XCTAssertEqual(countAndFirst.4, "Thryv, Inc.")
XCTAssertEqual(countAndFirst.5!, "LithoByte, Co.")
}

func testTupleUnCurry() {
var firstCalled = false
var secondCalled = false
let firstCalledSetter: (Int) -> Void = {
if $0 == 1 {
firstCalled = true
}
}
let secondCalledSetter: (String) -> Void = {
if $0 == "lithobyte" {
secondCalled = true
}
}

let firstSecondSetter = tupleUncurry(firstCalledSetter, secondCalledSetter)
firstSecondSetter(1, "lithobyte")

XCTAssertTrue(firstCalled)
XCTAssertTrue(secondCalled)
}

func testTupleUncurry3Args() {
var firstCalled = false
var secondCalled = false
var thirdCalled = false
let firstCalledSetter: (Int) -> Void = {
if $0 == 1 {
firstCalled = true
}
}
let secondCalledSetter: (String) -> Void = {
if $0 == "lithobyte" {
secondCalled = true
}
}
let thirdCalledSetter: (Bool) -> Void = {
thirdCalled = $0
}
let allSetter = tupleUncurry(firstCalledSetter, secondCalledSetter, thirdCalledSetter)
allSetter(1, "lithobyte", true)

XCTAssertTrue(firstCalled)
XCTAssertTrue(secondCalled)
XCTAssertTrue(thirdCalled)
}

func testTupleMap() {
let equalsOne: (Int) -> Bool = { $0 == 1 }
let count: (String) -> Int = { $0.count }
let zipFn = tupleMap(equalsOne, count)
let tuple1 = zipFn(1, "hello")
XCTAssertTrue(tuple1.0)
XCTAssertEqual(tuple1.1, 5)
}
}
34 changes: 34 additions & 0 deletions Sources/LithoOperators/Classes/LithoOperators.swift
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,40 @@ public func second<A, B, C>(_ f: @escaping (B) -> C) -> ((A, B)) -> (A, C) {
}
}

/**
This function takes in two functions that return Void, and creates a function that takes in the inputs for both functions and runs the functions on their respective input
*/

public func tupleUncurry<T, U>(_ f: @escaping (T) -> Void, _ g: @escaping (U) -> Void) -> (T, U) -> Void {
return { t, u in
f(t)
g(u)
}
}

public func tupleUncurry<T, U, V>(_ f: @escaping (T) -> Void, _ g: @escaping (U) -> Void, _ h: @escaping (V) -> Void) -> (T, U, V) -> Void {
return { t, u, v in
f(t)
g(u)
h(v)
}
}

/**
This version works similar to the above tupleMap but allows the input functions to have return values, creates a function that returns a tuple of those values (i.e. a mix between tupleMap and fzip)
*/
public func tupleMap<T, U, V, W>(_ f: @escaping (T) -> V, _ g: @escaping (U) -> W) -> (T, U) -> (V, W) {
return { t, u in
(f(t), g(u))
}
}

public func tupleMap<T, U, V, W, X, Y>(_ f: @escaping (T) -> W, _ g: @escaping (U) -> X, _ h: @escaping (V) -> Y) -> (T, U, V) -> (W, X, Y) {
return { t, u, v in
(f(t), g(u), h(v))
}
}

/**
This function zips together the outputs of functions into a tuple. Very convenient when creating a view from a single model while
keeping the two decoupled.
Expand Down