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를 사용하여 깔끔한 도움말 메시지를 쉽게 생성할 수 있습니다. 유효하지 않은 옵션이 주어질 경우 오류를 발생시켜 적절한 예외 처리가 가능합니다.