루비에서 AST 변환을 활용한 엘릭서 파이프라인 연산자 구현 실험

Elixir-like pipes in Ruby (oh no not again)

작성자
HackerNews
발행일
2024년 11월 16일

핵심 요약

  • 1 Ruby에서 Elixir와 유사한 파이프라인 연산자를 AST 변환 기법을 활용하여 구현하는 실험적 접근 방식을 소개합니다.
  • 2 기존 Ruby의 메서드 체이닝 및 `.then` 사용으로 파이프라인 연산자가 불필요하다는 회의론에도 불구하고, 새로운 관점의 제안과 Python 라이브러리에서 영감을 받아 구현되었습니다.
  • 3 `pipe` 키워드로 메서드를 장식하고 `>>` 연산자를 사용하여 이전 단계의 결과를 `_`로 참조하거나 첫 번째 인자로 자동 전달하는 방식으로 동작합니다.

도입

엘릭서(Elixir)의 파이프라인 연산자는 데이터 처리 흐름을 명확하게 보여주어 많은 언어에서 유사한 기능 도입을 시도하고 있습니다. 루비(Ruby) 역시 예외는 아니지만, 루비의 객체 지향 API 구조와 기존 메서드 체이닝 방식, 그리고 `.then` (이전 `yield_self`) 등의 기능으로 인해 파이프라인 연산자의 필요성에 대한 회의적인 시각이 존재해왔습니다. 본 글은 이러한 배경 속에서 루비에 파이프라인 연산자를 구현하려는 저자의 새로운 실험적 접근 방식을 다룹니다.

엘릭서의 파이프라인 연산자는 value |> func1() |> func2()와 같이 데이터를 순차적으로 처리하는 방식을 제공합니다. 루비에서는 ("go " * 3).upcase.sub(/ $/, '!')와 같이 메서드 체이닝이나 URI.open(_1)과 같은 블록을 활용한 .then 메서드를 통해 유사한 흐름을 구현할 수 있습니다. 과거 루비 2.7에서 |> 연산자 도입 시도가 있었으나, 기존 기능과 차이가 없어 혼란만 가중되어 철회된 바 있습니다. 또한, 루비에는 메서드 참조(first-class method references)가 없어 URI.method(:open)처럼 객체를 생성해야 하는 점도 파이프라인 연산자 도입의 걸림돌로 작용했습니다.

그럼에도 불구하고 저자는 파이프라인 연산자 도입에 대한 새로운 논의와 파이썬의 pipe_operator 라이브러리, 특히 @elixir_pipe 데코레이터가 AST(추상 구문 트리) 변환을 통해 동작하는 방식에 영감을 받아 루비에서 유사한 실험을 진행했습니다.

구현 방식

구현된 방식은 다음과 같습니다:

  • pipe 키워드를 사용하여 메서드를 데코레이터처럼 표시합니다.

  • 해당 메서드 내부에서는 >> 연산자가 파이프 연산자처럼 작동합니다.

  • 각 단계에서는 이전 단계의 결과를 _ 변수로 참조할 수 있습니다.

  • _ 참조를 생략하고 메서드만 지정하면, 이전 단계의 결과가 해당 메서드의 첫 번째 인자로 자동 전달됩니다.

예시: ruby pipe def repos(username) username >> "https://api.github.com/users/#{_}/repos" >> URI.open >> _.read >> JSON.parse(symbolize_names: true) >> _.map { _1.dig(:full_name) }.first(10) >> pp end

동작 원리

이 구현의 핵심은 런타임에 코드를 실행하는 것이 아니라, pipe 데코레이터가 적용될 때 메서드의 소스 코드를 로드하고, parser gem을 사용하여 AST로 파싱한 뒤, 원하는 파이프라인 동작을 수행하도록 AST를 변환합니다. 이후 unparser를 사용하여 새로운 AST를 루비 코드로 변환하고, 이를 대상 클래스에서 eval하여 메서드를 재정의하는 방식입니다. 즉, 로드 타임에 문법 매크로처럼 동작하여 실제 실행되는 코드는 _ = username; _ = "url/#{_}"; _ = URI.open(_); ...와 같은 형태로 변경됩니다. 이 방식은 코어 객체에 대한 몽키 패치 없이 빠르고 효율적으로 작동합니다.

결론

이 실험은 루비에 새로운 연산자를 도입하려는 제안이라기보다는, 런타임 오버헤드나 코어 클래스 침범 없이 매크로와 유사한 기능을 제공하는 접근 방식을 탐구하는 데 중점을 둡니다. 이러한 AST 변환 기법은 새로운 언어 기능의 '실험실'로서 활용되거나, Rake, Sinatra, Arel과 같은 특정 도메인 특화 언어(DSL)의 경량 구현에 유용할 수 있습니다. 또한, `Prism` 파서의 발전과 루비에서의 데코레이터 활용 가능성, 구조적 패턴 매칭이 AST 변환에 얼마나 편리한지 등 여러 시사점을 제공합니다. 궁극적으로 이 실험은 루비의 표현력을 확장하고 코드 변환 기법에 대한 깊이 있는 이해를 제공하는 흥미로운 시도로 평가됩니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!