루비(Ruby) 인터프리터는 루비 코드를 읽어 들여 실행하는 프로그램입니다.
그런데 말이죠…
기본 루비 인터프리터인 MRI에는 흥미롭고 실용적인 명령줄 옵션이 무척 많다는 사실을 알고 계셨나요?
예를 들면:
ruby -v
이 옵션은 현재 사용 중인 루비 버전을 화면에 출력해 줍니다.
또한 -e 플래그를 사용하면 별도의 파일 없이, irb에 직접 진입하지 않고도 간단한 코드를 즉시 실행할 수 있습니다.
다음과 같이요:
ruby -e 'puts 123'
이러한 플래그들은 -h 옵션으로 확인할 수 있으며, 일부 "숨겨진" 플래그는 --help를 입력해야만 볼 수 있습니다.
아래 표는 그중에서도 특히 유용하다고 생각하는 플래그들을 정리한 것입니다.
꼭 알아야 할 핵심 플래그:
| 플래그 | 설명 |
|---|---|
| -v | 루비 버전 출력 |
| -c | 문법 검사 |
| -e | 코드 직접 실행 |
| -w | 경고 메시지 활성화 |
| -r | 파일 / 젬(gem) 불러오기 |
| -I | 로드 경로에 디렉터리 추가 |
| --enable frozen-string-literal | 모든 문자열 동결(freeze) |
| --dump parsetree | 파스 트리(parse tree) 출력 |
이제 몇 가지 플래그를 집중적으로 살펴보며 실제로 어떻게 작동하는지 알아보겠습니다!
문법 검사 (-c)
작성한 코드의 문법이 맞는지 빠르게 확인하고 싶다면 -c CLI 옵션을 사용하세요.
예제:
ruby -c code_without_syntax_errors.rb # Syntax OK ruby -c code_with_syntax_errors.rb # syntax error, unexpected tIDENTIFIER, expecting end-of-input
간단하지만 확실하게 동작하는 방법입니다 🙂
빠른 require (-r)
파일 상단에 일일이 require 구문을 작성하지 않고, 임시로 특정 젬(gem)을 불러와야 할 때가 있습니다.
디버깅용 젬을 사용할 때가 대표적이죠.
예제:
ruby -rpry code.rb
이렇게 하면 pry를 미리 로드한 상태로 스크립트를 실행할 수 있어 매우 편리합니다!
경고 플래그 (-w)
-w 플래그를 사용하면 린팅(linting)이 활성화되어 코드의 잠재적인 문제를 미리 알려 줍니다.
예를 들어 다음 코드:
p @test
ruby -w로 실행하면 아래와 같은 경고가 출력됩니다:
warning: instance variable @test not initialized
이건 꽤 유용한 경고입니다!
값을 할당하기도 전에 인스턴스 변수를 사용하려고 하거나, 변수 이름에 오타가 있는 경우 문제가 커지기 전에 미리 발견할 수 있기 때문입니다.
해결 방법은 간단합니다:
@test = nil
또 다른 예제를 살펴보겠습니다:
c = 1
이 경우에는:
warning: assigned but unused variable - c
이 경고를 해결하려면 해당 변수를 삭제하거나 실제로 사용하면 됩니다.
참고로 이 경고는 지역 변수(local variables)에만 적용됩니다.
블록 인자 중 사용하지 않는 것이 있다면 언더스코어(_)로 대체하는 것이 루비 커뮤니티의 "모범 사례"로 여겨진다는 점도 알아 두세요.
예제:
{ chocolate: 82 }.map { |k, _| k }
루비에서 널리 통용되는 관례입니다.
_ 자체에 특별한 기능이 있는 것은 아니며, 단지 유효한 변수 이름일 뿐이라는 점도 흥미로운 부분입니다.
경고 예제 더 살펴보기
다음 코드처럼 메서드의 반환값으로도 활용되지 않고, 어떤 변수에도 할당되지 않은 결과물이 있다면 어떻게 될까요?
2 * 2
루비는 이렇게 알려 줍니다:
warning: possibly useless use of * in void context
해결책은?
쓸모없는 구문을 삭제하거나, 결과를 변수에 할당하면 됩니다.
이번에는 이 메서드를 보겠습니다:
def orange(weight, quantity) # ... end
orange 메서드를 호출하는 방법은 여러 가지가 있습니다:
orange 100, 2 orange(100, 2) orange *[100, 2] orange(*[100, 2])
경고 옵션을 켠 상태에서 orange *[100, 2]처럼 호출하면 다음 경고가 나타납니다:
warning: '*' interpreted as argument prefix
왜 이런 일이 생길까요?
바로 모호함(ambiguity) 때문입니다.
루비는 orange *[100, 2](배열 전개)이 아니라 orange * [100, 2](곱셈 연산)를 의도했다고 해석하는 것입니다.
*와 [ 사이의 공백 여부가 중요한 이유가 바로 여기에 있습니다. 공백이 없으면 *가 배열과 결합된 스플랫(splat) 연산자로 해석되지만, 공백이 있으면 *를 곱셈 메서드 호출로 판단하게 됩니다.
즉, 이 경우에는 공백 하나가 의미를 바꾸는 셈입니다.
이 경고를 피하려면 위의 다른 호출 방식을 사용하면 됩니다.
이제, 여러분의 코드에도 -w 플래그를 붙여 실행해 보고 경고를 하나씩 제거하며 코드를 개선해 보세요 🙂
Read-Eval-Print-Loop (REPL)
irb와 pry는 익숙하실 텐데요, 둘 다 우리가 흔히 말하는 REPL(Read-Eval-Print-Loop) 도구입니다.
-n 플래그와 -e 플래그를 조합하면 아주 적은 코드로 비슷한 효과를 낼 수 있습니다.
예제:
echo 'bacon\nchocolate\norange' | ruby -ne 'puts $_.upcase' # BACON # CHOCOLATE # ORANGE
이 명령은 echo의 출력을 입력받아, 각 줄마다 지정한 코드(puts $_.upcase)를 실행합니다.
여기서 $_는 gets가 마지막으로 읽어 들인 입력값을 담고 있는 특수 변수입니다.
동결 문자열 리터럴(Frozen String Literals)
루비 2.3부터는 동결 문자열 리터럴 "매직 코멘트(magic comment)"가 도입되었습니다.
형태는 다음과 같습니다:
# frozen_string_literal: true
이 주석을 넣으면 모든 문자열이 동결(freeze)되어 변경 불가능(immutable)한 상태가 됩니다.
같은 효과를 내는 또 다른 방법은 루비 실행 시 --enable=frozen-string-literal 플래그를 전달하는 것입니다.
다음 코드:
str = "abcdef" str[0] = "b"
이 플래그가 켜진 상태에서 실행하면 아래와 같은 에러가 발생합니다:
can't modify frozen String (FrozenError)
그렇다면 문자열을 변경해야 하는 경우에는 어떻게 해야 할까요?
이렇게 하면 됩니다:
str = "abcdef".dup
혹은 이렇게:
str = +"abcdef"
두 방식 모두 동결되지 않은 문자열을 새로 만들어 자유롭게 수정할 수 있게 해 줍니다.
마치며
이번 글에서는 루비의 명령줄 옵션 중 버전 확인 플래그, 경고 플래그, 동결 문자열 리터럴 등을 살펴보았습니다. 이 플래그들은 실제 개발 과정에서 모두 유용하게 쓰이니 직접 사용해 보시길 권합니다!
더 많은 사람들이 도움을 받을 수 있도록 이 글을 공유하는 것도 잊지 마세요.
읽어 주셔서 감사합니다 🙂