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: 2 additions & 2 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let package = Package(
.library(name: "LoggerMiddleware", targets: ["LoggerMiddleware"])
],
dependencies: [
.package(url: "https://github.com/SwiftRex/SwiftRex.git", .upToNextMajor(from: "0.8.6"))
.package(url: "https://github.com/SwiftRex/SwiftRex.git", .upToNextMajor(from: "0.8.8"))
],
targets: [
.target(
Expand Down
52 changes: 20 additions & 32 deletions Sources/LoggerMiddleware/LoggerMiddleware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,31 @@ import Foundation
import os.log
import SwiftRex

extension Middleware where StateType: Equatable {
extension MiddlewareProtocol where StateType: Equatable {
public func logger(
actionTransform: LoggerMiddleware<Self>.ActionTransform = .default(),
actionPrinter: LoggerMiddleware<Self>.ActionLogger = .osLog,
actionTransform: LoggerMiddleware<InputActionType, StateType>.ActionTransform = .default(),
actionPrinter: LoggerMiddleware<InputActionType, StateType>.ActionLogger = .osLog,
actionFilter: @escaping (InputActionType) -> Bool = { _ in true },
stateDiffTransform: LoggerMiddleware<Self>.StateDiffTransform = .diff(),
stateDiffPrinter: LoggerMiddleware<Self>.StateLogger = .osLog,
stateDiffTransform: LoggerMiddleware<InputActionType, StateType>.StateDiffTransform = .diff(),
stateDiffPrinter: LoggerMiddleware<InputActionType, StateType>.StateLogger = .osLog,
queue: DispatchQueue = .main
) -> LoggerMiddleware<Self> {
) -> ComposedMiddleware<InputActionType, OutputActionType, StateType> {
LoggerMiddleware(
self,
actionTransform: actionTransform,
actionPrinter: actionPrinter,
actionFilter: actionFilter,
stateDiffTransform: stateDiffTransform,
stateDiffPrinter: stateDiffPrinter,
queue: queue
)
).lift(outputAction: { (_: Never) -> OutputActionType in }) <> self
}
}

public final class LoggerMiddleware<M: Middleware>: Middleware where M.StateType: Equatable {
public typealias InputActionType = M.InputActionType
public typealias OutputActionType = M.OutputActionType
public typealias StateType = M.StateType
private let middleware: M
public final class LoggerMiddleware<Action, State: Equatable>: MiddlewareProtocol {
public typealias InputActionType = Action
public typealias OutputActionType = Never
public typealias StateType = State

private let queue: DispatchQueue
private var getState: GetState<StateType>?
private let actionTransform: ActionTransform
Expand All @@ -37,15 +36,13 @@ public final class LoggerMiddleware<M: Middleware>: Middleware where M.StateType
private let stateDiffPrinter: StateLogger

init(
_ middleware: M,
actionTransform: ActionTransform,
actionPrinter: ActionLogger,
actionFilter: @escaping (InputActionType) -> Bool = { _ in true },
stateDiffTransform: StateDiffTransform,
stateDiffPrinter: StateLogger,
queue: DispatchQueue
) {
self.middleware = middleware
self.actionTransform = actionTransform
self.actionPrinter = actionPrinter
self.actionFilter = actionFilter
Expand All @@ -54,19 +51,11 @@ public final class LoggerMiddleware<M: Middleware>: Middleware where M.StateType
self.queue = queue
}

public func receiveContext(getState: @escaping GetState<StateType>, output: AnyActionHandler<OutputActionType>) {
self.getState = getState
middleware.receiveContext(getState: getState, output: output)
}

public func handle(action: InputActionType, from dispatcher: ActionSource, afterReducer: inout AfterReducer) {
guard actionFilter(action) else { return }
public func handle(action: Action, from dispatcher: ActionSource, state: @escaping GetState<State>) -> IO<Never> {
guard actionFilter(action) else { return .pure() }
let stateBefore = getState?()
var innerAfterReducer = AfterReducer.doNothing()

middleware.handle(action: action, from: dispatcher, afterReducer: &innerAfterReducer)

afterReducer = innerAfterReducer <> .do { [weak self] in
return IO { [weak self] _ in
guard let self = self,
let stateAfter = self.getState?() else { return }

Expand All @@ -83,15 +72,14 @@ public final class LoggerMiddleware<M: Middleware>: Middleware where M.StateType

extension LoggerMiddleware {
public static func `default`(
actionTransform: LoggerMiddleware<IdentityMiddleware<InputActionType, OutputActionType, StateType>>.ActionTransform = .default(),
actionPrinter: LoggerMiddleware<IdentityMiddleware<InputActionType, OutputActionType, StateType>>.ActionLogger = .osLog,
actionTransform: LoggerMiddleware<InputActionType, StateType>.ActionTransform = .default(),
actionPrinter: LoggerMiddleware<InputActionType, StateType>.ActionLogger = .osLog,
actionFilter: @escaping (InputActionType) -> Bool = { _ in true },
stateDiffTransform: LoggerMiddleware<IdentityMiddleware<InputActionType, OutputActionType, StateType>>.StateDiffTransform = .diff(),
stateDiffPrinter: LoggerMiddleware<IdentityMiddleware<InputActionType, OutputActionType, StateType>>.StateLogger = .osLog,
stateDiffTransform: LoggerMiddleware<InputActionType, StateType>.StateDiffTransform = .diff(),
stateDiffPrinter: LoggerMiddleware<InputActionType, StateType>.StateLogger = .osLog,
queue: DispatchQueue = .main
) -> LoggerMiddleware<IdentityMiddleware<InputActionType, OutputActionType, StateType>> {
) -> LoggerMiddleware<InputActionType, StateType> {
.init(
IdentityMiddleware(),
actionTransform: actionTransform,
actionPrinter: actionPrinter,
actionFilter: actionFilter,
Expand Down
95 changes: 47 additions & 48 deletions Tests/LoggerMiddlewareTests/LoggerMiddlewareTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,42 +17,41 @@ struct Substate: Equatable {
public let z: Bool
}

struct TestMiddleware: Middleware {
func receiveContext(getState: @escaping GetState<TestState>, output: AnyActionHandler<Int>) {
struct TestMiddleware: MiddlewareProtocol {

func handle(action: Int, from dispatcher: ActionSource, state: @escaping GetState<TestState>) -> IO<Int> {
.pure()
}

func handle(action: Int, from dispatcher: ActionSource, afterReducer: inout AfterReducer) {
}


typealias InputActionType = Int
typealias OutputActionType = Int
typealias StateType = TestState
}

final class LoggerMiddlewareTests: XCTestCase {

func testStateDiff() {
// given
let beforeState: LoggerMiddleware<TestMiddleware>.StateType = TestState(a: Substate(x: ["SetB", "SetA"],
y1: ["one": 1, "eleven": 11],
y2: ["one": 1, "eleven": 11, "zapp": 42],
z: true),
b: [0, 1],
c: "Foo",
d: "✨",
e: nil)
let afterState: LoggerMiddleware<TestMiddleware>.StateType = TestState(a: Substate(x: ["SetB", "SetC"],
y1: ["one": 1, "twelve": 12],
y2: ["one": 1, "twelve": 12, "zapp": nil],
z: false),
b: [0],
c: "Bar",
d: nil,
e: "🥚")

let beforeState = TestState(a: Substate(x: ["SetB", "SetA"],
y1: ["one": 1, "eleven": 11],
y2: ["one": 1, "eleven": 11, "zapp": 42],
z: true),
b: [0, 1],
c: "Foo",
d: "✨",
e: nil)
let afterState = TestState(a: Substate(x: ["SetB", "SetC"],
y1: ["one": 1, "twelve": 12],
y2: ["one": 1, "twelve": 12, "zapp": nil],
z: false),
b: [0],
c: "Bar",
d: nil,
e: "🥚")
// when
let result: String? = LoggerMiddleware<TestMiddleware>.recursiveDiff(prefixLines: "🏛", stateName: "TestState", before: beforeState, after: afterState)

let result: String? = LoggerMiddleware<Int, TestState>.recursiveDiff(prefixLines: "🏛", stateName: "TestState", before: beforeState, after: afterState)
// then
let expected = """
🏛 TestState.a.x: 📦 <SetA, SetB> → <SetB, SetC>
Expand All @@ -66,37 +65,37 @@ final class LoggerMiddlewareTests: XCTestCase {
"""
XCTAssertEqual(result, expected)
}


func testStateDiffWithFilters() {
// given
let beforeState: LoggerMiddleware<TestMiddleware>.StateType = TestState(a: Substate(x: ["SetB", "SetA"],
y1: ["one": 1, "eleven": 11],
y2: ["one": 1, "eleven": 11, "zapp": 42],
z: true),
b: [0, 1],
c: "Foo",
d: "✨",
e: nil)
let afterState: LoggerMiddleware<TestMiddleware>.StateType = TestState(a: Substate(x: ["SetB", "SetC"],
y1: ["one": 1, "twelve": 12],
y2: ["one": 1, "twelve": 12, "zapp": nil],
z: false),
b: [0],
c: "Bar",
d: nil,
e: "🥚")

let beforeState = TestState(a: Substate(x: ["SetB", "SetA"],
y1: ["one": 1, "eleven": 11],
y2: ["one": 1, "eleven": 11, "zapp": 42],
z: true),
b: [0, 1],
c: "Foo",
d: "✨",
e: nil)
let afterState = TestState(a: Substate(x: ["SetB", "SetC"],
y1: ["one": 1, "twelve": 12],
y2: ["one": 1, "twelve": 12, "zapp": nil],
z: false),
b: [0],
c: "Bar",
d: nil,
e: "🥚")
// when
let result: String? = LoggerMiddleware<TestMiddleware>.recursiveDiff(prefixLines: "🏛",
let result: String? = LoggerMiddleware<Int, TestState>.recursiveDiff(prefixLines: "🏛",
stateName: "TestState",
filters: [
" TestState.a.y2",
" TestState.b.#"
],
before: beforeState,
after: afterState)

// then
let expected = """
🏛 TestState.a.x: 📦 <SetA, SetB> → <SetB, SetC>
Expand All @@ -108,7 +107,7 @@ final class LoggerMiddlewareTests: XCTestCase {
"""
XCTAssertEqual(result, expected)
}

static var allTests = [
("testStateDiff", testStateDiff),
]
Expand Down