Ruby의 OptionParser를 활용한 서브 커맨드 CLI 개발

Building a Sub-command Ruby CLI with just OptionParser

작성자
Ruby Weekly
발행일
2025년 10월 07일

핵심 요약

  • 1 Ruby 표준 라이브러리의 OptionParser는 서브 커맨드(git-like) CLI 구축에 가장 효과적인 도구입니다.
  • 2 글로벌 옵션과 서브 커맨드별 옵션을 각각 처리하기 위해 두 개의 OptionParser를 사용하는 전략이 핵심입니다.
  • 3 외부 Gem 대신 OptionParser를 사용함으로써 안정성, 유지보수성, 그리고 UNIX-like CLI의 일관성을 확보할 수 있습니다.

도입

수년간 Rake, Thor, GLI 등 다양한 도구로 CLI를 구축해 온 저자는 Ruby의 표준 라이브러리인 OptionParser가 스크립팅 및 서브 커맨드(git-like) CLI 개발에 가장 적합한 선택이라고 주장합니다. 이 글은 OptionParser가 겉보기와 달리 복잡한 CLI 구조, 특히 서브 커맨드와 관련된 옵션들을 어떻게 효과적으로 처리할 수 있는지, 그 잘 알려지지 않은 기능을 활용하여 보여주고자 합니다.

Ruby의 OptionParser를 사용하여 서브 커맨드 CLI를 구축하는 핵심은 두 개의 OptionParser 인스턴스를 활용하는 것입니다.

서브 커맨드 CLI의 구성 요소bin/test --verbose audit --type Component specs/front_end와 같은 서브 커맨드 CLI는 다음 다섯 가지 주요 부분으로 구성됩니다:* 앱 이름: bin/test* 글로벌 옵션: --verbose (전역적으로 적용되는 옵션)

  • 서브 커맨드: audit (실행될 특정 작업)
  • 커맨드 옵션: --type Component (서브 커맨드에만 해당하는 옵션)
  • 인자: specs/front_end (커맨드에 전달되는 추가 데이터)

두 개의 OptionParser를 통한 작업 분할이러한 구조를 처리하기 위해 다음과 같은 두 단계의 파싱 전략을 사용합니다:1. 첫 번째 OptionParser (글로벌 옵션 파싱):* 전역적으로 적용되는 옵션들을 처리합니다.

  • parse! 대신 order! 메서드를 사용합니다. order!는 자신이 이해하지 못하는 첫 번째 인자(예: audit과 같은 서브 커맨드 이름)까지만 파싱하고, 그 이후의 인자들은 ARGV 배열에 그대로 남겨둡니다.
  • 예시 코드:rubyrequire "optparse"global_parser = OptionParser.new do |opts| opts.banner = "bin/test [global options] command [command options] [command args...]" opts.on("--verbose", "Show additional logging/debug information")endglobal_options = {}global_parser.order!(into: global_options) # ARGV에 서브 커맨드와 그 이후 인자들이 남음2. 두 번째 OptionParser (서브 커맨드 옵션 파싱):* 첫 번째 OptionParser가 처리한 후 ARGV[0]에 남아있는 서브 커맨드 이름을 기반으로 해당 서브 커맨드에 특화된 OptionParser를 찾습니다.
  • 이 OptionParser는 parse! 메서드를 사용하여 남은 명령줄 전체를 파싱하고, 서브 커맨드에 해당하는 옵션들을 추출합니다.
  • 예시 코드:rubycommands = {}commands["audit"] = OptionParser.new do |opts| opts.on("--type TYPE", "Set the type of test to audit. Omit to audit all types")endcommand = ARGV[0] # 이제 'audit'이 됨command_parser = commands[command]command_options = {}command_parser.parse!(into: command_options) # 서브 커맨드 옵션 파싱### 커맨드 실행 로직 관리 및 추가 기능OptionParser는 옵션 파싱에 특화되어 있어 커맨드의 실제 실행 로직을 직접 제공하지는 않습니다. 하지만 Ruby의 강력한 객체 지향 기능을 활용하여 각 서브 커맨드를 별도의 클래스로 구현하고, execute 메서드를 통해 해당 로직을 캡슐화할 수 있습니다. 또한, OptionParser는 accept 메서드를 통해 정교한 타입 강제(type coercion) 기능을 제공하며, puts global_parser 또는 puts command_parser를 사용하여 깔끔한 도움말 메시지를 쉽게 생성할 수 있습니다. 유효하지 않은 옵션이 주어질 경우 오류를 발생시켜 적절한 예외 처리가 가능합니다.

결론

OptionParser를 활용한 CLI 개발은 다소 장황하게 느껴지거나 커맨드 실행 로직 및 오류 처리에 수동적인 작업이 필요할 수 있습니다. 그러나 Ruby 표준 라이브러리에 의존함으로써 얻는 안정성, 지속적인 유지보수, 그리고 불필요한 의존성 회피라는 장점은 매우 큽니다. GLI, Thor, Rake와 같은 외부 Gem들은 복잡한 DSL을 도입하거나 불필요한 기능을 포함하여 학습 곡선을 높이고 UNIX 명령줄 관행과 어긋나는 경우가 있습니다. 따라서 일반적인 Ruby CLI 개발에서는 표준 라이브러리의 OptionParser를 채택하는 것이 장기적인 신뢰성과 유지보수 측면에서 가장 현명한 접근 방식입니다.

댓글 0

댓글 작성

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

아직 댓글이 없습니다

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