Skip to content

Commit

Permalink
Merge pull request #150 from spotify/connectable-map
Browse files Browse the repository at this point in the history
Add `Connectable.map` to `MobiusExtras`
  • Loading branch information
jeppes authored Apr 20, 2020
2 parents 3c8c7c0 + a031592 commit 6ef1e94
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 13 deletions.
10 changes: 10 additions & 0 deletions Mobius.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
025BB529244DA65100E80BD2 /* ConnectableMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025BB528244DA65100E80BD2 /* ConnectableMap.swift */; };
025BB52C244DA6BF00E80BD2 /* ConnectableMapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025BB52A244DA68500E80BD2 /* ConnectableMapTests.swift */; };
025BB52D244DA6C400E80BD2 /* ConnectableMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025BB528244DA65100E80BD2 /* ConnectableMap.swift */; };
02BED1BB21DD20D20093FB47 /* ConnectableContramap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9CE80421197FE000DB79A7 /* ConnectableContramap.swift */; };
02C4061D2373078400BD7ED8 /* EffectExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C4061C2373078400BD7ED8 /* EffectExecutor.swift */; };
02C40621237422EF00BD7ED8 /* EffectRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C40620237422EF00BD7ED8 /* EffectRouter.swift */; };
Expand Down Expand Up @@ -292,6 +295,8 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
025BB528244DA65100E80BD2 /* ConnectableMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectableMap.swift; sourceTree = "<group>"; };
025BB52A244DA68500E80BD2 /* ConnectableMapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectableMapTests.swift; sourceTree = "<group>"; };
02C4061C2373078400BD7ED8 /* EffectExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectExecutor.swift; sourceTree = "<group>"; };
02C40620237422EF00BD7ED8 /* EffectRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectRouter.swift; sourceTree = "<group>"; };
02C40622237425E100BD7ED8 /* EffectRouterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectRouterTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -754,6 +759,7 @@
5BB287E8209995420043B530 /* SimpleLogger.swift */,
DD748322212DB525008EEECD /* Copyable.swift */,
5B1F104C21105CAD0067193C /* EventSource+Extensions.swift */,
025BB528244DA65100E80BD2 /* ConnectableMap.swift */,
);
path = Source;
sourceTree = "<group>";
Expand Down Expand Up @@ -847,6 +853,7 @@
5B9CE80621199D4400DB79A7 /* ConnectableContramapTests.swift */,
DD748324212DEEC1008EEECD /* CopyableTests.swift */,
5B1F104F21105CC00067193C /* EventSource+ExtensionsTests.swift */,
025BB52A244DA68500E80BD2 /* ConnectableMapTests.swift */,
2DA1E89D2449F1ED00D240B7 /* WikiTutorialTest.swift */,
);
path = Test;
Expand Down Expand Up @@ -1252,6 +1259,7 @@
3EE5AF052110BF2E00CF8CA8 /* ConnectableClass.swift in Sources */,
2DF4C42420DBDF1B00A4B6DE /* SimpleLogger.swift in Sources */,
02BED1BB21DD20D20093FB47 /* ConnectableContramap.swift in Sources */,
025BB52D244DA6C400E80BD2 /* ConnectableMap.swift in Sources */,
5B1F104E21105CB10067193C /* EventSource+Extensions.swift in Sources */,
2D3A696D2355AED90053C95E /* Lock.swift in Sources */,
);
Expand Down Expand Up @@ -1357,6 +1365,7 @@
5B9CE80521197FE000DB79A7 /* ConnectableContramap.swift in Sources */,
5B1F104D21105CAD0067193C /* EventSource+Extensions.swift in Sources */,
DDA64A6720A0AD2D00150355 /* SimpleLogger.swift in Sources */,
025BB529244DA65100E80BD2 /* ConnectableMap.swift in Sources */,
5BCF5F0120F3620700721C0D /* ConnectableClass.swift in Sources */,
2D3A696E2355AED90053C95E /* Lock.swift in Sources */,
);
Expand Down Expand Up @@ -1419,6 +1428,7 @@
buildActionMask = 2147483647;
files = (
DD748325212DEEC1008EEECD /* CopyableTests.swift in Sources */,
025BB52C244DA6BF00E80BD2 /* ConnectableMapTests.swift in Sources */,
5B1F105121105CC50067193C /* EventSource+ExtensionsTests.swift in Sources */,
5BCF5F0420F3636800721C0D /* ConnectableClassTests.swift in Sources */,
2DA1E8A12449FBC500D240B7 /* WikiTutorialTest.swift in Sources */,
Expand Down
22 changes: 9 additions & 13 deletions MobiusExtras/Source/ConnectableContramap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,18 @@
import MobiusCore

public extension Connectable {
func contramap<NewInput>(_ map: @escaping (NewInput) -> Input) -> AnyConnectable<NewInput, Output> {
let newConnectClosure = { (consumer: @escaping Consumer<Output>) -> Connection<NewInput> in
let connection = self.connect(consumer)
let mappedAcceptFunction = { (newTypeInput: NewInput) in
let oldTypeInput = map(newTypeInput)
connection.accept(oldTypeInput)
}
/// Transform the input type of this `Connectable` by applying the `transform` function to each input.
///
/// - Parameter transform: The function which should be used to transform the input to this `Connectable`
/// - Returns: A `Connectable` which applies `transform` to each input value before handling it.
func contramap<NewInput>(_ transform: @escaping (NewInput) -> Input) -> AnyConnectable<NewInput, Output> {
return AnyConnectable { dispatch in
let connection = self.connect(dispatch)

return Connection<NewInput>(
acceptClosure: mappedAcceptFunction,
return Connection(
acceptClosure: { connection.accept(transform($0)) },
disposeClosure: connection.dispose
)
}

let contramapped = AnyConnectable(newConnectClosure)

return contramapped
}
}
35 changes: 35 additions & 0 deletions MobiusExtras/Source/ConnectableMap.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2020 Spotify AB.
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import MobiusCore

public extension Connectable {
/// Transform the output type of this `Connectable` by applying the `transform` function to each output.
///
/// - Parameter transform: The function which should be used to transform the output of this `Connectable`
/// - Returns: A `Connectable` which applies `transform` to each output value.
func map<NewOutput>(_ transform: @escaping (Output) -> NewOutput) -> AnyConnectable<Input, NewOutput> {
return AnyConnectable { dispatch in
return self.connect { output in
let newOutput = transform(output)
dispatch(newOutput)
}
}
}
}
68 changes: 68 additions & 0 deletions MobiusExtras/Test/ConnectableMapTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) 2020 Spotify AB.
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import MobiusCore
import MobiusExtras
import Nimble
import Quick

class ConnectableMapTests: QuickSpec {
override func spec() {
context("Connectable Map") {
it("applies the `transform` function to the output") {
var output: [Int?] = []
let connection = TestConnectable()
.map { Int($0) }
.connect {
output.append($0)
}

connection.accept("1")
connection.accept("2")
connection.accept("3")

expect(output).to(equal([1, 2, 3]))

connection.dispose()
}

it("preserves the connectable's `Disposable` conformance") {
let testConnectable = TestConnectable()
expect(testConnectable.isDisposed).to(beFalse())

testConnectable
.connect { _ in }
.dispose()

expect(testConnectable.isDisposed).to(beTrue())
}
}
}
}

private final class TestConnectable: Connectable {
var isDisposed = false

func connect(_ consumer: @escaping Consumer<String>) -> Connection<String> {
return Connection(
acceptClosure: consumer,
disposeClosure: { self.isDisposed = true }
)
}
}

0 comments on commit 6ef1e94

Please sign in to comment.