Skip to content

Commit c489eac

Browse files
committed
add post
1 parent 2555b9d commit c489eac

7 files changed

Lines changed: 156 additions & 2 deletions

.ruby-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.2.2

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
source 'https://rubygems.org/'
22

33
gem 'github-pages', group: :jekyll_plugins
4+
gem 'webrick'
45

56
group :jekyll_plugins do
67
gem "jekyll-mermaid"

Gemfile.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ GEM
251251
tzinfo (2.0.6)
252252
concurrent-ruby (~> 1.0)
253253
unicode-display_width (1.8.0)
254+
webrick (1.9.2)
254255
zeitwerk (2.6.15)
255256

256257
PLATFORMS
@@ -259,6 +260,7 @@ PLATFORMS
259260
DEPENDENCIES
260261
github-pages
261262
jekyll-mermaid
263+
webrick
262264

263265
BUNDLED WITH
264266
2.2.31

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# minsone.github.io
22

3-
## License
3+
## 로컬 개발 환경 설정 (Mac)
4+
5+
이 프로젝트는 Jekyll을 사용하여 구축되었습니다. 로컬에서 서버를 띄워 포스팅을 미리 보려면 아래 단계를 따르세요.
6+
7+
### 1. 자동 설정 스크립트 실행
8+
프로젝트 루트에 포함된 `setup_jekyll.sh` 스크립트를 사용하면 `rbenv`, `Ruby`, `Bundler` 및 필요한 모든 라이브러리를 한 번에 설치하고 서버를 실행합니다.
9+
10+
```bash
11+
# 실행 권한 부여 (필요한 경우)
12+
chmod +x setup_jekyll.sh
13+
14+
# 환경 설정 및 서버 실행
15+
./setup_jekyll.sh
16+
```
417

18+
### 2. 수동 서버 실행
19+
설치가 이미 완료된 상태에서 서버만 다시 띄우고 싶을 때는 아래 명령어를 사용하세요.
20+
21+
```bash
22+
# 초안(Drafts) 포함 및 증분 빌드(--incremental)로 서버 실행
23+
bundle exec jekyll serve --drafts --incremental
24+
```
25+
26+
---
27+
28+
## License
529
MIT

_config.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
plugins:
22
- jekyll-mermaid
3-
gems: [jekyll-mermaid]
43

