Skip to content

Commit

Permalink
Adds FilterProcedure (#496)
Browse files Browse the repository at this point in the history
* [OPR-496]: Adds FilterProcedure

* [OPR-496]: Adds filter method for when Result is a sequence
  • Loading branch information
danthorpe committed Oct 8, 2016
1 parent 51ea907 commit 8f877e0
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 13 deletions.
12 changes: 12 additions & 0 deletions ProcedureKit.xcodeproj/project.pbxproj
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
650182C91D8916EC0052CE90 /* DelayProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 650182C81D8916EC0052CE90 /* DelayProcedureTests.swift */; };
6518D5E31D7B3A2800A12EF4 /* Condition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6518D5E21D7B3A2800A12EF4 /* Condition.swift */; };
651FFDF01DA850FE00112220 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 651FFDEF1DA850FE00112220 /* Filter.swift */; };
65245D1B1D72129800340A2D /* QueueTestDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65245D1A1D72129800340A2D /* QueueTestDelegate.swift */; };
65245D1D1D721A7100340A2D /* ProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65245D1C1D721A7100340A2D /* ProcedureTests.swift */; };
65245D1F1D7231DC00340A2D /* CancellationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65245D1E1D7231DC00340A2D /* CancellationTests.swift */; };
Expand Down Expand Up @@ -72,6 +73,8 @@
658A7B4F1D74E54800F897C8 /* GroupStressTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 658A7B4E1D74E54800F897C8 /* GroupStressTests.swift */; };
6591B3001D74954E00C2B57F /* GroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6591B2FE1D74953A00C2B57F /* GroupTests.swift */; };
6591B3021D74980900C2B57F /* GroupTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6591B3011D74980900C2B57F /* GroupTestCase.swift */; };
6593008C1DA8E31900750212 /* MapProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6593008B1DA8E31900750212 /* MapProcedureTests.swift */; };
6593008E1DA8E32D00750212 /* FilterProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6593008D1DA8E32D00750212 /* FilterProcedureTests.swift */; };
65958FD51D96B0AE00F542E2 /* BlockObserverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65958FD41D96B0AE00F542E2 /* BlockObserverTests.swift */; };
659E11A71D9856FB00C5D749 /* Composed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 659E11A61D9856FB00C5D749 /* Composed.swift */; };
659E11AA1D985B9300C5D749 /* ComposedProcedureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 659E11A81D985AA700C5D749 /* ComposedProcedureTests.swift */; };
Expand Down Expand Up @@ -246,6 +249,7 @@
/* Begin PBXFileReference section */
650182C81D8916EC0052CE90 /* DelayProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DelayProcedureTests.swift; path = Tests/DelayProcedureTests.swift; sourceTree = "<group>"; };
6518D5E21D7B3A2800A12EF4 /* Condition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Condition.swift; path = Sources/Condition.swift; sourceTree = "<group>"; };
651FFDEF1DA850FE00112220 /* Filter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = Sources/Filter.swift; sourceTree = "<group>"; };
65245D1A1D72129800340A2D /* QueueTestDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = QueueTestDelegate.swift; path = Sources/Testing/QueueTestDelegate.swift; sourceTree = "<group>"; };
65245D1C1D721A7100340A2D /* ProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProcedureTests.swift; path = Tests/ProcedureTests.swift; sourceTree = "<group>"; };
65245D1E1D7231DC00340A2D /* CancellationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CancellationTests.swift; path = Tests/CancellationTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -308,6 +312,8 @@
658A7B4E1D74E54800F897C8 /* GroupStressTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GroupStressTests.swift; path = "Tests/Stress Tests/GroupStressTests.swift"; sourceTree = "<group>"; };
6591B2FE1D74953A00C2B57F /* GroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GroupTests.swift; path = Tests/GroupTests.swift; sourceTree = "<group>"; };
6591B3011D74980900C2B57F /* GroupTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GroupTestCase.swift; path = Sources/Testing/GroupTestCase.swift; sourceTree = "<group>"; };
6593008B1DA8E31900750212 /* MapProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MapProcedureTests.swift; path = Tests/MapProcedureTests.swift; sourceTree = "<group>"; };
6593008D1DA8E32D00750212 /* FilterProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FilterProcedureTests.swift; path = Tests/FilterProcedureTests.swift; sourceTree = "<group>"; };
65958FD41D96B0AE00F542E2 /* BlockObserverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockObserverTests.swift; path = Tests/BlockObserverTests.swift; sourceTree = "<group>"; };
659E11A61D9856FB00C5D749 /* Composed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Composed.swift; path = Sources/Composed.swift; sourceTree = "<group>"; };
659E11A81D985AA700C5D749 /* ComposedProcedureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComposedProcedureTests.swift; path = Tests/ComposedProcedureTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -485,9 +491,11 @@
659E11A81D985AA700C5D749 /* ComposedProcedureTests.swift */,
65403AB71D7C453200D6036B /* ConditionTests.swift */,
650182C81D8916EC0052CE90 /* DelayProcedureTests.swift */,
6593008D1DA8E32D00750212 /* FilterProcedureTests.swift */,
65245D201D72345000340A2D /* FinishingTests.swift */,
6591B2FE1D74953A00C2B57F /* GroupTests.swift */,
65245D241D724FC200340A2D /* LoggerTests.swift */,
6593008B1DA8E31900750212 /* MapProcedureTests.swift */,
65881B781D880ACB00C212C8 /* MutualExclusivityTests.swift */,
652AFD381D8C5BC000793AF3 /* NegatedConditionTests.swift */,
6583F95E1D8C4C7F00000A8D /* NoFailedDependenciesConditionTests.swift */,
Expand Down Expand Up @@ -712,6 +720,7 @@
65A63B121DA03D1C00E90B9D /* Capability.swift */,
659E11A61D9856FB00C5D749 /* Composed.swift */,
653EBBB91D88AFA800F4DB9F /* Delay.swift */,
651FFDEF1DA850FE00112220 /* Filter.swift */,
65245D261D7258E400340A2D /* Group.swift */,
654FAFFC1D7CD5EA002FA74D /* Map.swift */,
659E11AB1D9862B900C5D749 /* Repeat.swift */,
Expand Down Expand Up @@ -1281,6 +1290,7 @@
files = (
652AFD361D8C5A5E00793AF3 /* NegatedCondition.swift in Sources */,
65A63B131DA03D1C00E90B9D /* Capability.swift in Sources */,
651FFDF01DA850FE00112220 /* Filter.swift in Sources */,
65A63B0F1D9FFDAD00E90B9D /* Retry.swift in Sources */,
65A2D7FB1D6852A500FB067C /* BlockObservers.swift in Sources */,
65245D231D723A6B00340A2D /* Logging.swift in Sources */,
Expand Down Expand Up @@ -1327,9 +1337,11 @@
65403ABE1D7C9E7600D6036B /* ResultInjectionTests.swift in Sources */,
65245D1F1D7231DC00340A2D /* CancellationTests.swift in Sources */,
655594F11D9E482D00B08990 /* RepeatProcedureTests.swift in Sources */,
6593008E1DA8E32D00750212 /* FilterProcedureTests.swift in Sources */,
659E11AA1D985B9300C5D749 /* ComposedProcedureTests.swift in Sources */,
6583F95F1D8C4C7F00000A8D /* NoFailedDependenciesConditionTests.swift in Sources */,
65245D211D72345000340A2D /* FinishingTests.swift in Sources */,
6593008C1DA8E31900750212 /* MapProcedureTests.swift in Sources */,
65403AB81D7C453200D6036B /* ConditionTests.swift in Sources */,
65A0CB271D7D4CF1008FB37C /* BlockProcedureTests.swift in Sources */,
65A63B151DA04FDB00E90B9D /* CapabilityTests.swift in Sources */,
Expand Down
47 changes: 47 additions & 0 deletions Sources/Filter.swift
@@ -0,0 +1,47 @@
//
// ProcedureKit
//
// Copyright © 2016 ProcedureKit. All rights reserved.
//

import Foundation

public class FilterProcedure<Element>: Procedure, ResultInjectionProtocol {

public var requirement: AnySequence<Element>
public var result: Array<Element> = []
public let isIncluded: (Element) throws -> Bool

public init<S: Sequence>(source: S, isIncluded block: @escaping (Element) throws -> Bool) where S.Iterator.Element == Element, S.SubSequence: Sequence, S.SubSequence.Iterator.Element == Element, S.SubSequence.SubSequence == S.SubSequence {
requirement = AnySequence(source)
isIncluded = block
super.init()
}

public convenience init(isIncluded block: @escaping (Element) throws -> Bool) {
self.init(source: [], isIncluded: block)
}

public override func execute() {
var finishingError: Error? = nil
defer { finish(withError: finishingError) }
do {
result = try requirement.filter(isIncluded)
}
catch { finishingError = error }
}
}

public extension ProcedureProtocol where Self: ResultInjectionProtocol, Self.Result: Sequence {

func filter(includeElement: @escaping (Result.Iterator.Element) throws -> Bool) -> FilterProcedure<Result.Iterator.Element> {
let filter = FilterProcedure(isIncluded: includeElement)
filter.inject(dependency: self) { filter, dependency, errors in
guard errors.isEmpty else {
filter.cancel(withError: ProcedureKitError.dependency(finishedWithErrors: errors)); return
}
filter.requirement = AnySequence(Array(dependency.result))
}
return filter
}
}
4 changes: 1 addition & 3 deletions Sources/Map.swift
Expand Up @@ -29,9 +29,7 @@ public class MapProcedure<Requirement, Result>: Procedure, ResultInjectionProtoc
do {
result = try transform(requirement)
}
catch {
finishingError = error
}
catch { finishingError = error }
}
}

