Sourcery란 Swift용 코드 생성 툴입니다.
대부분의 개발자가 "보일러 플레이트"라고 부르는 매우 반복적인 자동 생성 코드에 적합합니다.
Ex)
- Equatable 구현
- Hashable 구현
- struct 생성자
- Lens 구현
역주 : Mock과 Stub도 만들 수 있습니다.
간단하게 기본적인 Mac command line 앱부터 시작하겠습니다.
이 앱에는 간단한 타입이 있습니다.
struct Person {
var firstName: String
var lastName: String
var birthDate: Date
var age: Int {
return Calendar.current.dateComponents([.year],
from: birthDate,
to: Date()).year ?? -1
}
}
이 타입에는 세 개의 일반 프로퍼티과 하나의 read-only 프로퍼티가 있습니다.
Swift에서 두 Person 인스턴스가 같은지 비교하려면 Equatable이라는 프로토콜을 구현해야 합니다.
그렇게 하는 것은 쉬운 일입니다. 적어도 이 경우에는 다음과 같습니다.
extension Person: Equatable {
static func ==(lhs: Person, rhs: Person) -> Bool {
guard lhs.firstName == rhs.firstName else { return false }
guard lhs.lastName == rhs.lastName else { return false }
guard lhs.birthDate == rhs.birthDate else { return false }
return true
}
}
그러나 10개의 타입에 이 작업을 수행한다고 상상해 보세요. 50개라면? 프로젝트에 몇 개의 구조체와 클래스가 있습니까?
이것들을 지속적으로 구현하는 것은 기계적인 작업이며 실제로 돈을 받는 것이 아닙니다. 이와 같은 반복 작업의 경우 자동화할 수 있는 방법이 있습니다.
Sourcery를 사용하면 템플릿을 기반으로 코드를 자동 생성할 수 있습니다. 이러한 템플릿은 여러 템플릿 언어로 작성할 수 있습니다.
저는 Stencil을 사용할 것입니다.
Sourcery와 Stencil 템플릿의 조합은 모든 타입에 대해 Equatable 구현을 자동으로 만들 수 있습니다.
템플릿은 다음과 같습니다.
{% for type in types.implementing.AutoEquatable %}
// MARK: {{ type.name }} Equatable
extension {{type.name}}: Equatable {
static func ==(lhs: {{type.name}}, rhs: {{type.name}}) -> Bool {
{% for variable in type.storedVariables %}guard lhs.{{variable.name}} == rhs.{{variable.name}} else { return false }
{% endfor %}
return true
}
}
{% endfor %}
중요한 라인을 살펴보겠습니다.
{% for type in types.implementing.AutoEquatable %}
여기에서는 AutoEquatable을 구현하는 프로젝트의 모든 타입을 열거하고 있습니다.
AutoEquatable은 단순히 마커 프로토콜입니다.
역주 : 마커 프로토콜이란?
클래스들의 공통 그룹명으로 프로토콜를 생성하고 아무것도 구현해놓지 않는 것.
즉, 그 클래스들이 같은 그룹으로 묶였다는 뜻입니다. 이는, 기능을 구현, 상속하겠다는 의미가아니라, 프로토콜에는 아무것도 구현하지않고, 단지 같은 클래스들끼리 그룹화하겠다는 의도입니다.
protocol AutoEquatable {}
이 전제 조건과 함께 Equatable 구현의 자동 생성을 선택하는 데 사용합니다.
자동으로 생성되도록 하려면 마커 프로토콜을 타입에 추가하기만 하면 됩니다.
extension Person: AutoEquatable {}
이러한 각 타입에 대해 해당 타입에 대한 extension과 필요한 함수를 생성합니다.
extension {{type.name}}: Equatable {
static func ==(lhs: {{type.name}}, rhs: {{type.name}}) -> Bool {
이 함수에서 해당 유형의 저장된 프로퍼티 각각에 대해 비교를 수행해야 합니다.
Person의 나이와 같은 프로퍼티은 저장되지 않으므로 비교할 필요가 없습니다. 하지만 Sourcery는 우리에게 이를 가능하게 합니다.
{% for variable in type.storedVariables %}guard lhs.{{variable.name}} == rhs.{{variable.name}} else { return false }
위의 내용은 기본적으로 "이 타입에 저장된 각 변수에 대해 비교를 수행하십시오"라고 말합니다.
템플릿의 나머지 부분은 뻔합니다.
그러나 간결함을 위해 이 템플릿은 많은 내용이 빠져 있습니다. Sourcery에서 제공하는 샘플 템플릿을 확인하는 것을 추천합니다.
코드 생성 수행하기
이제 Sourcery를 사용하여 생성을 수행해야 합니다.
샘플 앱에서 시작하여 Sourcery 바이너리를 다운로드하고 프로젝트에 포함할 수 있습니다. 이 경우 ./Resources/sourcery에 넣었습니다. 여기에서 볼 수 있습니다.
이제 파일에서 Sourcery를 실행할 수 있습니다. 프로젝트의 홈 폴더(SourceryDemo.xcodeproj가 있는 폴더)에 있다고 가정하고 다음과 같이 실행합니다.
$ ./Resources/sourcery/bin/sourcery
--sources ./SourceryDemo
--templates ./SourceryDemo/Templates/
--output ./SourceryDemo/Autogenerated
Sourcery의 마법의 결과는 여기에서 볼 수 있습니다.
// Generated using Sourcery 0.5.9 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
// MARK: Person Equatable
extension Person: Equatable {
static func ==(lhs: Person, rhs: Person) -> Bool {
guard lhs.firstName == rhs.firstName else { return false }
guard lhs.lastName == rhs.lastName else { return false }
guard lhs.birthDate == rhs.birthDate else { return false }
return true
}
}
Sourcery는 우리가 원하는 것을 정확히 생성했습니다. Person에 저장된 각 프로퍼티를 비교할 func ==()입니다!
자동 재생
템플릿을 변경하고 결과를 매우 빠르게 확인하려는 경우 어떻게 됩니까? 템플릿과 터미널 사이를 왔다 갔다 하는 것은 지루하고 답답합니다.
운 좋게도 Sourcery에는 이에 대한 해결책이 있습니다. 편리한 --watch 옵션을 command line에 추가하면 템플릿과 소스 파일의 변경 사항을 지속적으로 감시하면서 열린 상태로 유지됩니다.
한 단계 더 나아가 변경 사항이 실시간으로 발생하는 것을 볼 수 있습니다. Visual Studio Code는 여기에서 훌륭한 도우미입니다
보시다시피 템플릿을 저장하기 위해 ⌘-S를 누르는 순간 Swift 코드가 자동으로 재생성됩니다.
Visual Studio Code에는 기본적으로 Stencil 하이라이트 표시가 제공되지 않습니다. 설치하려면 ⌘-T를 누른 다음 ext install stencil 명령을 입력합니다.
사전 빌드 단계
Visual Studio Code와 함께 작성하여 템플릿을 정돈하면 여전히 손으로 새로운 것들을 생성하고 싶지 않을 것입니다.
새 타입을 추가하면 어떻게 될까요? Sourcery는 이를 자동으로 선택하지만 다시 실행하는 경우에만 가능합니다.
우리가 빌드할 때마다 Sourcery가 실행되도록 쉽게 만들 수 있습니다.
Xcode에서 사전 빌드 단계를 추가할 수 있습니다. Xcode에서 대상을 선택한 다음 Build Phases 탭을 선택합니다.
새 항목을 추가할 수 있습니다.
이제 빌드할 때마다 첫 번째 단계는 Sourcery output을 새로 고치는 것입니다.
앞으로
오늘 제가 한 것은 단순히 개념 증명에 불과했지만 월요일의 의도는 Sourcery를 실제 프로젝트에 통합하는 데 시간을 할애하는 것입니다.
제 설정을 보고 싶으시다면 Github에 샘플 프로젝트를 올려 놓았습니다. 커밋 기록을 보면 RxSwift 입문서에서 했던 것처럼 각 단계를 살펴볼 수 있습니다.
역자 : 안녕하세요 ◠‿◠ 고고입니다. 이 글은 작성자께 허락을 받고 번역하였습니다.
원문 : https://www.caseyliss.com/2017/3/31/the-magic-of-sourcery
'Swift' 카테고리의 다른 글
Nimble library not found for -lswiftXCTest (0) | 2021.11.07 |
---|
댓글