새로운 기능과 성능 개선을 담은 Ruby의 새 버전이 곧 출시됩니다.
이번 변화들을 미리 파악해 두면 좋겠죠?
지금부터 하나씩 살펴보겠습니다!
무한 범위(Endless Range)
Ruby 2.5 이하 버전에서도 Float::INFINITY를 활용하면 일종의 무한 범위를 표현할 수 있었지만, Ruby 2.6에서는 이를 한 단계 발전시킨 새로운 문법이 도입되었습니다.
새로운 무한 범위는 다음과 같이 작성합니다:
(1..)
(1..10)처럼 끝값을 갖는 일반적인 범위와 달리, 이 표현식에는 종료 값이 없다는 점이 특징입니다.
활용 예시:
["a", "b", "c"].zip(1..) # [["a", 1], ["b", 2], ["c", 3]] [1,2,3,4,5][1..] # [2, 3, 4, 5] (1..).step(5).take(100) # [1, 6, 11, 16, 21, 26, 31, 36, 41, 46]
여러분이라면 어떤 상황에서 활용할 수 있을까요?
ArithmeticSequence
Ruby 2.6에서는 새로운 종류의 Enumerable 객체가 도입되었습니다.
바로 Enumerator::ArithmeticSequence입니다.
현재 ArithmeticSequence를 반환하는 메서드는 두 가지입니다:
- Range#step
- Numeric#step
그렇다면 이 객체의 특별한 점은 무엇일까요?
ArithmeticSequence는 요소의 개수와 첫 번째 요소, 마지막 요소를 스스로 알고 있습니다.
예시:
(1..10).step(2).first # 1 (1..10).step(2).last # 9
이러한 first, last 메서드는 Ruby 2.6 이전에는 사용할 수 없었습니다. 그래서 ArithmeticSequence가 새롭게 등장한 것입니다!
또 다른 차이점도 있습니다:
(1..10).step(2) == (1..10).step(2) # false - Ruby 2.5 (및 이전 버전) (1..10).step(2) == (1..10).step(2) # true - Ruby 2.6
Ruby 2.6에서는 산술 시퀀스끼리 서로 비교할 수 있게 되었습니다.
여러 인수로 해시 병합하기
여러 개의 해시를 하나로 합치고 싶을 때가 있습니다.
기존에는 이렇게 작성해야 했습니다:
a = { a: 1 }
b = { b: 2 }
c = { c: 3 }
a.merge(b).merge(c)
# {:a=>1, :b=>2, :c=>3}
Ruby 2.6에서는 새로운 방식이 추가되었습니다:
a.merge(b, c)
# {:a=>1, :b=>2, :c=>3}
결과는 동일하지만, 메서드 호출을 딱 한 번만 하면 됩니다!
새로운 exception 옵션
Integer 같은 형변환 메서드를 사용할 때, 값을 변환할 수 없으면 예외가 발생합니다.
예시:
Integer("a")
# ArgumentError (invalid value for Integer(): "a")
Ruby 2.6에서는 다음 메서드에 새로운 exception 키워드 인수가 추가되었습니다:
- Integer()
- Float()
- Rational()
- Complex()
이 키워드를 통해 해당 메서드들의 동작 방식을 직접 제어할 수 있습니다.
예시:
Integer("a", exception: false)
# nil
Random.bytes
랜덤 바이트가 필요하다면? Ruby 2.6에서는 Random 클래스에 새로운 bytes 메서드가 추가되었습니다.
사용 예시는 다음과 같습니다:
Random.bytes(10) # "\xCD\r\xE6Wz\xBA)\x02\xC4\xDB"
사실 이 기능 자체는 완전히 새로운 것은 아닙니다. 예전부터 securerandom 모듈을 통해 동일한 기능을 사용할 수 있었습니다.
require 'securerandom' SecureRandom.bytes(10)
그렇다면 굳이 새로운 메서드가 필요한 이유는 무엇일까요?
Random.bytes는 보안성을 일부 희생하는 대신 속도를 얻는 방식으로, SecureRandom보다 약 8배 빠릅니다.
Range#%
Ruby 2.6에서는 Range에 새로운 % 메서드가 추가되었습니다.
예시:
((0..) % 2).take(5) # [0, 2, 4, 6, 8]
이 메서드는 Range#step과 동일하게 동작합니다.
TracePoint#parameters
TracePoint 클래스는 메서드 호출, 클래스 정의, 스레드 같은 이벤트를 추적하는 데 유용한 도구입니다.
Ruby 2.6에는 여기에 새로운 parameters 메서드가 추가되었습니다.
이 메서드를 사용하면 호출되는 메서드의 매개변수 목록을 출력할 수 있습니다.
예시:
TracePoint.trace(:call, :b_call, :c_call) do |tp| p [tp.event, tp.parameters] end def orange(a,b,c*) end orange(1,2,3)
실행 결과:
[:call, [[:req, :a], [:req, :b], [:rest, :c]]]
Transient Heap
Transient Heap은 수명이 짧은 객체를 위한 성능 개선 기능으로, 메모리 단편화 문제와 느린 malloc 호출을 줄이는 것이 목표입니다.
Malloc은 Ruby 인터프리터(그리고 대부분의 C 프로그램)가 운영체제로부터 메모리를 할당받는 방식입니다.
NEWS 항목에 따르면 약 6~7%의 속도 향상을 기대할 수 있다고 합니다.
실제로 몇 가지 벤치마크를 돌려본 결과는 다음과 같습니다:
이 기능은 요소가 10개 미만인 작은 해시를 대량으로 생성할 때 가장 효과적입니다.

반면 위 결과를 보면, 큰 해시의 경우 Ruby 2.6(프리뷰 3)에서 오히려 느려진 것으로 나타났습니다.
Transient Heap의 혜택을 받을 수 있는 다른 객체들도 있습니다:
- 배열(Array)
- Struct
- 일반 객체(직접 만든 클래스의 인스턴스)
Array#union & Array#difference
Ruby 2.6의 Array 클래스에는 union과 difference라는 두 가지 새로운 메서드가 추가되었습니다.
예시:
[1,2,3,4,5].difference([3]) # [1, 2, 4, 5] [1,2,3,4,5].union([5,6,7]) # [1, 2, 3, 4, 5, 6, 7]
이 메서드들은 여러 개의 인수를 받을 수 있다는 점도 기억해 두세요.
마무리
Ruby 2.6은 더 적은 시간에 더 좋은 코드를 작성하는 데 도움이 되는 실용적인 새 기능들을 담고 있습니다. 또 다른 성능 관련 신기능인 MJIT(Method Based Just-in-Time Compiler)에 대해서는 별도의 글에서 자세히 다룰 예정입니다.
Ruby 2.6은 2018년 12월 25일 출시될 예정입니다.
최신 변화를 꾸준히 따라가고, Ruby 실력을 한 단계 끌어올려 멋진 루비 개발자가 되고 싶으시다면 지금 바로 뉴스레터에 가입해 보세요.
읽어주셔서 감사합니다!