Expand Down
10 changes: 0 additions & 10 deletions Tests/BlockProcedureTests.swift
Expand Up @@ -8,16 +8,6 @@ import XCTest
import TestingProcedureKit
@testable import ProcedureKit

class MapProcedureTests: ProcedureKitTestCase {

func test__requirement_is_mapped_to_result() {
let timesTwo = MapProcedure<Int, Int> { return $0 * 2 }
timesTwo.requirement = 2
wait(for: timesTwo)
XCTAssertEqual(timesTwo.result, 4)
}
}

class BlockProcedureTests: ProcedureKitTestCase {

func test__block_executes() {
Expand Down
64 changes: 64 additions & 0 deletions Tests/FilterProcedureTests.swift
@@ -0,0 +1,64 @@
//
// ProcedureKit
//
// Copyright © 2016 ProcedureKit. All rights reserved.
//

import XCTest
import TestingProcedureKit
@testable import ProcedureKit

class NumbersProcedure: Procedure, ResultInjectionProtocol {

var requirement: Void = ()
var result: Array<Int> = []
var error: Error? = nil

init(error: Error? = nil) {
self.error = error
super.init()
}

override func execute() {
if let error = error {
finish(withError: error)
}
else {
result = [0, 1, 2, 3, 4, 5 , 6 , 7, 8, 9]
finish()
}
}
}

class FilterProcedureTests: ProcedureKitTestCase {

func test__requirement_is_filtered_to_result() {
let evenOnly = FilterProcedure(source: [0,1,2,3,4,5,6,7]) { $0 % 2 == 0 }
wait(for: evenOnly)
XCTAssertProcedureFinishedWithoutErrors(evenOnly)
XCTAssertEqual(evenOnly.result, [0,2,4,6])
}

func test__finishes_with_error_if_block_throws() {
let evenOnly = FilterProcedure(source: [0,1,2,3,4,5,6,7]) { _ in throw TestError() }
wait(for: evenOnly)
XCTAssertProcedureFinishedWithErrors(evenOnly, count: 1)
}

func test__filter_dependency_which_finishes_without_errors() {
let numbers = NumbersProcedure()
let filtered = numbers.filter { $0 % 2 == 0 }
wait(for: numbers, filtered)
XCTAssertProcedureFinishedWithoutErrors(numbers)
XCTAssertProcedureFinishedWithoutErrors(filtered)
XCTAssertEqual(filtered.result, [0,2,4,6,8])
}

func test__filter_dependency_which_finishes_with_errors() {
let numbers = NumbersProcedure(error: TestError())
let filtered = numbers.filter { $0 % 2 == 0 }
wait(for: numbers, filtered)
XCTAssertProcedureFinishedWithErrors(numbers, count: 1)
XCTAssertProcedureCancelledWithErrors(filtered, count: 1)
}
}
19 changes: 19 additions & 0 deletions Tests/MapProcedureTests.swift
@@ -0,0 +1,19 @@
//
// ProcedureKit
//
// Copyright © 2016 ProcedureKit. All rights reserved.
//

import XCTest
import TestingProcedureKit
@testable import ProcedureKit

class MapProcedureTests: ProcedureKitTestCase {

func test__requirement_is_mapped_to_result() {
let timesTwo = MapProcedure<Int, Int> { return $0 * 2 }
timesTwo.requirement = 2
wait(for: timesTwo)
XCTAssertEqual(timesTwo.result, 4)
}
}

0 comments on commit 8f877e0

Please sign in to comment.