그라나밍

[28M03] Esoteric Obfuscated Ruby Programming / Yusuke Endoh (independent)

작성자
RubyKaigi
발행일
2025년 10월 05일

핵심 요약

  • 1 루비의 문자 사용 제약 및 배치 제약을 활용한 에소테릭 프로그래밍 기법과 다양한 콰인(Quine) 구현 사례를 소개합니다.
  • 2 괴델 수, method_missing, at_exit 등 루비의 다양한 기능을 활용하여 숫자로만, 밑줄로만, 알파벳으로만 프로그램을 작성하는 방법을 시연합니다.
  • 3 루비가 에소테릭 프로그래밍에 매우 강력하며, 1.8과 1.9 버전 간의 높은 호환성 및 JRuby의 성능 이슈를 언급합니다.

도입

본 발표는 루비 및 RSpec 커미터인 에토 씨가 '그라나밍'이라는 주제로 루비를 활용한 에소테릭 프로그래밍의 세계를 탐구합니다. 에토 씨는 온라인에서 다소 강한 인상으로 알려져 있지만, 실제로는 평화롭고 에소테릭 프로그래밍을 사랑하는 사람임을 밝히며 강연을 시작합니다. 본 강연의 핵심은 루비에 특이한 제약을 가했을 때 루비 역시 에소테릭 프로그래밍 언어(Esoprog)로서 얼마나 재미있게 활용될 수 있는지를 보여주는 데 있습니다.

에소테릭 프로그래밍 언어 (Esoprogs)

에소테릭 프로그래밍 언어는 의도적으로 읽고 쓰기 어렵게 설계된 프로그래밍 언어를 의미합니다. Brainf*ck과 같은 언어가 대표적이며, 대개 다음과 같은 기묘한 제약 사항을 특징으로 합니다.

  • 사용 가능한 문자의 편향

  • 사용 가능한 명령어의 편향

  • 명령어 순서나 문자 배치에 대한 제약

루비를 활용한 에소테릭 프로그래밍

본 발표에서는 루비에 이러한 제약을 적용하여 에소테릭 프로그래밍 언어로 즐길 수 있음을 보여줍니다. 발표는 크게 두 가지 제약 조건으로 나뉘어 진행됩니다.

1. 문자 사용 제약

사용할 수 있는 문자를 제한하여 루비 프로그램을 작성하는 방법을 시연합니다.

숫자만으로 프로그래밍

  • 기법: 프로그램 코드를 괴델 수(Gödel number)로 인코딩한 후, 이 거대한 숫자를 루비 인터프리터에 전달합니다. at_exit 훅을 활용하여 인터프리터 종료 시점에 ObjectSpace에서 BigNum 객체를 강제로 추출하고 디코딩하여 eval 합니다.

  • 특징: require 구문은 필요하지만, 실제 프로그램 로직은 숫자만으로 인코딩됩니다. 1.8 및 1.9 버전 모두에서 호환되며 JRuby에서도 특정 옵션과 함께 작동합니다.

  • Gem: 12345_라는 이름으로 공개되어 있습니다.

밑줄(_)만으로 프로그래밍

  • 기법: 프로그램을 괴델 수로 인코딩하고, 이를 6진수로 표현합니다. 각 6진수 자릿수는 밑줄의 길이로 표현됩니다. method_missing 기법을 사용하여 밑줄 호출을 가로채고 괴델 수를 복원하여 eval 합니다.

  • Gem: _라는 이름으로 공개되어 있습니다.

알파벳만으로 프로그래밍

  • 기법: 순수하게 알파벳만 사용하여 프로그램을 작성합니다. Shinichiro Hamama 씨의 아이디어를 기반으로 숫자까지 배제한 형태로 구현되었습니다. require 없이 순수 루비 코드만으로 구성됩니다.

문자 제약 관련 요약 및 미해결 문제

  • 루비는 문자 사용 제약에 매우 강하며, 1.8과 1.9 버전 간의 높은 호환성을 보여줍니다.

  • 미해결 문제: 소문자 알파벳만으로 프로그래밍하는 방법 (대문자는 상수 호출에 한정될 가능성).

  • 해결된 문제: 기호만으로 프로그래밍하는 방법 (Kurimura 씨의 RSCode).

