Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enum plus plus #199

Merged
merged 5 commits into from
Jul 2, 2019
Merged

Enum plus plus #199

merged 5 commits into from
Jul 2, 2019

Conversation

pietrocaselani
Copy link
Owner

This PR adds Sourcery/Stencil templates to give Swift enum more powers!
Now we have the protocol EnumClosures, that when implemented in an enum will create closures for each enum case.

Using the following enum as example:

enum ViewState<T> {
    case start(data: T)
    case loading
    case completed(count: Int, message: String)
}

you can implement EnumClosures, by doing extension ViewState: EnumClosures, and Sourcery will generate the following code:

extension ViewState {
    internal func onStart(_ fn: (T) -> Void) {
        guard case let .start(data) = self else { return }
        fn(data)
    }
    internal func onLoading(_ fn: () -> Void) {
        guard case .loading = self else { return }
        fn()
    }
    internal func onCompleted(_ fn: (Int, String) -> Void) {
        guard case let .completed(count, message) = self else { return }
        fn(count, message)
    }
}

There is also the EnumProperties that will generate accessors for each case. So using the same enum, ViewState, you can extend ViewState to use EnumProperties by doing extension ViewState: EnumProperties which will generate the following code:

extension ViewState {
    internal var isStart: Bool {
        guard case .start = self else { return false }
        return true
    }
    internal var isLoading: Bool {
        guard case .loading = self else { return false }
        return true
    }
    internal var isCompleted: Bool {
        guard case .completed = self else { return false }
        return true
    }

    internal var start: T? {
        guard case let .start(data) = self else { return nil }
        return (data)
    }
    internal var completed: (count: Int, message: String)? {
        guard case let .completed(count, message) = self else { return nil }
        return (count, message)
    }
}

And by doing that, we are now able to write such code:

func render(viewState: ViewState<User>) {
    viewState.onLoading {
        // show loading indicator
    }

    viewState.onStart { user in
        // show the user
    }

    viewState.onCompleted { (count, message) in
        // show the cout and message
    }

    // Or

    view.loading = viewState.isLoading
    view.user = viewState.start
    view.countAndMessage = viewState.completed
}

@codecov-io
Copy link

codecov-io commented Jul 2, 2019

Codecov Report

Merging #199 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #199   +/-   ##
=======================================
  Coverage   34.54%   34.54%           
=======================================
  Files         292      292           
  Lines        7292     7292           
=======================================
  Hits         2519     2519           
  Misses       4773     4773
Impacted Files Coverage Δ
...ackerCore/MovieDetails/MovieDetailsViewState.swift 40% <ø> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5ed3c6b...df7a046. Read the comment docs.

@pietrocaselani pietrocaselani merged commit 698466f into master Jul 2, 2019
@pietrocaselani pietrocaselani deleted the enum_plus_plus branch July 2, 2019 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants