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

더 나은 Ruby 코드를 위한 숨겨진 보석 같은 메서드 7가지

적절한 Ruby 메서드를 활용하면 많은 작업을 절약할 수 있다는 사실을 알고 계셨나요?

익숙하게 사용할 수 있는 메서드가 많을수록 동작하는 코드를 더 빠르게 작성할 수 있으며, 성능과 품질 모두에서 더 나은 결과물을 얻을 수 있습니다.

그래서 오늘은 여러분이 아직 접해보지 못했을 만한 흥미로운 메서드 7가지를 소개해 드리려고 합니다.

1. Integer#digits 메서드 (Ruby 2.4)

Ruby 2.4에서 새롭게 도입된 이 메서드는 정수(Integer)의 개별 자릿수를 다룰 때 매우 유용합니다.

참고: Ruby 2.4의 변경 사항을 놓치셨다면, Fixnum과 Bignum이 더 이상 사용되지 않고(deprecated) 두 클래스가 Integer로 통합되었다는 점을 기억하세요.

배열처럼 인덱싱하면 자릿수를 얻을 수 있을 거라 생각할 수 있습니다:

2[0]

# 0

2[1]

# 1

하지만 이렇게 얻어지는 것은 자릿수가 아니라 해당 숫자를 구성하는 이진 비트(binary bits)입니다.

그래서 digits 메서드가 등장하기 전에는 숫자를 문자열로 변환한 후, chars 메서드로 문자 배열로 쪼개고, 마지막으로 각 문자열을 다시 정수로 변환하는 우회 방법을 사용했습니다.

예제:

123.to_s.chars.map(&:to_i).reverse

[3, 2, 1]

하지만 digits 메서드가 있는 지금은 이렇게 간단하게 처리할 수 있습니다:

123.digits

[3, 2, 1]

훨씬 깔끔해졌죠?

2. tap 메서드

때로는 객체를 생성하고, 그 객체에 몇 가지 메서드를 호출한 뒤, 동일한 객체를 반환하고 싶을 때가 있습니다.

보통은 이렇게 작성해야 합니다:

user = User.new

user.name = "John"

user

문제는 임시 변수를 따로 관리해야 한다는 점입니다.

바로 여기서 tap 메서드가 구원자로 등장합니다!

tap을 사용하면 앞선 예제가 이렇게 바뀝니다:

User.new.tap { |user| user.name = "John" }

임시 변수가 사라진 것에 주목하세요. 훨씬 더 깔끔한 코드가 되었습니다 🙂

3. Array#values_at

배열이나 해시에서 연속적이지 않은 여러 값을 가져와야 할 때, 보통은 이렇게 작성합니다:

arr = [1,2,3,4,5]

a, b, c = arr[0], arr[1], arr[4]

하지만 values_at 메서드를 사용하면 더 간결해집니다:

arr = [1,2,3,4,5]

a, b, c = arr.values_at(0, 1, 4)

해시에서도 동일하게 작동합니다:

hash = {bacon: 300, chocolate: 200}

p hash.values_at(:bacon, :chocolate)

# [300, 200]

4. Hash#transform_values (Ruby 2.4)

해시가 있고 어떤 이유로든 모든 값을 변경하고 싶다고 가정해 봅시다.

Array#map으로 하는 것과 비슷한 작업이죠.

그런데 map의 문제점은 해시가 아니라 배열의 배열(다차원 배열)을 반환한다는 것입니다. 게다가 Hash#map!도 존재하지 않습니다.

따라서 전통적인 해결책은 다음과 같습니다:

h = {bacon: 200, coconut: 300}

h.each { |k,v| h[k] = v*2 }

이 예제에서는 각 값에 2를 곱합니다.

실행 결과는 다음과 같습니다:

{:bacon=>400, :coconut=>600}

Ruby 2.4부터는 이 작업을 수행하는 더 좋은 방법이 생겼습니다:

h.transform_values! { |v| v * 2 }

이 메서드 역시 원래 Rails에서 제공되던 것 중 하나로, 이제는 프레임워크 없이도 사용할 수 있게 되었습니다 🙂

5. Kernel#itself (Ruby 2.2)

이 메서드가 처음에는 크게 흥미롭지 않아 보인다고 하시면 저도 동의합니다.

하지만 그 이유는 아직 좋은 활용 예제를 보지 못했기 때문입니다.

반복되는 단어들이 담긴 배열이 있고, 각 단어의 등장 횟수를 세고 싶다고 가정해 봅시다.

이를 처리하는 방법은 여러 가지가 있지만, 새로운 친구 Kernel#itself를 시험해 보기에 딱 좋은 사례라고 생각합니다.

예제:

words = %w(cat cat tiger dog cat)

words.group_by(&:itself).transform_values(&:size)

여기에 Hash#transform_values까지 조합해서 사용한 점에 주목하세요!

만약 transform_values를 사용할 수 없는 환경이라면 다음과 같이 대체할 수 있습니다:

words
  .group_by(&:itself)
  .each_with_object({}) { |(k,v), hash| hash[k] = v.size }

참고: itself 메서드는 공식 문서에서 Object 클래스 아래에 표시되지만, 실제로는 Kernel 모듈에 정의되어 있습니다.

6. Array#count

때로는 단순히 무언가를 세야 할 때가 있습니다.

흔히 쓰는 카운터 변수 + 루프 조합 대신 count 메서드를 사용해 보세요!

예제:

letters = %w(a a a b c d a)

letters.count("a")

# 4

배열 버전의 이 메서드는 블록도 인자로 받을 수 있어, 더 복잡한 조건의 카운팅도 가능합니다.

numbers = [1,2,3,4,5,6]

numbers.count(&:even?)

# 3

7. Enumerable#cycle

특정 패턴을 반복하고 싶으신가요? 아니면 간단한 on/off 토글이 필요하신가요?

그렇다면 Enumerable#cycle이 찾고 계신 바로 그 메서드일지도 모릅니다!

예제:

array = %w(a b c)

# array * 3과 동일한 결과
array.cycle(3).to_a

하지만 제가 가장 좋아하는 cycle 활용법은 "스위치" 또는 "토글" 객체를 만드는 것입니다.

switch = %w(on off).cycle

switch.next

이 방식의 장점은 스위치의 현재 값을 일일이 확인해서 수동으로 갱신할 필요가 없다는 점입니다.

그저 next를 호출하기만 하면 Ruby가 알아서 정확히 처리해 줍니다 🙂

마무리

이번 글에서 유용한 메서드들을 살펴봤습니다: Integer#digits, Kernel#tap, Array#values_at, Hash#transform_values, Kernel#itself, Array#count, Enumerable#cycle.

이미 알고 계셨다면 훌륭하고요! 그렇지 않았다면 실무에서 유용하게 활용하시길 바랍니다 🙂

이 글이 도움이 되셨나요? 그렇다면 친구들에게 공유해서 함께 즐겨보세요!