2. 문자 배치 제약 및 콰인(Quine)

문자 배치에 제약을 두거나, 자기 자신을 출력하는 프로그램인 콰인을 구현하는 방법을 다룹니다.

콰인이란?

  • 자기 자신의 소스 코드를 출력하는 프로그램입니다. 루비로 작성된 간단한 콰인 예시가 제시됩니다.

야마노테선 콰인 (Yamanote Quine)

  • 특징: 일본 야마노테선 역 이름을 ASCII 아트로 출력하는 콰인으로, 실행할 때마다 다음 역 이름으로 코드가 변경되며 29개 역을 순환합니다.

  • 성능: MRI(Matz’s Ruby Interpreter)에서는 3.3초가 걸리지만, JRuby에서는 33초가 걸려 JRuby의 느린 시작 속도를 지적합니다.

ASCII 아트 프로그램 구현 기법

  • 기법: %w(...)와 같은 문자열 배열 리터럴을 사용하여 공백과 개행을 무시하고, joineval하여 코드를 실행합니다. 이를 통해 코드의 형태를 자유롭게 조작할 수 있습니다.

  • 압축: 프로그램 크기를 줄이기 위해 36진수, Base64, Zlib 등의 압축 기법이 활용되며, 데이터 규모에 따라 최적의 압축 방식이 달라집니다 (콜모고로프 복잡성과 연관).

다양한 콰인 구현 사례

  • 15 퍼즐 콰인: 퍼즐을 한 칸 움직일 때마다 다음 판면으로 코드가 변경됩니다.

  • 오셀로 대전 콰인: AI와 대전 가능한 콰인으로, 사용자의 수에 따라 코드가 변경됩니다.

  • 승리 시에만 콰인하는 오셀로: 플레이어가 승리해야만 자기 자신을 출력하는 콰인입니다.

  • 크리스마스 캐럴 연주 콰인: 실행하면 ‘Joy to the World’ 캐럴을 연주하고 콰인합니다 (파형 합성 포함).

  • 이미지 콰인: 이미지 파일(PNG, GIF) 그 자체가 루비 코드로 작성되어, 실행하면 자기 자신인 이미지를 출력합니다.

  • 콰인 릴레이: Ruby, Unlambda, Whitespace, Brainf*ck, Java, C, Haskell, OCaml, Lua, Perl, Python 등 11개 언어를 거쳐 마지막에 루비로 돌아오는 콰인 체인입니다.

문자 배치 제약 및 콰인 관련 요약

  • 루비는 문자 배치 제약과 콰인 구현에 매우 강력합니다.

  • 강점: 특이한 리터럴(%w(...)), BEGIN, eval 등 Perl에서 유래한 기능들, 강력한 문자열 처리 및 포매팅 기능, 다양한 진수 지원, pack/unpack 등의 유용한 기능 덕분입니다.

결론

결론적으로, 본 발표는 루비를 활용하여 에소테릭 프로그래밍의 즐거움을 만끽할 것을 권장합니다. 이를 통해 무의미해 보이는 작업 속에서 수리 논리나 프로그래밍 이론과 같은 심오한 배경 이론에 도달하거나, 제약을 극복하기 위한 '더티 핵(dirty hack)'을 즐길 수 있습니다. 또한, 제시된 대부분의 에소테릭 프로그램과 콰인이 Ruby 1.8과 1.9 버전 모두에서 작동하여 두 버전 간의 높은 호환성을 입증했습니다. 반면, JRuby는 느린 시작 속도로 인해 이러한 유형의 프로그래밍에는 부적합하다는 인상을 남겼습니다. 마지막으로, 과거에 존재했던 IORCC(International Obfuscated Ruby Code Contest)의 부활을 제안하며, 참가자가 있다면 기꺼이 참여하겠다는 의사를 밝히며 발표를 마무리합니다.

댓글 0

댓글 작성

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

아직 댓글이 없습니다

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