54
# This is the default format.
65
# For more see: http://jekyllrb.com/docs/permalinks/
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
layout: post
3+
title: "[Swift][Macro] 환경별 Swift 매크로 분기 처리: 환경에 따라 다른 매크로 호출"
4+
tags: [Swift, Macro, Conditional Compilation, Build Configuration]
5+
---
6+
{% include JB/setup %}
7+
8+
Swift 매크로를 사용하다보면 개발 환경에서 생성된 코드가 운영 환경에서는 불필요한 경우가 발생할 수 있습니다. 특정 Protocol을 구현한 Mock 객체를 생성하는 매크로를 사용한다고 가정해봅시다. [swift-spyable](https://github.com/Matejkob/swift-spyable), [Mockable](https://github.com/Kolos65/Mockable) 등의 매크로를 이용해서 Mock 객체를 쉽게 생성할 수 있습니다.
9+
10+
이들 매크로의 코드는 전처리기를 이용해서 `#if DEBUG ... #endif` 구문을 사용해서 개발 환경에서만 생성되도록 할 수 있습니다.
11+
12+
```swift
13+
@Mockable
14+
protocol MyService {
15+
func doSomething()
16+
}
17+
18+
#if DEBUG
19+
final class MyServiceMock: MyService {
20+
var doSomethingCallCount = 0
21+
func doSomething() {
22+
doSomethingCallCount += 1
23+
}
24+
}
25+
#endif
26+
```
27+
28+
하지만 이러한 방식은 생성된 매크로 코드를 다른 모듈에서 인식을 할 수 없는 단점이 있습니다.(예: Mock 객체를 다른 모듈에서 사용해야 하는 경우, 인식이 되지 않음. 단순 코드 작성하면 동작하나, 자동완성이 되지 않음.)
29+
30+
개발 환경에서는 생성된 코드를 통해 테스트를 진행하고, 운영 환경에서는 코드가 생성되지 않도록 하는 방법은 없을까요?
31+
32+
## 매크로 인터페이스 분기 처리
33+
34+
매크로 템플릿을 통해 생성하면 기본 매크로인 `stringify` 를 만들 수 있습니다.
35+
36+
```swift
37+
@freestanding(expression)
38+
public macro stringify<T>(_ value: T) -> (T, String) =
39+
#externalMacro(module: "MyMacroMacros", type: "StringifyMacro")
40+
```
41+
42+
외부에서는 매크로를 호출하지만, 실제로는 매크로 모듈의 매크로를 호출하는 방식입니다. 즉, 여기서는 매크로 모듈에 전처리기를 이용해서 분기 처리를 할 수 있습니다.
43+
44+
```swift
45+
#if DEBUG
46+
47+
@freestanding(expression)
48+
public macro stringify<T>(_ value: T) -> (T, String) =
49+
#externalMacro(module: "MyMacroMacros", type: "StringifyMacro")
50+
51+
#else
52+
53+
@freestanding(expression)
54+
public macro stringify<T>(_ value: T) -> (T, String) =
55+
#externalMacro(module: "MyMacroMacros", type: "DummyMacro")
56+
57+
#endif
58+
```
59+
60+
이와 같이 매크로 인터페이스를 분기 처리하면, 환경에 관계없이 동일하게 매크로를 호출할 수 있습니다.
61+
62+
### DummyMacro의 역할
63+
64+
여기서 `DummyMacro`는 운영 환경에서 매크로가 불필요한 작업을 수행하지 않도록 설계합니다. 예를 들어, `stringify` 매크로의 경우 `DummyMacro`는 단순히 입력받은 값을 그대로 반환하기만 하도록 구현할 수 있습니다.
65+
66+
```swift
67+
// MyMacroMacros/DummyMacro.swift
68+
public struct DummyMacro: ExpressionMacro {
69+
public static func expansion(
70+
of node: some FreestandingMacroExpansionSyntax,
71+
in context: some MacroExpansionContext
72+
) -> ExprSyntax {
73+
// 단순히 입력 인자를 그대로 반환하거나 결과값만 전달
74+
return "\(node.argumentList.first!.expression)"
75+
}
76+
}
77+
```
78+
79+
이렇게 하면 운영 환경의 바이너리에는 복잡한 Mock 생성 로직이나 디버깅용 코드가 포함되지 않으며, 매크로 확장으로 인한 빌드 시간 오버헤드도 최소화할 수 있습니다.
80+
81+
## 결론: 관심사의 분리와 깔끔한 코드
82+
83+
이 방식의 핵심 이점은 다음과 같습니다.
84+
85+
1. **관심사의 분리**: 매크로를 사용하는 쪽에서 `#if DEBUG`를 일일이 관리할 필요가 없습니다. 환경에 따른 동작 결정은 매크로 인터페이스 정의 단계에서 한 번만 처리됩니다.
86+
2. **깨끗한 코드**: 호출부 코드가 복잡해지지 않아 가독성이 높아지고 유지보수가 쉬워집니다.
87+
3. **DX(개발 경험) 향상**: 모듈 간 참조 시 발생하는 인식 문제나 자동완성 누락 문제를 매크로 수준에서 해결하여 더 쾌적한 개발 환경을 제공합니다.
88+

setup_jekyll.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/zsh
2+
3+
# 1. Homebrew 확인
4+
if ! command -v brew &> /dev/null; then
5+
echo "❌ Homebrew가 설치되어 있지 않습니다. https://brew.sh/ 에서 먼저 설치해주세요."
6+
exit 1
7+
fi
8+
9+
# 2. rbenv 및 ruby-build 설치
10+
echo "📂 rbenv 및 ruby-build 설치 중..."
11+
brew install rbenv ruby-build
12+
13+
# 3. .zshrc 설정 (이미 있으면 중복 추가 안 함)
14+
if ! grep -q 'rbenv init' ~/.zshrc; then
15+
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc
16+
echo 'eval "$(rbenv init -)"' >> ~/.zshrc
17+
echo "✅ ~/.zshrc에 rbenv 설정이 추가되었습니다. 새 터미널을 열거나 source ~/.zshrc를 실행하세요."
18+
fi
19+
20+
# 현재 쉘 세션에 rbenv 바로 적용
21+
export PATH="$HOME/.rbenv/bin:$PATH"
22+
eval "$(rbenv init -)"
23+
24+
# 4. 루비 설치 (3.2.2 버전 기준, 필요시 변경 가능)
25+
RUBY_VERSION="3.2.2"
26+
echo "💎 Ruby $RUBY_VERSION 설치 중... (시간이 다소 소요될 수 있습니다)"
27+
rbenv install $RUBY_VERSION --skip-existing
28+
rbenv local $RUBY_VERSION
29+
30+
# 5. Bundler 설치
31+
echo "📦 Bundler 2.2.31 설치 중..."
32+
gem install bundler -v 2.2.31
33+
34+
# 6. 프로젝트 의존성 설치
35+
echo "📥 프로젝트 라이브러리 설치 중..."
36+
bundle install
37+
38+
echo "🚀 모든 설정이 완료되었습니다! Jekyll 서버를 실행합니다."
39+
bundle exec jekyll serve --drafts

0 commit comments

Comments
 (0)