Computer >> 컴퓨터 >  >> 프로그래밍 >> Ruby

루비 case 문 완벽 가이드 - 고급 활용 기법

case 문만큼 단순하고 지루한 문법도 없을 것입니다. C 언어에서 물려받은 유산이고, 길게 늘어진 if 문들을 대체하는 용도로 쓰이니까요. 이제 더 이상 설명할 게 없어 보입니다. 하지만 정말 그럴까요?

사실 루비의 case 문은 여러분이 상상하는 것보다 훨씬 풍부하고 강력합니다. 간단한 예제 하나부터 살펴보겠습니다.

case "Hi there"
when String
  puts "case statements match class"
end

# 출력 결과: "case statements match class"

이 예제는 case 문이 값(value)뿐만 아니라 클래스(class)까지 매칭할 수 있음을 보여줍니다. 그 비결은 내부적으로 루비가 === 연산자, 즉 삼중 등호(triple equals) 연산자를 사용하기 때문입니다.

=== 연산자 빠르게 살펴보기

루비에서 x === y라고 작성하면 사실상 "y는 x가 나타내는 집합에 속하는가?"라는 질문을 던지는 것입니다. 아주 일반적인 질문이며, 구체적인 동작은 어떤 종류의 객체를 다루느냐에 따라 달라집니다.

# 여기서는 Class.===(item) 메서드가 호출되며,
# item이 해당 클래스의 인스턴스라면 true를 반환합니다

String === "hello" # true
String === 1 # false

문자열(String), 정규표현식(Regexp), 범위(Range)는 모두 자체적인 ===(item) 메서드를 정의하고 있으며, 대체로 예상대로 동작합니다. 심지어 여러분이 직접 만든 클래스에도 삼중 등호 메서드를 추가할 수 있습니다.

이제 이 원리를 알았으니, case 문으로 다양한 트릭을 구사할 수 있습니다.

case 문에서 범위(Range) 매칭하기

range === n이 단순히 range.include?(n)의 결과를 반환하기 때문에, case 문에서 범위를 그대로 사용할 수 있습니다. 어떻게 확신할 수 있냐고요? 공식 문서에 명시되어 있습니다.

case 5
when (1..10)
  puts "case statements match inclusion in a range"
end

# 출력 결과: "case statements match inclusion in a range"

case 문으로 정규표현식 매칭하기

정규표현식 역시 case 문에서 활용할 수 있습니다. /regexp/ === "string"은 문자열이 해당 정규표현식과 일치할 때만 true를 반환하기 때문인데, 이 역시 Regexp 공식 문서에 설명되어 있습니다.

case "FOOBAR"
when /BAR$/
  puts "they can match regular expressions!"
end

# 출력 결과: "they can match regular expressions!"

Proc과 Lambda 매칭하기

조금 생소하게 느껴질 수 있는 부분입니다. Proc#===(item)Proc#call(item)과 동일하게 동작합니다. 즉, 람다(lambda)와 프록(proc)을 case 문에서 동적 매처(matcher)로 활용할 수 있다는 의미입니다.

case 40
when -> (n) { n.to_s == "40" }
  puts "lambdas!"
end

# 출력 결과: "lambdas"

나만의 매처(Matcher) 클래스 작성하기

앞서 언급했듯이, 클래스에 커스텀 case 동작을 추가하는 것은 === 메서드를 직접 정의하는 것만큼 간단합니다. 이를 잘 활용하면 복잡한 조건 로직을 여러 개의 작은 클래스로 분리해 코드의 가독성과 유지보수성을 크게 높일 수 있습니다. 아래 예제에서 그 활용 방향을 대략적으로 보여드리겠습니다.

class Success
  def self.===(item)
    item.status >= 200 && item.status < 300
  end
end

class Empty
  def self.===(item)
    item.response_size == 0
  end
end

case http_response
when Empty
  puts "response was empty"
when Success
  puts "response was a success"
end

이처럼 === 연산자의 동작 원리만 제대로 이해하면, 단순해 보이던 case 문을 훨씬 더 표현력 있고 우아하게 활용할 수 있습니다. 조건 분기 로직이 복잡해진다면 오늘 소개한 기법들을 적극적으로 적용해 보시기 바랍니다.