Skip to content

Instantly share code, notes, and snippets.

@ronanrodrigo
Last active May 16, 2019 16:46
Show Gist options
  • Save ronanrodrigo/1d4d96cd6b35b2ee094e8d2d46f02f8b to your computer and use it in GitHub Desktop.
Save ronanrodrigo/1d4d96cd6b35b2ee094e8d2d46f02f8b to your computer and use it in GitHub Desktop.
EnumPoetry
// Sources/ViewState.swift
// Given an enum with some cases
protocol EnumPoetry {}
enum ViewState<T>: EnumPoetry {
case start(T)
case loading
case completed(Int, String)
}
// Templates/EnumPoetry.stencil
// When run this stencil template code with:
// sourcery --sources Sources/ --templates Templates/ --output Sources/
{% macro associatedValueTypes associatedValues %}{% for associatedValue in associatedValues %}{% if forloop.first %}{{ associatedValue.typeName }}{% else %}, {{ associatedValue.typeName }}{% endif %}{% endfor %}{% endmacro %}
{% macro associatedValueNames associatedValues %}{% for associatedValue in case.associatedValues %}{% if forloop.first %}value{{forloop.counter}}{% else %}, value{{forloop.counter}}{% endif %}{% endfor %}{% endmacro %}
{% for enum in types.enums where enum.implements.EnumPoetry %}
{{ enum.accessLevel }} extension {{ enum.name }} {
{% for case in enum.cases %}
{% if case.hasAssociatedValue %}
func on{{ case.name|capitalize }}(_ fn: ({% call associatedValueTypes case.associatedValues %}) -> Void) {
guard case let .{{ case.name }}({% call associatedValueNames case.associatedValues %}) = self else { return }
fn({% call associatedValueNames case.associatedValues %})
}
{% else %}
func on{{ case.name|capitalize }}(_ fn: () -> Void) {
guard case .{{ case.name }} = self else { return }
fn()
}
{% endif %}
{% endfor %}
}
{% endfor %}
// Sources/EnumPoetry.generated.swift
// Then you will get this
internal extension ViewState {
func onStart(_ fn: (T) -> Void) {
guard case let .start(value1) = self else { return }
fn(value1)
}
func onLoading(_ fn: () -> Void) {
guard case .loading = self else { return }
fn()
}
func onCompleted(_ fn: (Int, String) -> Void) {
guard case let .completed(value1, value2) = self else { return }
fn(value1, value2)
}
}
// Sources/UsingState.swift
// And you can use this way:
func handle(state: ViewState<Int>) {
state.onStart { number in
print("start: \(number)")
}
state.onLoading { print("loading: ∞") }
state.onCompleted { (number, text) in
print("completed: \(number) \(text)")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment