Ruby Gold는 문법 암기 시험이 아니라, Ruby의 고급 객체 모델과 실행 원리를 깊이 이해했는지를 묻는 시험입니다. 이 글은 Ruby Gold 빈출 주제를 중심으로 고난도 개념, 함정 포인트, 실전 해설을 한 번에 정리한 완성형 가이드입니다.
1) Ruby Gold 시험의 핵심 평가 포인트
- 객체 모델 심화: singleton class, method lookup, self 동작
- 메타프로그래밍: define_method, class_eval, method_missing
- 모듈/상속 고급: include/extend/prepend 우선순위
- 예외/리소스 관리: custom exception, ensure, retry 개념
- 동시성 기초: Thread, Mutex, Queue
- 표준 라이브러리 이해: Enumerator, Fiber 개념, GC 기본
2) Silver와 Gold의 차이
Silver가 "코드 결과를 맞히는 문법 중심"이라면, Gold는 "왜 그렇게 동작하는지"를 설명할 수 있어야 합니다.
- Silver: 변수, 조건문, Enumerable, 기본 OOP
- Gold: 객체 모델 내부 동작, 메서드 탐색 체인, 메타프로그래밍
3) 메서드 탐색 순서(Method Lookup Chain)
module A
def hello
"A"
end
end
module B
def hello
"B"
end
end
class Base
def hello
"Base"
end
end
class User < Base
include A
prepend B
end
u = User.new
puts u.hello
p User.ancestors
해설: prepend 모듈이 클래스보다 앞에 오므로 결과는 B입니다. 시험에서는 ancestors 순서를 직접 묻는 문제가 자주 나옵니다.
4) Singleton Class(고유 클래스) 이해
obj = "ruby"
def obj.shout
upcase + "!"
end
puts obj.shout
another = "ruby"
puts another.respond_to?(:shout)
해설: 메서드는 해당 객체의 singleton class에만 정의됩니다. 따라서 obj만 shout를 갖고, another는 갖지 않습니다.
5) class << self 와 클래스 메서드
class Config
class << self
attr_accessor :env
def production?
env == "production"
end
end
end
Config.env = "production"
puts Config.production?
시험 포인트: class << self 블록은 현재 객체(여기서는 클래스 객체)의 singleton class 컨텍스트입니다.
6) define_method vs def
class Report
[:daily, :weekly].each do |name|
define_method(name) do
"#{name} report"
end
end
end
r = Report.new
puts r.daily
puts r.weekly
해설: define_method는 클로저를 캡처합니다. 동적으로 메서드를 생성할 때 유용하며 Gold에서 자주 다루는 주제입니다.
7) method_missing과 respond_to_missing?
class DynamicFinder
def method_missing(name, *args)
if name.to_s.start_with?("find_by_")
field = name.to_s.sub("find_by_", "")
"search by #{field}: #{args.first}"
else
super
end
end
def respond_to_missing?(name, include_private = false)
name.to_s.start_with?("find_by_") || super
end
end
f = DynamicFinder.new
puts f.find_by_email("a@test.com")
puts f.respond_to?(:find_by_email)
시험 포인트: method_missing만 구현하면 반쪽짜리입니다. respond_to_missing?도 함께 구현해야 일관성이 맞습니다.
8) Refinements, reopen, monkey patch 주의점
Ruby는 클래스 재오픈이 가능해 강력하지만, 전역 monkey patch는 부작용이 큽니다. 시험에서는 개념 차이를 묻는 형태가 나옵니다.
9) Proc/lambda 심화: arity와 return
p1 = Proc.new { |x, y| [x, y] }
l1 = lambda { |x, y| [x, y] }
p p1.call(1) # [1, nil]
# p l1.call(1) # ArgumentError
def test_proc
p_obj = Proc.new { return "proc escaped" }
p_obj.call
"after"
end
def test_lambda
l_obj = -> { return "lambda only" }
l_obj.call
"after"
end
puts test_proc
puts test_lambda
해설: Proc은 인자 체크가 느슨하고 return이 바깥 메서드를 탈출합니다. lambda는 함수처럼 엄격하게 동작합니다.
10) Enumerator와 Lazy 평가
enum = (1..Float::INFINITY).lazy
result = enum.select { |n| n.odd? }
.map { |n| n * n }
.first(5)
p result
시험 포인트: lazy는 즉시 계산하지 않고 필요 시점에 평가합니다. 대용량/무한 시퀀스 문제에 연결됩니다.
11) Module.nesting, 상수 탐색, lexical scope
VALUE = "TOP"
module App
VALUE = "APP"
class Service
VALUE = "SERVICE"
def self.show
puts VALUE
puts ::VALUE
p Module.nesting
end
end
end
App::Service.show
해설: 상수는 lexical scope를 기준으로 탐색됩니다. ::VALUE는 최상위 상수를 참조합니다.
12) 예외 계층과 커스텀 예외
class PaymentError < StandardError; end
class CardDeclinedError < PaymentError; end
def charge!(amount)
raise CardDeclinedError, "card declined" if amount > 100
"ok"
end
begin
puts charge!(120)
rescue CardDeclinedError => e
puts "declined: #{e.message}"
rescue PaymentError => e
puts "payment error: #{e.message}"
ensure
puts "audit log written"
end
시험 포인트: 구체적인 예외를 상위 예외보다 먼저 rescue해야 합니다.
13) Thread와 Mutex 기초
counter = 0
mutex = Mutex.new
threads = 10.times.map do
Thread.new do
1000.times do
mutex.synchronize { counter += 1 }
end
end
end
threads.each(&:join)
puts counter
해설: Mutex 없이 공유 자원을 갱신하면 race condition이 발생할 수 있습니다.
14) freeze, dup, clone 차이
s = "ruby"
s.freeze
d = s.dup
c = s.clone
puts d.frozen? # false
puts c.frozen? # true
시험 포인트: clone은 frozen 상태 등 객체의 상태를 더 충실히 복제합니다.
15) GC 기본 개념
Gold에서는 GC 튜닝 깊이보다 개념 이해가 중요합니다. "객체 참조가 끊긴 대상은 가비지 컬렉션 대상"이라는 원리를 기반으로 메모리 누수 패턴을 판단하는 문제가 출제됩니다.
16) 블록 기반 리소스 관리 패턴
File.open("app.log", "w") do |f|
f.puts "start"
end
# 블록이 끝나면 자동 close
시험 포인트: Ruby는 블록 기반 API로 리소스 해제를 안전하게 처리합니다.
17) 빈출 함정 12선
prepend우선순위 오해- singleton class 개념 혼동
class << self컨텍스트 해석 오류define_method클로저 캡처 특성 누락method_missing만 구현하고respond_to_missing?누락- Proc/lambda arity 차이 실수
- Proc return 탈출 범위 오해
- 상수 탐색 lexical scope 오해
- 예외 rescue 순서 오류
- Thread 공유 데이터 동기화 누락
dupvsclone차이 혼동- Enumerable lazy 평가 시점 오해
18) 실전 문제 해설
문제 A: 메서드 탐색
module M1
def x; "M1"; end
end
module M2
def x; "M2"; end
end
class C
include M1
prepend M2
end
puts C.new.x
정답: M2. prepend가 클래스 앞에 삽입되기 때문입니다.
문제 B: 클래스 메서드 정의 위치
class A
def self.a1
"a1"
end
class << self
def a2
"a2"
end
end
end
puts A.a1
puts A.a2
정답: 둘 다 클래스 메서드이며 호출 가능합니다.
문제 C: lambda 인자 체크
l = ->(x, y) { x + y }
puts l.call(1, 2)
# puts l.call(1)
정답: 첫 줄은 3, 주석 해제 시 ArgumentError.
19) 6주 Ruby Gold 학습 로드맵
1주차: 객체 모델 복습(self, 클래스 객체, singleton class)
2주차: 모듈/상속/include-extend-prepend + ancestors
3주차: 메타프로그래밍(define_method, method_missing, eval 계열)
4주차: 예외 계층, 상수 탐색, Proc/lambda 심화
5주차: Thread/Mutex, Enumerator/lazy, 파일/리소스 패턴
6주차: 실전 문제 반복 + 오답 노트 압축 정리
20) 시험 직전 요약 카드
prepend > class > include > superclass- Proc: 느슨한 인자, 바깥 return 탈출 / lambda: 엄격 인자, 내부 return
method_missing구현 시respond_to_missing?함께- 상수는 lexical scope 우선,
::는 최상위 - Thread 공유 데이터는 Mutex로 보호
마무리
Ruby Gold 합격은 "Ruby를 Ruby답게 이해"하는 데서 시작합니다. 이 글의 핵심 코드를 직접 실행하고, 실행 결과를 근거와 함께 설명할 수 있게 훈련하면 고난도 문항에서도 흔들리지 않습니다.