diff --git a/.sourcery.yml b/.sourcery.yml new file mode 100644 index 00000000..e04a82c9 --- /dev/null +++ b/.sourcery.yml @@ -0,0 +1,5 @@ +sources: + - CouchTrackerCore +templates: + - SourceryTemplates +output: CouchTrackerCore/CodeGenerated diff --git a/Brewfile b/Brewfile index e478fe3d..b0d175b4 100644 --- a/Brewfile +++ b/Brewfile @@ -1,5 +1,6 @@ tap 'blender/homebrew-tap' -brew 'rome' + +brew 'sourcery' brew 'swiftlint' brew 'sonar-scanner' brew 'tailor' diff --git a/CouchTrackerCore/CodeGeneration/EnumClosures.swift b/CouchTrackerCore/CodeGeneration/EnumClosures.swift new file mode 100644 index 00000000..776858b1 --- /dev/null +++ b/CouchTrackerCore/CodeGeneration/EnumClosures.swift @@ -0,0 +1,31 @@ +/* + Given the following enum + + ``` + enum ViewState: EnumClosures { + case start(data: T) + case loading + case completed(count: Int, message: String) +} + ``` + + 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) + } +} + ``` + */ +public protocol EnumClosures {} diff --git a/CouchTrackerCore/CodeGeneration/EnumPoetry.swift b/CouchTrackerCore/CodeGeneration/EnumPoetry.swift new file mode 100644 index 00000000..1015b794 --- /dev/null +++ b/CouchTrackerCore/CodeGeneration/EnumPoetry.swift @@ -0,0 +1,2 @@ +// See `EnumClosures` and `EnumProperties` +public protocol EnumPoetry: EnumClosures, EnumProperties {} diff --git a/CouchTrackerCore/CodeGeneration/EnumProperties.swift b/CouchTrackerCore/CodeGeneration/EnumProperties.swift new file mode 100644 index 00000000..fa435f25 --- /dev/null +++ b/CouchTrackerCore/CodeGeneration/EnumProperties.swift @@ -0,0 +1,40 @@ +/* + Given the following enum + + ``` + enum ViewState: EnumProperties { + case start(T) + case loading + case completed(Int, String) + } + ``` + + 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) + } +} + ``` + */ +public protocol EnumProperties {} diff --git a/CouchTrackerCore/MovieDetails/MovieDetailsViewState.swift b/CouchTrackerCore/MovieDetails/MovieDetailsViewState.swift index 6a60926a..af5caa78 100644 --- a/CouchTrackerCore/MovieDetails/MovieDetailsViewState.swift +++ b/CouchTrackerCore/MovieDetails/MovieDetailsViewState.swift @@ -1,4 +1,4 @@ -public enum MovieDetailsViewState: Hashable { +public enum MovieDetailsViewState: Hashable, EnumPoetry { case loading case showing(movie: MovieEntity) case error(error: Error) diff --git a/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift b/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift index c450490a..c02baedc 100644 --- a/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift +++ b/CouchTrackerCore/Movies/Manager/MoviesManagerViewState.swift @@ -1,4 +1,4 @@ -public enum MoviesManagerViewState: Hashable { +public enum MoviesManagerViewState: Hashable, EnumPoetry { case loading case showing(pages: [ModulePage], selectedIndex: Int) } diff --git a/SourceryTemplates/EnumClosures.stencil b/SourceryTemplates/EnumClosures.stencil new file mode 100644 index 00000000..2a39141b --- /dev/null +++ b/SourceryTemplates/EnumClosures.stencil @@ -0,0 +1,22 @@ +{% macro associatedValueNamedType associatedValue %}{% if associatedValue.localName %}{{ associatedValue.localName }}{% else %}value{{ forloop.counter }}{% endif %}{% endmacro %} +{% 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 %}{% call associatedValueNamedType associatedValue %}{% else %}, {% call associatedValueNamedType associatedValue %}{% endif %}{% endfor %}{% endmacro %} +// MARK: - EnumClosures + +{% for enum in types.enums where enum.implements.EnumClosures %} +extension {{ enum.name }} { + {% for case in enum.cases %} + {% if case.hasAssociatedValue %} + {{ enum.accessLevel }} 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 %} + {{ enum.accessLevel }} func on{{ case.name|capitalize }}(_ fn: () -> Void) { + guard case .{{ case.name }} = self else { return } + fn() + } + {% endif %} + {% endfor %} +} +{% endfor %} diff --git a/SourceryTemplates/EnumProperties.stencil b/SourceryTemplates/EnumProperties.stencil new file mode 100644 index 00000000..05a97bfa --- /dev/null +++ b/SourceryTemplates/EnumProperties.stencil @@ -0,0 +1,24 @@ +{% macro associatedValueNamedType associatedValue %}{% if associatedValue.localName %}{{ associatedValue.localName }}{% else %}value{{ forloop.counter }}{% endif %}{% endmacro %} +{% 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 %}{% call associatedValueNamedType associatedValue %}{% else %}, {% call associatedValueNamedType associatedValue %}{% endif %}{% endfor %}{% endmacro %} +{% macro associatedTypeAsTuple associatedValues %}{% if associatedValues.count == 1 %}{{ associatedValues[0].typeName }}{% else %}({% for associatedValue in associatedValues %}{% if forloop.first %}{% call associatedValueNamedType associatedValue %}: {{ associatedValue.typeName }}{% else %}, {% call associatedValueNamedType associatedValue %}: {{ associatedValue.typeName }}{% endif %}{% endfor %}){% endif %}{% endmacro %} +// MARK: - EnumProperties + +{% for enum in types.enums where enum.implements.EnumProperties %} +extension {{ enum.name }} { + {% for case in enum.cases %} + {{ enum.accessLevel }} var is{{ case.name|capitalize }}: Bool { + guard case .{{ case.name }} = self else { return false } + return true + } + {% endfor %} + {% for case in enum.cases %} + {% if case.hasAssociatedValue %} + {{ enum.accessLevel }} var {{ case.name }}: {% call associatedTypeAsTuple case.associatedValues %}? { + guard case let .{{ case.name }}({% call associatedValueNames case.associatedValues %}) = self else { return nil } + return ({% call associatedValueNames case.associatedValues %}) + } + {% endif %} + {% endfor %} +} +{% endfor %} diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 3e1f3c7c..146b1dda 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -10,7 +10,6 @@ platform :ios do sh("../scripts/generate_secrets #{secrets_param}", log: false) sh('cd .. && tuist generate') - pods end @@ -19,6 +18,12 @@ platform :ios do cocoapods(podfile: '.', repo_update: false) end + desc 'Setup Certificates' + lane :setup_certs do + match(type: 'development') + match(type: 'appstore') + end + desc 'Run CouchTrackerCore tests' lane :tests do run_tests_for_scheme(scheme: 'TVDBSwiftTests') diff --git a/fastlane/README.md b/fastlane/README.md index c8ff12ce..3405ba76 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -21,6 +21,11 @@ or alternatively using `brew cask install fastlane` fastlane ios pods ``` Run bundle exec pod install --repo-update +### ios setup_certs +``` +fastlane ios setup_certs +``` +Setup Certificates ### ios tests ``` fastlane ios tests diff --git a/scripts/codegeneration b/scripts/codegeneration new file mode 100755 index 00000000..7c9788c0 --- /dev/null +++ b/scripts/codegeneration @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +sourcery